3D 与游戏开发的 MCP 服务器:决定成败的是工具设计
只暴露 run_python 的 MCP 服务器把一切都交给了智能体,却什么忙都没帮上。什么样的 3D 工具面,智能体才真正用得上。
任何一个为 3D 应用写的 MCP 服务器,最终都会走到同一个岔口。你可以只暴露一个工具——run_python(code)——用一个下午把整个应用的 API 交给智能体;也可以想清楚一片场景到底需要哪二十个操作,只把它们暴露出来,这要花上几周。两条路在协议层面的工作量完全一样,智能体之后能做到什么却完全不同。
两百字讲清 MCP
Model Context Protocol 是一种通信格式,不是什么技巧。宿主(你面前那个 AI 应用,可能是智能体 CLI,也可能是 IDE)为每条连接启动一个客户端,每个客户端对接一个服务器——一个用 JSON-RPC 应答的普通程序,要么通过本机的 stdin 和 stdout,要么走 HTTP。
服务器提供三样东西。工具是模型可以调用的函数,每个都有名称、描述和描述参数的 JSON Schema,活都是它们干的。资源是宿主可以拉取的只读数据:一个文件、一份 schema、一张清单。提示模板是用户从菜单里挑选的预置模板。在 3D 服务器里,几乎全部分量都压在工具上;资源偶尔出现,提示模板几乎从不使用。
Anthropic 于 2024 年 11 月发布 MCP,一年后将其捐赠给 Linux Foundation 旗下的 Agentic AI Foundation,指导委员会里坐着 OpenAI、Google、Microsoft 和 AWS。对工具作者来说,协议就这么多——这也正是协议不是难题的原因。
工具面就是产品本身
run_python 的代价
单个代码执行工具看起来是「最大化」的:应用能做的一切一次性全部开放。实际上它没给智能体任何它原本没有的东西。要用它,模型必须凭记忆复现应用的 API——模块路径、参数顺序、哪个轴朝上的约定、单位——而这份记忆冻结在训练时刻,你磁盘上的版本却不是。于是循环变成:写脚本、读 traceback、改一个名字、读下一个 traceback。沿街摆一排房子可能烧掉二十个来回,其中十五个是在收拾自己的残局。而且这个工具没有边界:添加一个立方体的脚本,用完全相同的权限就能删掉整个场景。
同一件事,抬高一层
现在换成按任务形状设计的工具:
get_scene_summary()
create_road_network(layout, length_m, lanes, sidewalks)
place_buildings_along(road_id, count, storeys, facade)
set_sun(azimuth_deg, elevation_deg)
十二栋房子的那条街,变成三次调用加一次回读。智能体不再需要 API,因为工具清单就是规划本身。回合数大约下降一个数量级——而比速度更有用的是,每一次失败现在都失败在你读得懂的地方。
这和生成场景而不是生成物件是同一个论证:构图和几何是两类问题,工具必须是关于构图的。
多粗算太粗
抬得太高是另一种失败。一个 build_city(prompt) 就是老虎机:只有一根拉杆,对不满意的地方毫无办法。合适的高度大致是这样——一个工具应当对应关卡设计师会说出口的一句话。「把这个街区填成两层住宅。」如果这个工具没法用一句话说出来,那它的高度就选错了。
- 十五到四十个工具,不是四百个。每一条定义在用户开口之前就已经躺在上下文窗口里,而过长的目录会可测量地劣化工具选择。
- 每个工具八个参数以内。再多,模型就开始靠猜来填字段。
- 集合封闭的地方一律用枚举而非自由文本。
facade: brick | render | glass没法被编造出来,字符串可以。 - 单位写进参数名。
length_m一次性终结一整类 bug。
回读是被跳过的那一半
只会写的智能体是在盲干。它在视口里没有眼睛,没有本体感觉,四次调用之后它对场景的认知就是自己讲给自己听的故事。智能体 3D 里所有好的部分都来自闭合这个回路,而回路是靠一个读取工具闭上的。
好的场景摘要是摘要,不是转储——把每个物件的每个变换都吐出来,既庞大又无用。智能体真正需要的是:
- 按类别的数量,以及以米为单位的整体包围盒;
- 之后可能要修改的一切都有稳定的 id;
- 关系——哪些建筑属于哪条路,哪个房间里放着哪些道具;
- 以及最重要的问题清单:断头的道路、两个互相穿插的网格、背对街道的建筑。
最后这一条正是读取工具与诊断工具的分界,而诊断的价值高得多:你告诉它哪里坏了,它就会去修,靠它自己发现则很少发生。另外,把视口截图也当成读取工具:回答「这看起来像不像一条街」时它胜过任何坐标表,回答「这面墙是不是偏了 4 厘米」时它毫无用处。两个都要有。
幂等性,或者说被建了三遍的那条路
智能体会重试,客户端也会重试。编辑器正忙时一次调用超时,客户端重发,于是两套一模一样的路网为同一个 z 值打架。
解法是让写操作可寻址。创建东西的工具返回一个稳定 id,带着这个 id 再调一次就是更新而不是追加。place_building(building_id, ...) 调两次是一栋楼;place_building(...) 调两次是两栋。
MCP 为此准备了词汇。工具注解——readOnlyHint、destructiveHint、idempotentHint、openWorldHint——在 2025-03-26 版本中引入,宿主正是靠它们决定什么自动放行、什么要停下来问一句。它们是提示而非强制,而未加注解的工具会被当成最坏情况:破坏性、非幂等、会伸向公网。把读取类工具标成只读,是十分钟的工作,却能把每一轮循环里的确认弹窗都拿掉。
报错也是提示词
3D MCP 服务器的报错信息只有一个读者,而且不是人。是一个正在决定下一步做什么的模型,没有调试器,也看不到源码。按这个读者来写,报错就成了你手上最便宜的教学面。
| 工具返回了什么 | 智能体下一步会做什么 |
|---|---|
| 「参数无效」 | 原样重试一次,然后开始猜。 |
| 40 行的 Python traceback | 花掉 500 个 token,学到一个行号。 |
| 「lane_width_m 必须在 2.5 到 6.0 之间,收到 45」 | 换一个合法宽度重新调用。 |
| 「没有 r_07 这条路。现有:r_01、r_02、r_03。」 | 不用再回读就把 id 改对。 |
由此:说清楚错在哪里,同时说清楚什么才是对的;点名那个能消除困惑的工具;诚实汇报部分成功。如果 40 棵树落地了 34 棵、6 棵掉到多边形外面,就说清是哪 6 棵——把部分结果报成「成功」,正是智能体在坏地基上盖三层楼的方式。
影响半径
编辑源码的智能体可以用 git 回滚。编辑 3D 场景的智能体,动的是别人手工打磨了几个小时、而且常常完全没有版本控制的文档。这里的失败模式不是一次糟糕的提交,而是一个被抹掉的下午。
撤销、边界,以及够不着的工具
- 一次调用,一步撤销。如果种四十棵树在撤销栈里留下四十条记录,撤销就只是个装饰。
- 边界写在服务器里,不是写在提示词里。「只在这个多边形内建造」写进提示词是一个建议;同一条规则做成工具内的边界检查才是保证。标记出来的禁建区属于后者。
- 限制破坏性动词的作用域。
delete_selection没问题;delete_all要么不该存在,要么必须放在明确确认之后——MCP 的 elicitation 允许服务器在调用过程中直接询问用户。
没人预算过的注入面
工具的输出是不可信输入。一个搜索社区资源库的服务器会返回陌生人写的标题和标签,而这些文字会和你的指令一起落进智能体的上下文。工具投毒——把隐藏指令藏在工具返回值里——是有据可查的攻击类别,而资源元数据是理想的载体。让「下一个调用哪个工具」的决策远离从网络来的文本。
Cuberta 选的是这笔交易里较窄的那一版。它是一个免费的桌面编辑器,自带 MCP 服务器:按下 Copy connect command,把命令粘进终端,你的智能体就接上了。它建出来的一切都是可以选中、移动、删除和撤销的实体对象,并且只发生在你标记为可建造的区域内。
今天已有的东西,按类别看
与 3D 相关的 MCP 生态可以归为四种形态。
- DCC 桥接。Blender、Maya、Houdini、Cinema 4D 或贴图软件内部的插件守着一个 socket,外面一个小进程把 MCP 调用转发进去。最有名的是 Blender MCP。它们几乎都带一个执行代码的工具,也就是
run_python问题的原生栖息地;其中的取舍值得单开一篇。 - 资源库与生成服务器。Sketchfab、Poly Haven、Meshy、Tripo、Hyper3D Rodin。搜索、预览、下载、导入——它们最容易写。它们以读为主,而且彻底属于「开放世界」,所以注解和防注入的卫生要求在这里比任何地方都高。
- 引擎桥接。Unity、Unreal、Godot 和 Roblox Studio 都有。大多数是社区项目——广泛使用的那个 Unity 方案与 Unity Technologies 无关——但 Unreal Engine 5.8 随附了 Epic 官方的实验性 MCP 插件,带有面向 actor、场景和材质实例的工具集。这里反复出现的隐患是异步:一个改完脚本、却在编辑器完成重新编译之前就返回的工具,报出的是一个靠不住的成功。
- 为智能体而生的编辑器。从一开始就围绕智能体设计的应用,MCP 面是主要界面,而不是套在更早的 API 外面的一层壳。Cuberta 就是这样构建的。这也是唯一可以自由选择工具粒度的类别。
如果你要自己写一个
从对话记录开始,而不是从你的 API 开始。写下用户真的会对你的应用说的十句话,用他们自己的措辞。这些句子就是你的工具;你手上已有的 API 是它们底下的实现细节。然后:
- 先发布回读工具,并且自己用。如果你都看不懂自己的场景摘要,模型更看不懂。
- 按结果命名工具——
place_buildings_along,不是batch_transform_instances。 - 用一个你没给系统提示、也没给示例的智能体来测。它第一次就没做对的地方,是工具的问题,不是模型的问题。
工具面是一份设计文档。它写明了你的应用认为场景由什么构成、人是在什么粒度上思考它的、以及哪些错误代价低廉。智能体只是碰巧是这份文档极其字面的读者——所以认真写好它才是主要工作,而底下的协议确实是最简单的那部分。