原理
我們先來看看一般要讓 AI 可以操控 Unity 編輯器的 MCP 原理的實現方式:

其實就是透過在 Unity 中建立一個持續監聽的伺服器
然後再准備一個可以跟 AI 互相溝通的橋接器
進行各種 Function 的呼叫操作
根據這個核心原理
我們需要在遊戲中創建一個本地端的伺服器
然後讓 Python 調用裡面的代碼
AI 再調用到這個 Python 的代碼去查看
我們的遊戲裡面都有什麼工具可以讓 MCP 使用
準備工作
為了不要把整個專案弄得太複雜
我們只需要兩個簡單的代碼來驗證邏輯:
- simpleMCP.cs // 用來開啟伺服器, 和定義遊戲裡可以執行的方法
- simple_mcp_bridge.py // 讓 AI MCP 可以執行的 Python 橋接器
完整的專案源代碼放在 Github : https://github.com/yayapipi/InGameMCP
simpleMCP.cs
主要的功能室在遊戲啟動的時候先開啟一個 Server:
1private void StartServer()2{3 try4 {5 listener = new TcpListener(IPAddress.Any, port);6 listener.Start();7 isRunning = true;8
9 serverThread = new Thread(AcceptClients);10 serverThread.IsBackground = true;11 serverThread.Start();12
13 Debug.Log($"[SimpleMCP] 伺服器已啟動在端口 {port}");14 Debug.Log("[SimpleMCP] 建議透過 MCP Bridge 連接(Cursor 將依 .cursor/mcp.json 自動啟動 Python Bridge)");15 }16 catch (Exception e)17 {18 Debug.LogError($"[SimpleMCP] 啟動失敗: {e.Message}");19 }20}接著就會不斷的監聽這個 Port 有沒有新的訊息進來,
當檢測到有人連進來的時候, 就會跟它握手
然後建立長連線 WebSocket, 開始不斷地從他那邊接受指令:
1 private void HandleClient(TcpClient client)2 {3 NetworkStream stream = client.GetStream();4 byte[] buffer = new byte[4096];5
6 try7 {8 // WebSocket 握手9 int bytesRead = stream.Read(buffer, 0, buffer.Length);10 string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);11
12 if (request.Contains("Upgrade: websocket"))13 {14 string response = PerformHandshake(request);15 byte[] responseBytes = Encoding.UTF8.GetBytes(response);16 stream.Write(responseBytes, 0, responseBytes.Length);17
18 Debug.Log("[SimpleMCP] 客戶端已連接");19
20 // 處理消息21 while (isRunning && client.Connected)22 {23 if (stream.DataAvailable)24 {25 bytesRead = stream.Read(buffer, 0, buffer.Length);26 if (bytesRead <= 0)27 {28 break; // 連線關閉29 }30 if (bytesRead > 0)31 {32 string message = DecodeFrame(buffer, bytesRead);33 if (!string.IsNullOrEmpty(message))34 {35 ProcessMessage(message, stream);36 }37 }38 }39
40 Thread.Sleep(10);41 }42 }43 }44 catch (Exception e)45 {46 Debug.LogError($"[SimpleMCP] 客戶端錯誤: {e.Message}");47 }48 finally49 {50 client.Close();51 Debug.Log("[SimpleMCP] 客戶端已斷開");52 }53 }當收到新的指令的時候, 會在 ProcessMessage/HandleRequest 裡面進行判斷
收到什麼指令, 就觸發什麼 Function, 當然這個地方也可以帶一些參數進來
執行完之後, 就把結果包成 Json 回傳回去給 AI :
1private void ProcessMessage(string message, NetworkStream stream)2 {3 lock (mainThreadActions)4 {5 mainThreadActions.Enqueue(() =>6 {7 try8 {9 Debug.Log($"[SimpleMCP] 收到消息: {message}");10
11 var request = JsonUtility.FromJson<MCPRequest>(message);12
13 if (request == null || string.IsNullOrEmpty(request.method))14 {15 Debug.LogError("[SimpleMCP] 無效的請求格式");16 SendResponse(stream, "{\"error\":\"Invalid request format\"}");17 return;18 }19
20 string response = HandleRequest(request);21 SendResponse(stream, response);22 }23 catch (Exception e)24 {25 Debug.LogError($"[SimpleMCP] 處理消息錯誤: {e.Message}\n消息內容: {message}");26 SendResponse(stream, "{\"error\":\"Internal server error\"}");27 }28 });29 }30 }31
32 // 新增的 HandleRequest 方法33 private string HandleRequest(MCPRequest request)34 {35 try36 {37 Debug.Log($"[SimpleMCP] 處理請求方法: {request.method}");38
39 switch (request.method.ToLower())40 {41 case "get_position":42 case "getposition":43 return GetPlayerPosition();44
45 case "move_player":46 case "moveplayer":47 case "set_position":48 case "setposition":49 return MovePlayer(request.x, request.y, request.z);50
51 case "ping":52 return "{\"success\":true,\"message\":\"pong\"}";53
54 case "get_player_info":55 case "getplayerinfo":56 return GetPlayerInfo();57
58 default:59 Debug.LogWarning($"[SimpleMCP] 未知的請求方法: {request.method}");60 return "{\"error\":\"Unknown method\",\"method\":\"" + request.method + "\"}";61 }62 }63 catch (Exception e)64 {65 Debug.LogError($"[SimpleMCP] HandleRequest 錯誤: {e.Message}");66 return "{\"error\":\"Request handling failed\",\"details\":\"" + e.Message + "\"}";67 }68 }現在有兩個功能:
- get_position - 取得玩家的位置
- set_position - 設定玩家的位置

