行业资讯
📅 2026/9/8 4:22:05
从MCP到UnrealClaude:自然语言驱动Unity与Unreal编辑器
2026年做游戏工具链绕不开一个关键词MCP。还记得前两年我还在为一个“批量摆件工具”反复写Editor脚本现在很多团队已经开始用自然语言直接指挥Unity和Unreal了。Model Context Protocol模型上下文协议就是这件事的底座它把游戏编辑器的能力暴露成一个个可以被大模型调用的工具也就是MCP Server。你对着Claude说一句“在原点创建一个红色Cube再在它右边放一个球”AI就能拆成工具调用真正去改你的场景。这篇文章我会从实际踩坑的角度拆一遍从Unity MCP到UnrealClaude的完整链路MCP的原理、工具链怎么搭、自然语言怎么转换成编辑器操作以及最容易被文档忽略的坑。适合正在用Unity/Unreal做项目又被重复场景搭建、资源整理、参数调整折磨的程序和TA。1. MCP和游戏引擎结合的核心思路1.1 MCP解决的是“AI缺手缺脚”的问题MCP本质上是一个开放协议解决的是“大模型怎么调用外部工具”的问题。没有MCP之前你想让AI帮忙改Unity场景只能让它生成一段C#脚本你再手动复制进编辑器、编译、执行。MCP把这件事变成了标准的Client/Server结构Claude这类应用作为HostMCP Server负责暴露工具工具背后才是Unity或Unreal的编辑器API。你可以把MCP理解成USB-C接口以前每个设备都要专用线现在大家都用同一个协议插上就能通信。我第一次接触它时也有点懵觉得这不就是“函数调用”吗其实重点在于LLM要知道有哪些工具、每个工具接收什么参数、返回什么结果。MCP把工具列表、参数结构、执行结果都标准化了。大模型在对话中可以动态读取这些信息然后生成结构化的工具调用。换句话说你不需要预先训练一个“识别Unity意图”的模型MCP工具描述本身就是模型和环境之间的说明书。还有一个容易混淆的概念是Computer Use。Computer Use是靠视觉识别屏幕然后模拟鼠标键盘操作适合操作那些没有接口的旧软件。但对游戏引擎这种重GUI、高频操作的工具MCP明显更稳它直接调用API不需要关心按钮位置、分辨率、弹窗遮挡。编辑器哪怕深色模式、自定义布局对MCP都不影响。1.2 为什么Unity和Unreal都值得接一套MCPUnity的自动化通常靠C# Editor脚本Unreal靠Python和蓝图两套体系的调用方式完全不一样。如果只是想自己用倒也无所谓但一旦想让AI统一调度就需要一个比较抽象的操作层。MCP就是这个抽象层它不关心底层是Unity还是Unreal上游LLM只看到一组统一的工具。从影响范围看这套工具链最适合三类人。第一类是技术美术大量白盒场景、资源批量调整、光照测试用自然语言能省很多重复操作。第二类是游戏程序尤其是做玩法原型的时候频繁要生成测试Actor、调整参数、对比效果。第三类是希望团队里“非程序”也能操作编辑器的策划或PM给策划一个Claude入口说一句“在第三关需要放5个障碍物”要是权限控制得好他们自己就能完成基础摆件。但别指望它什么都干。复杂动画、需要美术直觉的构图、涉及物理手感微调的部分目前还是人来判断更靠谱。MCP更适合确定性操作而不是创意决策。理解了这一点你才不会对工具链产生不切实际的期待。2. 搭建前的准备环境版本和模型选择2.1 基础环境首选清单在动手之前先把环境梳理清楚。游戏引擎版本、Python版本、Node版本都会影响踩坑概率。我给一份我日常比较稳的组合组件推荐版本备注UnityUnity 6 LTS 或 2022.3 LTS2021.3也能用但部分新API需要适配Unreal EngineUE 5.3或5.4需要启用Python Editor Script PluginPython3.10MCP官方Python SDK目前很活跃Node.js18如果用TypeScript SDK才需要MCP客户端Claude Desktop / Claude Code / Cursor也可以自己写Host编辑器VS Code / Rider调试MCP Server用我的建议是Windows为主因为游戏引擎在Windows上遇到问题更容易搜到解决方案。MCP Server跑在本地监听回环端口不要暴露到公网这一点后面会在安全部分专门说。2.2 LLM选型Claude不一定唯一“UnrealClaude”这个名字容易让人以为只能用Claude。实际上MCP标准下只要模型支持工具调用就能接入。我选模型时会看三个点函数调用稳定性、上下文长度、是否方便内部部署。Claude系列在多步工具调用上确实表现很好尤其适合“连续创建多个物体再统一调整”这种场景。本地模型像是Qwen系列、GLM系列也有工具调用能力但对“多个工具轮流执行”的稳定性还需要压测。一个简单的测试方法让它连续调用三次同一个工具每次参数不同看看是否都能正确填参数。如果这一步都跑不顺后面复杂任务基本没法用。对团队项目而言还有个现实问题编辑器操作会暴露项目路径、资源名、场景结构如果公司对资产保密有要求本地模型或私有化部署会安全很多。但本地模型硬件要求不低部署和维护成本也高。个人学习阶段先用云端模型把流程跑通再决定要不要私有化。2.3 从官方SDK开始不要自己写JSON-RPCMCP底层协议是JSON-RPC 2.0但我不建议自己实现。官方Python SDK已经把Server、工具注册、连接管理都封装好了用起来体验很好。下面是最小的FastMCP示例from mcp.server.fastmcp import FastMCP mcp FastMCP(game-dev-tools) mcp.tool() def add_two_numbers(a: int, b: int) - int: 计算两个整数的和。 return a b if __name__ __main__: mcp.run()这个代码虽然简单但已经是一个可被Claude连接的MCP Server了。关键点是函数名和docstring它们会被发送给模型。docstring写得越具体模型越不容易填错参数。后面聊自然语言识别时这一点会非常明显。3. Unity MCP实战从配置到场景布置3.1 Unity侧为什么要放一个BridgeMCP Server是独立进程而Unity编辑器的API跑在Unity进程里。两个进程之间需要一个桥梁。我见过有人直接用Unity命令行批处理模式跑任务但那样每执行一次都要重新加载项目速度慢而且不能和当前打开的Editor实时交互。更好的方式是在Unity Editor里跑一个C# TCP服务我习惯叫它“Bridge”。整体链路是这样的ClaudeHost通过标准MCP协议调用Python MCP ServerPython Server再把请求转发到Unity Editor里的C# BridgeBridge调度到Unity主线程执行API操作。这样做的好处是Unity侧的所有编辑器能力都能复用不需要为MCP单独封装一遍。3.2 写一个最小的Unity Bridge在Unity项目里创建Editor目录放一个最简单的Bridge脚本。注意这只是一个架子实际用的时候要加上JSON解析、错误处理、返回结果。using System; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using UnityEditor; using UnityEngine; public static class McpBridge { private static TcpListener _listener; private static SynchronizationContext _mainContext; [MenuItem(Tools/MCP Bridge/Start)] public static void Start() { _mainContext SynchronizationContext.Current; _listener new TcpListener(IPAddress.Loopback, 9100); _listener.Start(); _listener.BeginAcceptTcpClient(OnClientAccepted, null); Debug.Log([McpBridge] listening on 9100); } private static void OnClientAccepted(IAsyncResult ar) { var client _listener.EndAcceptTcpClient(ar); _listener.BeginAcceptTcpClient(OnClientAccepted, null); var stream client.GetStream(); byte[] buffer new byte[65536]; int len stream.Read(buffer, 0, buffer.Length); string json Encoding.UTF8.GetString(buffer, 0, len); _mainContext.Post(_ ExecuteCommand(json), null); } private static void ExecuteCommand(string json) { // 演示创建一个Cube var cube GameObject.CreatePrimitive(PrimitiveType.Cube); cube.name AI_Generated; Debug.Log(json); } }这里的核心是_mainContext.Post它把收到的命令丢回Unity主线程执行。Unity很多Editor API只能从主线程调用如果直接在TCP接收线程里操作轻则报错重则直接卡死编辑器。这个点无论如何都要处理。3.3 配置MCP Server工具集并接入ClaudeUnity Bridge启动后Python端要定义对应的MCP工具。我用FastMCP写一个create_primitive工具它实际做的事情是把参数打包成JSON发到Unity的9100端口。from mcp.server.fastmcp import FastMCP import json, socket mcp FastMCP(unity-mcp) def send_to_unity(cmd, args): with socket.create_connection((127.0.0.1, 9100), timeout5) as s: s.sendall(json.dumps({cmd: cmd, args: args}).encode()) return s.recv(65536).decode() mcp.tool() def create_primitive(primitive_type: str, name: str, x: float, y: float, z: float) - str: 在Unity当前场景中创建一个基础几何体。primitive_type仅支持Cube、Sphere、Cylinder。坐标为世界坐标单位米。 return send_to_unity(create_primitive, { type: primitive_type, name: name, x: x, y: y, z: z }) if __name__ __main__: mcp.run()然后需要在MCP客户端里注册这个Server。以Claude Desktop为例配置文件在claude_desktop_config.json加上{ mcpServers: { unity-mcp: { command: python, args: [server.py] } } }配置好后重启客户端。如果顺利工具列表里应该能看到create_primitive。3.4 用一句话让AI搭一个测试房间配置都通了之后最爽的部分来了。我在Unity里开一个空场景然后对Claude说“在原点创建一个Cube作为地面缩放到(10,1,10)再在(0,0.5,0)处创建一个红色球体最后把相机移动到(5,3,5)并看向原点。”这句话会被模型拆成多个工具调用可能包括创建Cube、设置缩放、创建球体、创建材质、调整相机。如果你的MCP Server里没有“设置材质”或“设置相机”的工具模型可能会只做一部分。所以工具的覆盖面直接影响自然语言的操作边界。第一次跑通时我最大的感慨是原来需要写一整套脚本的活现在有点像在跟一个手脚麻利的实习生沟通。但前提是实习生能理解你的话而这一点靠的是工具描述不是模型玄学。3.5 Unity MCP工具太多怎么办接的工具一多模型选择错误率也会上升。我的做法是给工具名加统一前缀比如unity_scene_create_primitive、unity_scene_set_transform同时在描述里强调“只在当前激活的场景中操作”。这样模型看到名字就知道属于哪个域不容易跟Unreal的工具搞混。还有一个思路是动态注册工具。比如只在需要摆件时才加载场景类工具需要做资源优化时才加载Asset工具。MCP协议本身支持服务端动态更新工具列表客户端也有发现机制。工具列表精简化之后模型调用准确率会明显提升。4. UnrealClaude用自然语言控制Unreal Editor4.1 原理不是“AI读蓝图”而是Python远程执行Unreal侧的逻辑比Unity还要简单因为Unreal内置了Python Editor Script Plugin。社区里被称为UnrealClaude的方案本质就是Claude通过MCP Server把自然语言翻译成对Unreal Python API的调用。这里要区分两种模式。第一种是在Unreal编辑器内部启动一个Python脚本自己开Socket监听端口接收MCP请求。第二种是外部Python进程使用Unreal的Remote Execution协议去调用编辑器Python。我实践下来更推荐外部模式能不污染项目代码就不污染升级引擎版本时也更好调整。需要注意的是Unreal的Python API和Unity的C# API设计思路不一样。Unreal更多是面向“编辑器级别的操作”比如生成Actor、修改资产、运行关卡脚本。但如果你希望AI直接生成复杂蓝图节点图那难度会大不少因为Blueprint图的序列化和Python API绑定比较深。我建议UnrealClaude初期重点放在关卡布置、Actor属性调整、资产批量处理上面。4.2 启用Unreal的Python和执行环境在Unreal里启用Python步骤并不复杂打开Plugins搜索“Python Editor Script Plugin”勾选启用。项目设置里搜索“Python”确认Enable Remote Execution已勾选。重启编辑器在菜单Window Developer Tools Python Console中打开Python控制台。输入import unreal; print(unreal.EditorLevelLibrary.get_editor_world())如果能打印出World对象说明Python环境已通。不同UE版本API差异很大。UE 5.4之后官方更推荐用EditorActorSubsystem代替老的EditorLevelLibrary。写工具时最好加一层兼容例如def get_editor_actor_subsystem(): return unreal.get_editor_subsystem(unreal.EditorActorSubsystem)4.3 快速实现一个Unreal MCP Server下面这个MCP工具演示的是“在当前关卡生成一个Actor”。由于Unreal里生成Actor需要知道具体的类或Blueprint资源路径所以工具参数里必须传class_path否则模型再聪明也不知道该生成什么。import unreal from mcp.server.fastmcp import FastMCP mcp FastMCP(unreal-mcp) mcp.tool() def spawn_actor(class_path: str, x: float, y: float, z: float, name: str ) - str: 在当前Unreal关卡中生成一个Actor。class_path必须是加载好的Blueprint路径例如/Game/Blueprints/BP_Enemy.BP_Enemy_C。 actor_class unreal.load_object(None, class_path) if not actor_class: return f无法加载类: {class_path} location unreal.Vector(x, y, z) actor unreal.EditorActorSubsystem().spawn_actor_from_class(actor_class, location) if actor and name: actor.set_actor_label(name) return actor.get_name() if actor else 生成失败 if __name__ __main__: mcp.run()这个工具一旦注册Claude就能在你需要时调用。比如你说“在当前位置前方生成一个BP_Enemy”它会尝试把位置算出来再生成一个对象。如果你希望它能“生成一个Cube”那需要在服务端处理基础网格的生成逻辑不能只靠spawn_actor_from_class。4.4 用中文指令操控一支“巡逻队”我用UnrealClaude做过一个比较顺手的测试让AI在场景里放置5个巡逻点并把它们按顺序重命名。当时输入的是“在当前关卡里生成5个TargetPoint位置沿X轴每隔200厘米一个命名从Patrol_1到Patrol_5。”模型会先识别出“沿X轴每隔200厘米”这个槽位然后生成一串参数最终执行五次生成。如果不做批量封装它可能真的会调用五次工具每次生成一个点。这样做也能工作但速度慢而且占用token多。我后来在Server端加了一个批量工具spawn_multiple_target_points(points: list)问题就解决了。所以工具的设计值得花时间去思考。一个把循环写在Server端的高层工具远比让LLM一次次调底层工具稳定得多。5. 意图识别、槽位提取与工具描述自然语言到MCP的关键5.1 从传统NLU到LLM Function Call如果你接触过“Python自然语言意图识别 槽位提取”这套东西应该知道传统做法是训练一个意图分类器再抽实体槽位比如地点、数量、颜色。MCP和LLM出现后这套东西的很大部分被模型直接替代了。模型看到这话自己就会生成JSON格式的工具调用参数就是槽位。但底层的逻辑还是相通的。比如“在原点创建红色Cube”可以看成意图create_primitive槽位colorred, shapecube, position(0,0,0)如果模型没有正确提取通常不是模型不行而是工具描述里没有写清楚“红色”应该对应哪个参数或者根本没有接收颜色参数的工具。所以做MCP Server时要把自己放在“给一个不熟悉项目的实习生写操作手册”的位置上。5.2 工具描述的影响有多大一个写得差的工具描述Creates a cube.一个写得好的描述在Unity当前场景中创建一个Cube GameObject。 - primitive_type: 可选Cube、Sphere、Cylinder - x/y/z: 世界坐标单位米 - name: 物体名称如果不传则使用默认名字 - 如果没有指定材质则使用默认材质 - 返回新建物体的名称和实例ID后面这种描述模型基本不会理解错。我见过太多工具调用失败最后查下来都是描述里没写清楚默认值或单位。你写“缩放为2倍”到底是整体缩放2倍还是每个轴都是2这个歧义模型解不了只能靠描述消除。5.3 在MCP Server里加入“资源别名映射”自然语言里“敌人”“箱子”这类词模型并不知道对应哪个Prefab或Asset路径。最稳妥的方式是在Server端维护一张别名映射表ALIAS_MAP { 敌人: /Game/Blueprints/BP_Enemy.BP_Enemy_C, 宝箱: /Game/Blueprints/BP_Chest.BP_Chest_C, 地面: /Game/StarterContent/Materials/M_Ground.M_Ground } def resolve_class(alias: str) - str: return ALIAS_MAP.get(alias, alias)这样模型不需要记住整个项目的资源路径它只要把用户话里的“敌人”原样传给工具Server端负责解析。这个方法在Unity侧同样适用只不过把路径换成Assets/Prefabs/Enemy.prefab而已。5.4 多步任务拆解一次性指令 vs 分步调用大模型确实能做多步计划但让它在一次对话里完成几十个工具调用出错率和耗时都会增加。我的经验是尽量把“高频动作序列”封装成高层工具。比如“搭建一个测试房间”这个需求与其让模型调用create_primitive、set_material、set_lighting、set_camera等等不如在Server端直接写一个create_test_room(room_width, room_height, wall_color, light_intensity)工具。这并不是剥夺模型的推理能力而是把确定性的流程从模型手里拿回来。模型更擅长理解你的意图并不擅长精确执行一长串确定性操作。工程上的分工应该是模型做规划Server做执行。6. 实战中的坑与排查技巧6.1 Unity Bridge连不上先telnet如果你发现Claude报了“工具执行失败”第一步不是去看AI的返回而是先确认Unity Bridge是否真的在监听。我通常直接跑telnet 127.0.0.1 9100如果连不上检查端口是否被防火墙挡了、Unity里的Bridge是否真的通过菜单启动、有没有改过端口号。还有一个常见问题是Python Server和Unity Bridge虽然在同一台机器但Unity占了多个端口忘了监听地址是回环地址。6.2 Unity许可证错误“No valid Unity Editor license found”这个报错出现时通常是MCP Server或外部进程尝试调用Unity命令行但Unity许可证没激活或环境变量不对。MCP链路中如果Python Server不是去连接已经打开的Unity Editor而是去启动一个Unity批处理进程就可能踩到这个坑。解决思路很简单优先连接已激活的Editor实例不要动不动就起新进程。如果确实需要在命令行环境跑Unity提前在GUI里手动激活一次许可证确保当前用户目录下有有效的许可证文件。CI环境一定要有单独的激活流程否则很容易间歇性失败。6.3 Unreal Python API在不同版本中不一致Unreal的Python API迭代比较快网上很多老教程还在用unreal.EditorLevelLibrary但新版本里有些方法已经标为Deprecated。我建议所有工具代码都自己封装一层内部用hasattr判断版本def editor_actor_subsystem(): return unreal.get_editor_subsystem(unreal.EditorActorSubsystem)这样以后升级UE版本只需要修这一层适配MCP工具不用大改。6.4 所有UI/API调用都需要回到主线程Unity侧我已经强调过用SynchronizationContext。Unreal侧如果自己搭Socket服务也要注意收到外部网络消息的线程不一定适合直接操作编辑器对象。Unreal编辑器里一般用unreal.register_slate_post_tick_callback注册一个每帧回调把真正要执行的命令放到回调里跑。或者在外部RPC模式下利用Unreal的Remote Execution机制让它在内部帮你排队到主线程。这个问题很难从报错里看出来有时候只是“偶尔卡死”或“偶尔崩溃”排查起来非常费劲。所以一开始写Bridge就要把“命令进来先入队主线程再执行”作为基本架构。6.5 工具列表太长导致模型“瞎调用”MCP Server一旦注册了几十个工具模型选择工具时会出现幻觉。比如想创建Sphere却调了创建Cylinder的工具。这不是模型不聪明而是工具列表太密集名字又太像。对策缩小工具集按任务域拆分MCP Server。一个Server只负责场景布置另一个只负责资源批处理。Claude客户端可以连接多个Server但每个Server的工具数量控制在15个以内准确率会高很多。6.6 日志调试三板斧MCP调试有现成工具。第一步用MCP Inspector可以可视化查看工具列表和调用结果。第二步在Python Server里加日志记录每次“收到什么参数、返回什么结果”。第三步查看Claude客户端的MCP日志很多报错在那里才有详细信息。具体到实现可以给FastMCP的每个工具加一个简单装饰器把入参和返回值打到本地文件。别嫌麻烦这个日志会成为后续优化工具描述的重要依据。6.7 批量操作性能优化批量生成大量Actor时让AI一个一个调用工具是最差的做法。正确做法是定义批量工具让LLM传一个数组Server端在循环里完成所有操作。比如生成100个Cube如果一次工具调用能生成全部耗时只在网络通信一次的基础上加上Unity/Unreal本身的创建时间体验会好很多。我还会建议在批量生成时暂时关闭Undo记录或者把操作包成一个事务。这样既快又不会让Undo列表爆炸。最后再分享一点个人心得这套MCP工具链最值钱的地方不是“AI能帮你摆几个Cube”而是它把编辑器操作变成了一种可复用、可编排、可描述的能力。我的建议是从一个具体痛点入手比如“批量重命名资源”或“快速搭白盒”先做两个工具跑通全链路再慢慢扩展。工具描述值得反复打磨每次模型误解参数都可能是描述不够清晰。版本迭代也确实快但只要你理解了协议和调用链具体工具从Unity换到Unreal不过是换一层适配而已。