最近 MCP 这个词在 AIGC 圈子里的热度非常高。如果你用过 Claude Desktop、Cursor、Windsurf 这类 AI 工具,大概率听过“MCP Server”“工具调用”这些概念。但一说到“把 MCP 接到虚幻引擎(Unreal Engine)里”,网上的资料就开始各说各话:有人讲插件安装,有人讲 Python 脚本,有人直接丢一个仓库链接让你自己看,真正能把协议原理、调用链路和 UE 侧怎么对接讲清楚的很少。
这篇文章就是来解决这个问题的。我会从 MCP 的概念开始,逐步拆解它在虚幻引擎里的集成方式,然后给出可运行的 MCP Server 代码、UE 编辑器侧的本地桥接脚本,以及常见报错的排查思路。不管你是刚接触 UE 的新手,还是已经写过一些编辑器插件的进阶开发者,都可以按文章顺序把链路跑通。
顺便说明一下:本文标题写的 UE5.8,但 MCP 的原理不绑定某个具体 UE 版本。如果你打开 Epic Launcher 发现用的是 UE5.4、UE5.5、UE5.6,同样可以按本文思路操作,差异主要在个别 Python API 的命名上,文中会重点提示。
1. 为什么在虚幻引擎中需要 MCP
1.1 MCP 到底是什么
MCP 的全称是 Model Context Protocol,中文常翻译成“模型上下文协议”。它是由 Anthropic 提出的一个开放协议,解决的问题很直接:让大语言模型能够安全、标准化地调用外部工具和获取上下文数据。
在 MCP 出现之前,如果你想给 AI 加一个“查询天气”的能力,通常需要自己写一个 HTTP 接口,然后把接口地址、请求参数、返回格式全部告诉模型。不同的人写的接口风格完全不同,模型接入成本很高。
MCP 做的事情就是把这一层标准化。它定义了一套基于 JSON-RPC 2.0 的通信方式,AI 客户端(比如 Claude Desktop)可以通过固定的几种方法,发现某个服务端提供了哪些工具、调用某个工具、读取某些资源。你可以把 MCP 理解成“USB 接口”:无论背后是什么设备,只要接口规格统一,就能即插即用。
对应到虚幻引擎里,就是让 AI 能“看到”当前关卡有哪些 Actor、能修改某个 Actor 的属性、能在输出日志里打印信息,甚至能批量生成基础蓝图节点。
1.2 UE 开发者使用 MCP 的典型场景
在实际开发中,MCP 接入 UE 后能做的事情大致分四类:
| 能力层 | 典型动作 | 实际价值 |
|---|---|---|
| 信息查询 | 查询关卡 Actor 数量、获取选中对象信息、列出资产路径 | AI 先了解场景,再提供相对准确的建议 |
| 资产操作 | 重命名资产、批量设置材质参数、创建基础蓝图类 | 减少重复性操作,把 AI 当成“编辑器宏” |
| 场景生成 | 批量摆放置物、生成静态网格体实体、设置 Transform | 快速搭白盒场景,省去大量手动摆放时间 |
| 自动化流程 | 运行项目测试、触发命令let(Commandlet)、导出数据 | 把 AI 接入到项目构建与验收流程中 |
其中信息查询和日志打印是最容易落地的,也是本文演示的重点。因为这两类操作风险低,即使 AI 理解有偏差,也不会对项目资产造成不可逆的破坏。
1.3 没有 MCP 时怎么实现类似效果
在 MCP 还没有流行起来的时候,社区里也有过一些“AI 操作 UE”的方案,常见的有:
- 直接把 UE 的 Python 脚本片段发给 AI,让它生成完整代码。这种方式的问题是,AI 不知道你项目里具体有什么资产、哪个 Actor 叫什么名字,只能凭泛化知识猜。
- 自己写一个 WebSocket 服务,用自定义协议让 AI 调用。这种方式能跑通,但协议是自己的,换一个 AI 客户端就得重新适配。
- 用编辑器插件内置大模型聊天窗口。功能很强,但代码量大,而且相关插件通常绑定某个特定 AI 服务商,不够通用。
MCP 的优势恰恰在于“通用”。你只需要维护一个 MCP Server 和一个 UE 侧桥接模块,就能让任何支持 MCP 的客户端连接上来。
1.4 MCP 给 UE 带来的能力边界
需要注意的是,MCP 不是“AI 自动做游戏”的万能钥匙。它只是一个工具调用协议,AI 的决策质量仍然依赖模型能力、工具描述质量和 UE 侧封装的安全边界。
在引入 MCP 时,要分清什么适合交给 AI,什么不适合:
- 适合:查询场景信息、生成临时测试资产、批量执行低风险操作、把报错日志丢给 AI 分析。
- 不适合:在未备份的情况下删除资产、自动修改主关卡、调用会导致项目无法打开的高风险编辑器命令。
理解了这一点之后,再看 MCP 的架构就不会被各种花哨的功能带偏。
2. MCP 与 UE 的集成架构
2.1 MCP 的四个核心概念
在动手写代码之前,必须先搞清楚 MCP 里的几个角色和术语,否则看文档容易一头雾水。
- Host(宿主):指运行 AI 模型的应用程序,例如 Claude Desktop、Cursor、自研的聊天客户端。它是用户交互的入口。
- Client(客户端):在 Host 内部,负责与 MCP Server 建立连接,发送方法请求。你可以理解成“Host 里的协议适配层”。
- Server(服务端):提供具体能力的程序,例如我们即将写的
ue-demo-server。它暴露一批工具(Tools)、资源(Resources)和提示(Prompts)。 - Transport(传输层):MCP 支持多种传输方式,最常见的是 stdio(标准输入输出)和 Streamable HTTP。编辑器内工具场景中 stdio 最方便,因为它不需要开端口。
到目前为止,MCP 官方主要定义了三个原语:
| 原语 | 作用 | 类比 |
|---|---|---|
| Tools | 可被 AI 调用的函数,由 AI 决定何时调用 | 类似函数列表(Function Calling) |
| Resources | 可被读取的上下文数据,例如文件内容、场景快照 | 类似“给 AI 喂资料” |
| Prompts | 预定义的提示模板,方便复用常见指令 | 类似“提示词模板” |
其中 Tools 是本文核心,因为“让 AI 操作 UE”本质上就是让 AI 调用 UE 的封装函数。
2.2 UE 接入 MCP 的推荐架构
目前 Unreal Editor 官方还没有内置 MCP 按钮,所以我们需要自己搭建一条桥。推荐的架构分三层:
1. AI 客户端(Host) 2. MCP Server(独立 Python 进程) 3. UE 侧桥接模块(编辑器内运行的本地 HTTP/WebSocket 服务)MCP Server 本身不直接调用 UE API,而是把“UE 能执行的命令”封装成工具。当 AI 决定调用某个工具时,MCP Server 通过本地 HTTP 请求把指令发送给 UE 编辑器内运行的桥接服务,桥接服务再通过unrealPython 模块或 C++ 接口真正操作编辑器。
为什么中间要隔一层?原因有三个:
- UE 内置 Python 不一定能安装第三方 MCP SDK。UE 使用的 Python 环境是引擎自带的,直接安装
mcp包会遇到很多兼容性问题。 - 职责分离。MCP Server 只处理协议逻辑,UE 侧只处理编辑器操作,任何一侧出问题都好排查。
- 安全控制更灵活。UE 桥接服务可以只绑定
127.0.0.1,并且只允许白名单指令,降低 AI 误操作风险。
这个架构也是目前社区大多数 UE MCP 插件采用的思路。
2.3 数据流与调用链路解析
一次完整的调用链路可以这样理解:
- 用户在 Claude Desktop 中输入“当前关卡有多少个 Actor?”
- Claude 从系统提示中知道 MCP Server 提供了
get_level_actor_count这个工具。 - Claude 发送一个内部调用请求,由 Host 里的 Client 通过 MCP 协议发起
tools/call。 - MCP Server 收到请求,解析出工具名和参数。
- MCP Server 向 UE 本地桥接服务的
http://127.0.0.1:8765发送{"action": "get_actor_count"}。 - UE 桥接服务调用
unreal.EditorActorSubsystem查询关卡中的所有 Actor。 - 查询结果沿着原路返回,最终展示给用户。
链路不算短,但每一层的职责都清晰,排错时可以从任意一环断开验证。
3. 环境准备与版本说明
3.1 需要准备的工具
本文的示例需要以下环境:
- 虚幻引擎:UE 5.x 系列,本文以 UE5.8 版本为背景描述,但核心依赖的 Python API 在 UE5.1 之后基本一致。
- 启用 Python 编辑器脚本插件:在 UE 编辑器中,点击菜单
Edit -> Plugins,搜索 Python,启用Python Editor Script Plugin,然后重启编辑器。 - Python 3.10+:用于运行 MCP Server 的独立 Python,建议至少 3.10,MCP Python SDK 要求比较新的 Python 版本。
- MCP Python SDK:执行
pip install "mcp[cli]"安装。 - 支持 MCP 的客户端:Claude Desktop、Cline、自研客户端均可,本文会用 Python 脚本做客户端验证,不强依赖具体商业软件。
- 本地代码编辑器:VS Code 或任何你顺手的编辑器。
3.2 版本差异说明
以下是几个容易踩到的版本差异点:
| 差异点 | 说明 |
|---|---|
unreal.EditorActorSubsystem | UE5.x 常见 API,推荐使用;旧版本如果找不到,可改用unreal.EditorLevelLibrary.get_all_level_actors() |
MCP SDK 的FastMCP类 | 不同版本初始化方式可能略有不同,但@mcp.tool()装饰器基本稳定 |
| Python 版本 | UE 内置 Python 与独立 Python 的版本可能不同,桥接时尽量使用双方都支持的语法 |
| 编辑器启用 Python | 新版 UE 的 Python 插件入口位置可能变化,建议直接在 Plugins 面板搜索 |
如果你的环境和本文不同,先不要急着改代码,优先对照版本差异调整 API 名称即可。
3.3 一个最小可行目录结构
建议按下面的结构组织代码:
ue-mcp-demo/ ├── mcp_ue_demo_server.py # MCP Server,独立Python运行 ├── mcp_ue_demo_client.py # 测试客户端脚本 ├── ue_bridge.py # UE 编辑器内运行的本地桥接服务 ├── claude_desktop_config.json # 客户端配置示例(可选) └── README.md这样分层的好处是:MCP Server 可以脱离 UE 单独测试,UE 桥接服务也可以单独用curl测试,定位问题非常方便。
4. 核心协议拆解:JSON-RPC 与工具调用
4.1 MCP 基于 JSON-RPC 2.0
MCP 的通信协议建立在 JSON-RPC 2.0 之上。JSON-RPC 是一种很轻量的远程调用协议,请求和响应都是 JSON 对象,基本结构如下:
{ "jsonrpc": "2.0", "id": 1, "method": "方法名", "params": {} }响应则包含result或error。MCP 复用了这套模型,定义了自己的方法集合。作为入门,你不需要从头实现 JSON-RPC,官方 SDK 已经处理好了底层通信,但理解这个基础有助于看日志。
4.2 三个关键方法
在 MCP 协议里,有三个方法必须理解:
第一个是initialize。当客户端连接 MCP Server 后,第一件事就是握手。客户端告诉服务端自己的协议版本、客户端名称等;服务端返回支持的协议版本和服务端信息。这个过程几乎被 SDK 透明处理,但如果你自己抓包排查问题,会经常看到它。
第二个是tools/list。客户端询问“你这个 Server 提供哪些工具”。注意,这里返回的是工具的名称、描述和参数格式(JSON Schema),并不是执行结果。AI 模型就是依赖这个列表来决定何时调用哪个工具。
第三个是tools/call。客户端携带工具名和参数,请求执行某个工具。服务端执行完毕后返回执行结果。这个结果会作为模型生成回答的上下文。
下面是一段tools/call请求的简化示例:
{ "jsonrpc": "2.0", "id": 9, "method": "tools/call", "params": { "name": "print_to_ue_log", "arguments": { "message": "Hello UE" } } }对应的响应:
{ "jsonrpc": "2.0", "id": 9, "result": { "content": [ { "type": "text", "text": "{\"printed\": \"Hello UE\"}" } ] } }在 MCP Server 的日志里看到这类结构时,就可以快速判断是请求没收到、工具名不匹配,还是参数校验失败。
4.3 工具描述(Tool Schema)怎么写
工具描述的准确性直接影响 AI 是否愿意调用它。同一个工具,下面的写法差距很大。
不够清晰的写法:
查询Actor数量较为清晰的写法:
查询当前UE关卡中的Actor总数,用于评估场景复杂度后者包含了“当前关卡”“总数”“用于什么目的”这些信息。当 AI 面对“场景里对象多不多”这类模糊问题的时候,更可能命中后者。
参数 Schema 同样重要。比如我们设计一个“打印日志到 UE Output Log”的工具,参数是message,用 Python 的FastMCP写,可以利用类型注解自动生成 Schema:
@mcp.tool() def print_to_ue_log(message: str): """在UE输出日志中打印一条消息,方便确认AI到UE的链路是否通畅。""" ...这里message: str会让 SDK 自动生成{"type": "string"}的 Schema。如果参数是整数、布尔值,类型也要写清楚。
4.4 一次完整工具调用的数据包示例
为了让你在排查时不慌,下面给出一次“查询 Actor 数量”的完整 JSON 交互示意,但不要求手动构造这些数据,理解即可。
客户端发起tools/call:
{ "jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": { "name": "get_level_actor_count", "arguments": {} } }服务端在 UE 桥接层拿到真实数量后,返回给模型:
{ "jsonrpc": "2.0", "id": 2, "result": { "content": [ { "type": "text", "text": "{\"ok\": true, \"actor_count\": 345}" } ] } }模型看到345之后,才会组织自然语言回答用户:“当前关卡共有 345 个 Actor。”
到这里,MCP 的协议原理就已经足够支撑我们写代码了。下面开始实战。
5. 实战:从零搭建 UE 的 MCP Server
5.1 安装 MCP Python SDK
在独立 Python 环境中执行:
pip install "mcp[cli]"安装完成后,可以用下面的命令确认版本:
python -m mcp --version注意:不要在 UE 内置 Python 环境里执行这个命令。UE 自带的 Python 环境通常不联网、缺少 pip 管理机制,强行安装容易破坏引擎环境。这也是我们选择“MCP Server 独立运行 + UE 本地桥接”方案的重要原因。
5.2 编写第一个 MCP Server
新建文件mcp_ue_demo_server.py,内容如下:
# 文件路径:ue-mcp-demo/mcp_ue_demo_server.py from mcp.server.fastmcp import FastMCP mcp = FastMCP("ue-demo-server") @mcp.tool() def get_level_actor_count(): """查询当前UE关卡中的Actor总数(当前为演示数据)。""" # 后续会改成通过本地HTTP调用UE编辑器获取真实数据 return {"actor_count": 0, "source": "demo"} @mcp.tool() def print_to_ue_log(message: str): """在UE输出日志中打印一条消息。""" # 此处暂不真正连接UE,只返回确认信息 return {"printed": message, "source": "demo"} if __name__ == "__main__": mcp.run()这段代码做了三件事:
- 创建了一个名为
ue-demo-server的 MCP Server 实例。 - 用
@mcp.tool()注册了两个工具,分别是查询 Actor 数量和打印日志。 - 调用
mcp.run()启动服务,默认使用 stdio 传输。
mcp.run()默认在标准输入输出上监听请求。这样启动后,它不会自己创建端口,而是等着客户端把它当作子进程启动并读写标准流。好处是不需要担心端口冲突,缺点是只能在 CLI 模式下用。
5.3 用客户端脚本验证服务端
为了确认 Server 能正常工作,我们再写一个 Python 客户端。这个过程很重要,因为如果连最基本的tools/list和tools/call都走不通,后面接 UE 只会更乱。
新建文件mcp_ue_demo_client.py:
# 文件路径:ue-mcp-demo/mcp_ue_demo_client.py import asyncio import sys from mcp import ClientSession, StdioServerParameters from mcp.client.stdio import stdio_client async def main(): server_params = StdioServerParameters( command=sys.executable, args=["mcp_ue_demo_server.py"], ) async with stdio_client(server_params) as (read, write): async with ClientSession(read, write) as session: await session.initialize() tools = await session.list_tools() print("可用工具列表:", [tool.name for tool in tools]) result = await session.call_tool( "print_to_ue_log", {"message": "Hello UE"}, ) print("调用结果:", result) if __name__ == "__main__": asyncio.run(main())运行:
python mcp_ue_demo_client.py预期输出大致是:
可用工具列表: ['get_level_actor_count', 'print_to_ue_log'] 调用结果: ...这里使用sys.executable作为启动命令,可以避免多 Python 环境混在一起时选错解释器的问题。
5.4 在 UE 编辑器内暴露真实 Actor 查询能力
接下来写 UE 侧桥接服务。打开 UE 编辑器,在菜单中找到Edit -> Project Settings -> Plugins -> Python,或者直接用编辑器内的 Python 脚本编辑器运行下面的代码。
新建文件ue_bridge.py(这个文件需要在 UE 内置 Python 中运行):
# 文件路径:ue-mcp-demo/ue_bridge.py # 在 UE 编辑器的 Python 脚本编辑器中运行,或者作为资产脚本运行 import http.server import json import threading import unreal class UERequestHandler(http.server.BaseHTTPRequestHandler): def do_POST(self): length = int(self.headers.get("Content-Length", 0)) body = json.loads(self.rfile.read(length).decode("utf-8")) action = body.get("action") if action == "get_actor_count": response = self._get_actor_count() elif action == "print_log": unreal.log(body.get("message", "")) response = {"ok": True} else: response = {"ok": False, "error": f"unknown action: {action}"} data = json.dumps(response).encode("utf-8") self.send_response(200) self.send_header("Content-Type", "application/json") self.send_header("Content-Length", str(len(data))) self.end_headers() self.wfile.write(data) def _get_actor_count(self): try: subsystem = unreal.EditorActorSubsystem() actors = subsystem.get_all_level_actors() return {"ok": True, "actor_count": len(actors)} except Exception as exc: return {"ok": False, "error": str(exc)} def log_message(self, format, *args): # 避免HTTP访问日志刷屏 return def start_bridge(port=8765): server = http.server.HTTPServer(("127.0.0.1", port), UERequestHandler) thread = threading.Thread(target=server.serve_forever, daemon=True) thread.start() unreal.log(f"UE MCP bridge started on http://127.0.0.1:{port}") return server if __name__ == "__main__": start_bridge()启动后,UE 编辑器会运行一个只监听本机的 HTTP 服务。为了让 MCP Server 能访问,需要让桥接服务持续运行,所以用threading.Thread把它放到后台线程。
几点注意:
127.0.0.1表示只允许本机访问,不要让外网连进来。- 如果
unreal.EditorActorSubsystem在你的 UE 版本里不存在,改用unreal.EditorLevelLibrary.get_all_level_actors()。 get_all_level_actors()返回的是关卡顶层 Actor 列表,不包含子 Actor 层级,初学者使用时要知道这个口径。
5.5 让 MCP Server 调用 UE 本地桥接服务
现在修改mcp_ue_demo_server.py,让两个工具真正访问 UE。完整代码如下:
# 文件路径:ue-mcp-demo/mcp_ue_demo_server.py import json import urllib.request from mcp.server.fastmcp import FastMCP UE_BRIDGE_URL = "http://127.0.0.1:8765" mcp = FastMCP("ue-demo-server") def call_ue_bridge(payload: dict): data = json.dumps(payload).encode("utf-8") req = urllib.request.Request( UE_BRIDGE_URL, data=data, headers={"Content-Type": "application/json"}, ) with urllib.request.urlopen(req, timeout=3) as resp: return json.loads(resp.read().decode("utf-8")) @mcp.tool() def get_level_actor_count(): """查询当前UE关卡中的Actor总数,用于评估场景复杂度。""" return call_ue_bridge({"action": "get_actor_count"}) @mcp.tool() def print_to_ue_log(message: str): """在UE输出日志中打印一条消息,方便确认AI到UE的链路是否通畅。""" return call_ue_bridge({"action": "print_log", "message": message}) if __name__ == "__main__": mcp.run()此时运行客户端脚本,实际效果是先由 MCP Server 请求 UE 桥接服务,再通过unrealAPI 查询真实关卡数据。如果 UE 编辑器没有启动桥接服务,MCP Server 会在urllib.request.urlopen处抛出连接拒绝异常,这也是后面排查的重点。
5.6 接入 Claude Desktop 等支持 MCP 的客户端
如果你希望让 Claude Desktop 直接连接这个 MCP Server,可以在claude_desktop_config.json中配置 MCP 服务。配置查找入口为 Claude Desktop 设置中的 Developer / MCP 栏目,不同客户端入口不同。
参考配置:
{ "mcpServers": { "ue-demo": { "command": "python", "args": ["D:/ue-mcp-demo/mcp_ue_demo_server.py"] } } }关键点:
command最好写独立的 Python 解释器绝对路径,例如C:/Python310/python.exe,避免系统同时存在多个 Python 时选错。args中脚本路径建议写绝对路径。- 需要先启动 UE 编辑器内的桥接服务,再打开客户端,否则工具调用会失败。
配置完成后,你可以在客户端里直接问:“当前关卡有多少个 Actor?”AI 会先通过get_level_actor_count拿到真实数据,再组织回答。
这个 Demo 虽然简单,但从“协议理解”到“UE 真实数据回传”的完整链路已经通了。
6. 常见问题与排查思路
先列出几个最常见的报错现场和对应处理方式:
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
MCP Client 连接后卡住,tools/list超时 | MCP Server 启动失败,或 Python 解释器路径不对 | 先单独运行python mcp_ue_demo_server.py,确认没有语法错误 |
ConnectionRefusedError | UE 桥接服务未启动,或端口不一致 | 在 UE 编辑器中运行ue_bridge.py,确认输出日志里有 bridge started |
工具调用返回unknown action | UE 桥接收到的 JSON 缺少action字段 | 打印请求 body,检查 MCP Server 中call_ue_bridge参数拼写 |
UE 侧找不到unreal.EditorActorSubsystem | UE 版本较旧或 Python 插件未启用 | 改用unreal.EditorLevelLibrary.get_all_level_actors() |
pip install mcp报错 | 本机 Python 版本过低,或安装到了错误的环境 | 检查执行的是不是指定的 Python,使用python -m pip |
| UE 编辑器卡住或崩溃 | 桥接服务在主线程阻塞,或调用了不安全的编辑器 API | 改用线程启动 HTTP 服务;复杂编辑器操作放到游戏线程 |
| AI 反复调用错误工具 | 工具描述不清晰,或参数 Schema 不匹配 | 优化工具 description,尽量在描述中写清楚适用场景 |
下面展开几个重点问题的排查流程。
第一个是“MCP Server 启动失败”。当你配置好 Claude Desktop 后,客户端里可能只显示“工具加载失败”。此时应该脱离客户端,直接手动运行python mcp_ue_demo_server.py。如果进程能挂住不退出,说明 Server 本身没问题;如果直接报错,优先检查 Python 版本和 MCP SDK 安装状态。
第二个是“UE 桥接服务没起来”。在 UE 编辑器里运行脚本后,应该在 Output Log 看到UE MCP bridge started on http://127.0.0.1:8765。看不到说明脚本没有被执行,先检查插件是否启用,再看是否有 Python 语法错误。确认启动后,可以用浏览器或curl测试:
curl -X POST http://127.0.0.1:8765 -H "Content-Type: application/json" -d "{\"action\":\"get_actor_count\"}"如果返回 JSON 而不是 HTML 错误页面,说明桥接服务在线。
第三个是“线程安全问题”。很多初学者在 UE 内部写 HTTP 服务时,直接在主线程serve_forever(),导致编辑器界面无法刷新。本文的示例把服务放在daemon=True的子线程里,问题会缓解,但子线程中直接调用unrealAPI 仍存在跨线程风险。临时验证没问题,生产环境建议把请求塞入队列,由编辑器主线程统一消费,或者用unreal.CallInEditor之类的延迟调度机制。由于不同 UE 版本的调度 API 不完全一致,这里不列出固定代码,你需要在项目里按实际版本实现。
7. 最佳实践与工程建议
MCP 接入 UE 的价值很大,但如果缺少工程约束,风险同样很大。下面几条建议来自实际项目里最常见的翻车点。
7.1 权限与安全边界
永远记住一个原则:AI 工具应该拥有最小必要权限。
在 UE 桥接层,建议在代码里维护一个“允许执行的操作白名单”。不要把所有请求都转发给unreal,而是只开放你验证过的低风险指令。例如:查询类操作默认放行,删除资产、批量修改属性必须加二次确认参数。
另外,本地 HTTP 服务必须绑定127.0.0.1,不要绑定0.0.0.0。如果你在公网服务器上跑 UE 编辑器,还要在防火墙层面限制入站规则。建议给桥接请求增加一个 Token 头,避免局域网内其他进程伪造请求。
7.2 工具粒度设计
工具并不是越细越好。太细的工具会让 AI 需要多次调用才能完成一件事,增加错误概率;太粗的工具又会让 AI 在一次调用里执行太多操作,风险难以控制。
比较合理的设计是:
- 查询类工具粒度可以偏细:例如
get_selected_actor_info、get_level_actor_count、get_material_list。 - 操作类工具粒度要偏粗且语义明确:例如
duplicate_selected_actors、set_actors_visibility,一次只做一类操作。 - 危险操作单独归类:例如
delete_asset,不仅要在描述里强调风险,还要在参数里强制传入confirm: true。
7.3 日志与调试
MCP Server 运行在独立进程里,UE 桥接运行在编辑器进程里,两者日志分散,必须统一管理。
建议在 MCP Server 侧每次收到tools/call时,打印完整的工具名和参数;在 UE 桥接侧打印收到的action和响应耗时。这样即使 AI 表现奇怪,也能通过日志判断是模型决策错了、协议传参错了,还是 UE 执行失败了。
7.4 会话控制与超时
MCP Server 的urllib.request.urlopen需要设置timeout,否则 UE 桥接服务卡死会导致 AI 客户端长时间无响应。示例里用了 3 秒超时,实际项目中建议根据操作类型区分:
- 查询类操作:2 到 3 秒。
- 资产生成类操作:根据项目规模设置 10 到 30 秒。
- 涉及构建、导入大资产的操作:不要用 HTTP 同步调用,而是先触发异步任务,再轮询任务状态。
7.5 性能与稳定性建议
如果查询的关卡特别大,get_all_level_actors()返回的 Actor 列表会很长。不要直接把几万个 Actor 信息塞给 MCP 工具,那会让 AI 的上下文迅速爆掉。建议工具返回统计信息和摘要,细节信息按需查询。
例如:
- 返回
actor_count、visible_actor_count、selected_actor_count。 - 只返回前 50 个 Actor 的名称和类型。
- 提供
get_actor_details(actor_name)来查单个对象详情。
这样既能让 AI 了解全局,又不会因为上下文过长而忽略关键信息。
8. 总结与后续学习路线
本文从 MCP 的协议概念讲起,分析了它在虚幻引擎中的集成架构,然后通过一个可运行的 Demo 把整条链路打通:AI 客户端 -> MCP Server -> UE 本地桥接 ->unrealPython API -> 关卡 Actor 数据。整个过程中,你既看到了 MCP 最核心的tools/list和tools/call,也看到了 UE 侧暴露真实能力的封装方式。
跑通这个 Demo 之后,下一步可以尝试的方向有三个:
- 扩展查询类工具:把选中 Actor 信息、地形大小、关卡内资产列表都封装成 MCP 工具,让 AI 更了解你的项目。
- 加入低风险操作类工具:例如批量设置 Actor 可见性、批量调整缩放、自动命名选中对象,先在小关卡里验证稳定性。
- 搭建你自己的 AI 编辑器助手:把 MCP Server 接入自研客户端,与团队内部的资产规范、命名规则结合,形成一套自动检查工具。
需要特别提醒的是:版本差异是这个领域最常见的坑。MCP SDK 更新很快,UE 的 Python API 也在变化,如果你在照着本文操作时遇到接口不存在或行为不一致的问题,优先去查自己当前版本的官方文档,而不是怀疑思路错了。协议本身是稳定的,学会看协议日志和排查链路,比死记某个版本 API 有用得多。
如果你按本文把 Demo 跑通了,建议先在自己的测试项目里把get_level_actor_count和print_to_ue_log玩熟,再逐步加入更有风险的操作。保留一份备份项目,会让后面的探索从容很多。