代碼寫好之後,我們可以創建一個簡單的場景
把玩家 (Capsule) 放進去, 執行遊戲進行測試
看 Console 的顯示會不會正常打開 Server, 開始監聽
simple_mcp_bridge.py
接下來我們需要一個 Python 的橋接器代碼
讓 AI 可以透過這個代碼跟我們的遊戲進行溝通
一開始啟動的時候需要先安裝 Python 和 Websockets
1pip3 install websockets這個代碼一開始會先嘗試連接到 Unity WebSocket 的伺服器:
1async def connect_to_unity():2 """連接到 Unity WebSocket 伺服器"""3 global ws_connection4 5 log(f"Attempting to connect to Unity at {UNITY_URI}")6 7 max_retries = 58 retry_delay = 29 10 for attempt in range(max_retries):11 try:12 ws_connection = await asyncio.wait_for(13 websockets.connect(UNITY_URI),14 timeout=5.015 )16 log(f"✓ Connected to Unity at {UNITY_URI}")17 return True18 except asyncio.TimeoutError:19 log(f"✗ Connection timeout (attempt {attempt + 1}/{max_retries})")20 except ConnectionRefusedError:21 log(f"✗ Connection refused - Is Unity running? (attempt {attempt + 1}/{max_retries})")22 except Exception as e:23 log(f"✗ Connection error: {type(e).__name__} - {e} (attempt {attempt + 1}/{max_retries})")24 25 if attempt < max_retries - 1:26 log(f"Retrying in {retry_delay} seconds...")27 await asyncio.sleep(retry_delay)28 29 log("✗ Failed to connect to Unity after all retries")30 log("Please ensure:")31 log(" 1. Unity is running")32 log(" 2. SimpleMCP script is attached to a GameObject")33 log(" 3. The game is in Play mode")34 log(f" 4. Port {UNITY_PORT} is not blocked by firewall")收到 AI 的指令的時候就給我們的遊戲發送指令:
1async def send_unity_request(method, **kwargs):2 """發送請求到 Unity"""3 global ws_connection4 5 if ws_connection is None:6 log("WebSocket not connected, attempting to connect...")7 if not await connect_to_unity():8 return {"error": "Not connected to Unity. Is the game running?"}9 10 try:11 request = {"method": method, **kwargs}12 log(f"Sending to Unity: {json.dumps(request)}")13 14 await ws_connection.send(json.dumps(request))15 response = await asyncio.wait_for(ws_connection.recv(), timeout=5.0)16 17 log(f"Received from Unity: {response}")18 return json.loads(response)19 20 except asyncio.TimeoutError:21 log("✗ Unity request timeout")22 return {"error": "Unity request timeout"}23 except websockets.exceptions.ConnectionClosed as e:24 log(f"✗ Connection to Unity lost: {e}")25 ws_connection = None26 return {"error": "Connection to Unity lost"}27 except Exception as e:28 log(f"✗ Error sending request: {type(e).__name__} - {e}")29 return {"error": str(e)}那麼 AI 是怎麼跟這個 Python 代碼進行溝通的呢?
關鍵的代碼在 handle_mcp_request 這個方法裡
一開始的時候 AI 會先進行初始化 Initialize
這個時候要回傳這個工具的相關資訊給 AI
1# MCP 初始化握手2if method == "initialize":3 log("Handling initialize request")4 return {5 "protocolVersion": "2024-11-05",6 "capabilities": {7 "tools": {}8 },9 "serverInfo": {10 "name": "unity-game-mcp",11 "version": "1.0.0"12 }13 }接著, 我們會在 tools/list 定義可以使用的工具有哪些
像我們目前有的指令是
- get_player_position - 取得玩家的位置
- move_player - 移動玩家坐標, 然後要帶入參數進來
1elif method == "tools/list":2 return {3 "tools": [4 {5 "name": "get_player_position",6 "description": "獲取玩家在遊戲中的當前位置座標",7 "inputSchema": {8 "type": "object",9 "properties": {},10 "required": []11 }12 },13 {14 "name": "move_player",15 "description": "將玩家移動到指定的座標位置",16 "inputSchema": {17 "type": "object",18 "properties": {19 "x": {"type": "number", "description": "X 座標"},20 "y": {"type": "number", "description": "Y 座標(高度)"},21 "z": {"type": "number", "description": "Z 座標"}22 },23 "required": ["x", "y", "z"]24 }25 }26 ]27 }最後 AI 會根據 使用者的 Prompt 來決定要使用哪個工具
然後會自己調用 tools/call 這個地方
這裡會直接 send_unity_request , 發送指令到 Unity 的遊戲中
然後等待回復, Unity 回復之後, 就把它列印出來
1elif method == "tools/call":2 tool_name = params.get("name")3 arguments = params.get("arguments", {})4 5 log(f"Calling tool: {tool_name} with arguments: {arguments}")6 7 if tool_name == "get_player_position":8 result = await send_unity_request("get_position")9 if "error" in result:10 return {"error": result["error"]}11 return {12 "content": [13 {14 "type": "text",15 "text": f"玩家當前位置:\nX: {result.get('x', 0):.2f}\nY: {result.get('y', 0):.2f}\nZ: {result.get('z', 0):.2f}"16 }17 ]18 }19 20 elif tool_name == "move_player":21 x = arguments.get("x")22 y = arguments.get("y")23 z = arguments.get("z")24 25 if x is None or y is None or z is None:26 return {"error": "Missing required parameters: x, y, z"}27 28 result = await send_unity_request("move_player", x=x, y=y, z=z)29 if "error" in result:30 return {"error": result["error"]}31 32 return {33 "content": [34 {35 "type": "text",36 "text": f"✓ 玩家已移動到:\nX: {result.get('x', 0):.2f}\nY: {result.get('y', 0):.2f}\nZ: {result.get('z', 0):.2f}"37 }38 ]39 }設定 MCP Config
架設好代碼和環境之後
我們要在想要使用的AI工具上設定 MCP Config
以 Cursor 舉例:

你要到 Cursor 的 MCP.json 中加入執行這個 Python 代碼的指令
1{2 "mcpServers": {3 "unity-game-mcp": {4 "command": "python",5 "args": [6 "Assets/SimpleMCP/PythonServer/simple_mcp_bridge.py"7 ],8 "env": {9 "UNITY_HOST": "localhost",10 "UNITY_PORT": "8765"11 },12 "enabled": true13 }14 }15}Claude 或是別的AI工具也是一樣
可以到對應的 Config 文件上加上這個 MCP Config 資訊
遊戲測試:
一切都准備好之後
你可以直接在 Unity Editor 運行遊戲進行測試或是 Build 出來進行
Build 的時候 Player Setting 那邊可以把 Run In Background 打鉤
我測試過兩種方式都是可以正常運行的
測試的時候記得先運行 Unity, 再啟動 MCP 的工具:
以上就是一個簡單的 In Game MCP 效果的實現
你可以繼續延伸擴展更多的應用
如果對你有收獲的話歡迎訂閱支持 Yapi Flow 平台 :)






