Summary
When using mcp-unity from Codex CLI project-local config, simple read-only tool calls such as get_scene_info time out. Unity accepts WebSocket connections, and direct raw WebSocket requests can return successfully, but MCP stdio tool calls through the Node server time out after 60 seconds.
This appears related to the known Codex/multiple-connection and timeout cascade issues, but it still reproduces on latest main commit cce8b57de9cb69633deb222c9162dad539a52b87.
Environment
- Unity:
6000.3.8f1
- OS: macOS / Apple Silicon
- Node.js:
v22.22.0
- npm:
10.9.4
- mcp-unity install method: Unity Package Manager Git URL
- mcp-unity package URL:
https://github.com/CoderGamester/mcp-unity.git
- Resolved commit:
cce8b57de9cb69633deb222c9162dad539a52b87
- mcp-unity version in
server.json: 1.3.0
- MCP client: Codex CLI project-local
.codex/config.toml
- Unity MCP settings:
{
"Port": 8090,
"RequestTimeoutSeconds": 60,
"AutoStartServer": true,
"EnableInfoLogs": false,
"NpmExecutablePath": "",
"AllowRemoteConnections": false
}
Project-local Codex config:
[mcp_servers.mcp-unity]
command = "node"
args = ["Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/build/index.js"]
Reproduction Steps
- Install
mcp-unity via Unity Package Manager using:
https://github.com/CoderGamester/mcp-unity.git
- Open Unity and start the MCP Unity server on port
8090.
- Confirm Unity logs:
[MCP Unity] WebSocket server started successfully on localhost:8090.
- Configure Codex CLI project-local MCP config:
[mcp_servers.mcp-unity]
command = "node"
args = ["Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/build/index.js"]
- Restart Codex from the project root.
- Call
get_scene_info through the MCP client.
Actual Result
Codex reports:
When reproduced with a standalone MCP SDK client against the same stdio server, the result is also a timeout:
McpError: MCP error -32001: Request timed out
at Timeout.timeoutHandler (.../@modelcontextprotocol/sdk/dist/esm/shared/protocol.js:282:49)
code: -32001,
data: { timeout: 60000 }
lsof -nP -iTCP:8090 shows multiple Node bridge clients connected to Unity during/after attempts:
node ... TCP [::1]:63010->[::1]:8090 (ESTABLISHED)
node ... TCP [::1]:63064->[::1]:8090 (ESTABLISHED)
Unity ... TCP [::1]:8090 (LISTEN)
Unity logs show WebSocket clients connecting, sometimes the request arriving and a response being produced, but the MCP client still times out:
[MCP Unity] WebSocket client connected (... Name: Unknown MCP Client ...)
[MCP Unity] WebSocket message received: {"method":"get_scene_info","params":{},"id":"..."}
[MCP Unity] Retrieved scene info for active scene 'SampleScene'
[MCP Unity] WebSocket message response for request ID '...': {"id":"...","result":{"success":true,...}}
In other clean MCP SDK runs, the Node server log shows the tool call timing out even though the WebSocket connection was established:
[INFO] [Unity] WebSocket connected to Unity
[INFO] [Unity] Successfully connected to Unity WebSocket
[INFO] [Tools] Executing tool: get_scene_info
{}
[ERROR] [Unity] Request ... timed out after 60000ms
[ERROR] [Tools] Tool execution failed: get_scene_info
{
"type": "timeout_error",
"message": "Request timed out"
}
Unity also logs this after clients time out or disconnect:
[MCP Unity] WebSocket error: An error has occurred in sending data.
WebSocketSharp.WebSocketException: The header of a frame cannot be read from the stream.
Expected Result
get_scene_info should return promptly through the MCP stdio server, matching the direct raw WebSocket behavior.
Expected response shape:
{
"activeScene": {
"name": "SampleScene",
"path": "Assets/Scenes/SampleScene.unity",
"isDirty": false,
"isLoaded": true,
"rootCount": 2
}
}
Direct WebSocket Control Test
A direct raw WebSocket request to Unity can succeed:
node -e "import WebSocket from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/ws/wrapper.mjs'; const ws=new WebSocket('ws://localhost:8090/McpUnity',{headers:{'X-Client-Name':'direct-long-scene-test'},origin:'direct-long-scene-test'}); const t=setTimeout(()=>{console.error('timeout'); ws.close(); process.exit(2)},65000); ws.on('open',()=>{console.log('open'); ws.send(JSON.stringify({id:'direct-long-scene-1',method:'get_scene_info',params:{}}));}); ws.on('message',d=>{clearTimeout(t); console.log(d.toString()); setTimeout(()=>{ws.close(); process.exit(0)},500);}); ws.on('error',e=>{clearTimeout(t); console.error('error',e.message || e.code || e); process.exit(1);});"
This returned successfully:
{"id":"direct-long-scene-1","result":{"success":true,"type":"text","message":"Active scene: 'SampleScene'","activeScene":{"name":"SampleScene","path":"Assets/Scenes/SampleScene.unity","buildIndex":0,"isDirty":false,"isLoaded":true,"rootCount":2},"loadedSceneCount":1,"loadedScenes":[{"name":"SampleScene","path":"Assets/Scenes/SampleScene.unity","buildIndex":0,"isLoaded":true,"isDirty":false,"rootCount":2,"isActive":true}]}}
This suggests Unity's editor-side tool implementation can work, while the stdio MCP bridge lifecycle/request handling still fails.
Standalone MCP SDK Repro
This reproduces outside Codex using the MCP SDK directly:
LOGGING_FILE=true node --input-type=module -e "import { Client } from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js'; import { StdioClientTransport } from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js'; const client = new Client({name:'manual-mcp-client', version:'1.0.0'}, {capabilities:{}}); const transport = new StdioClientTransport({command:'node', args:['Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/build/index.js'], cwd:process.cwd(), env:{...process.env, LOGGING_FILE:'true'}}); await client.connect(transport); console.error('connected'); const result = await client.callTool({name:'get_scene_info', arguments:{}}); console.log(JSON.stringify(result,null,2)); await client.close();"
It connects, then times out after 60 seconds.
Related Existing Issues
Notes
The issue still reproduces on main after fixes for #110/#119 appear to have landed. It may be a remaining edge case around Codex/MCP SDK stdio startup, multiple concurrent bridge processes, or the WebSocket request/response matching path in mcpUnity.sendRequestInternal.
No local source patches are required to reproduce; avoid relying on edits under Library/PackageCache because Unity can regenerate that directory.
Summary
When using
mcp-unityfrom Codex CLI project-local config, simple read-only tool calls such asget_scene_infotime out. Unity accepts WebSocket connections, and direct raw WebSocket requests can return successfully, but MCP stdio tool calls through the Node server time out after 60 seconds.This appears related to the known Codex/multiple-connection and timeout cascade issues, but it still reproduces on latest
maincommitcce8b57de9cb69633deb222c9162dad539a52b87.Environment
6000.3.8f1v22.22.010.9.4https://github.com/CoderGamester/mcp-unity.gitcce8b57de9cb69633deb222c9162dad539a52b87server.json:1.3.0.codex/config.toml{ "Port": 8090, "RequestTimeoutSeconds": 60, "AutoStartServer": true, "EnableInfoLogs": false, "NpmExecutablePath": "", "AllowRemoteConnections": false }Project-local Codex config:
Reproduction Steps
mcp-unityvia Unity Package Manager using:8090.get_scene_infothrough the MCP client.Actual Result
Codex reports:
When reproduced with a standalone MCP SDK client against the same stdio server, the result is also a timeout:
lsof -nP -iTCP:8090shows multiple Node bridge clients connected to Unity during/after attempts:Unity logs show WebSocket clients connecting, sometimes the request arriving and a response being produced, but the MCP client still times out:
In other clean MCP SDK runs, the Node server log shows the tool call timing out even though the WebSocket connection was established:
Unity also logs this after clients time out or disconnect:
Expected Result
get_scene_infoshould return promptly through the MCP stdio server, matching the direct raw WebSocket behavior.Expected response shape:
{ "activeScene": { "name": "SampleScene", "path": "Assets/Scenes/SampleScene.unity", "isDirty": false, "isLoaded": true, "rootCount": 2 } }Direct WebSocket Control Test
A direct raw WebSocket request to Unity can succeed:
node -e "import WebSocket from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/ws/wrapper.mjs'; const ws=new WebSocket('ws://localhost:8090/McpUnity',{headers:{'X-Client-Name':'direct-long-scene-test'},origin:'direct-long-scene-test'}); const t=setTimeout(()=>{console.error('timeout'); ws.close(); process.exit(2)},65000); ws.on('open',()=>{console.log('open'); ws.send(JSON.stringify({id:'direct-long-scene-1',method:'get_scene_info',params:{}}));}); ws.on('message',d=>{clearTimeout(t); console.log(d.toString()); setTimeout(()=>{ws.close(); process.exit(0)},500);}); ws.on('error',e=>{clearTimeout(t); console.error('error',e.message || e.code || e); process.exit(1);});"This returned successfully:
{"id":"direct-long-scene-1","result":{"success":true,"type":"text","message":"Active scene: 'SampleScene'","activeScene":{"name":"SampleScene","path":"Assets/Scenes/SampleScene.unity","buildIndex":0,"isDirty":false,"isLoaded":true,"rootCount":2},"loadedSceneCount":1,"loadedScenes":[{"name":"SampleScene","path":"Assets/Scenes/SampleScene.unity","buildIndex":0,"isLoaded":true,"isDirty":false,"rootCount":2,"isActive":true}]}}This suggests Unity's editor-side tool implementation can work, while the stdio MCP bridge lifecycle/request handling still fails.
Standalone MCP SDK Repro
This reproduces outside Codex using the MCP SDK directly:
LOGGING_FILE=true node --input-type=module -e "import { Client } from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/@modelcontextprotocol/sdk/dist/esm/client/index.js'; import { StdioClientTransport } from './Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/node_modules/@modelcontextprotocol/sdk/dist/esm/client/stdio.js'; const client = new Client({name:'manual-mcp-client', version:'1.0.0'}, {capabilities:{}}); const transport = new StdioClientTransport({command:'node', args:['Library/PackageCache/com.gamelovers.mcp-unity@cce8b57de9cb/Server~/build/index.js'], cwd:process.cwd(), env:{...process.env, LOGGING_FILE:'true'}}); await client.connect(transport); console.error('connected'); const result = await client.callTool({name:'get_scene_info', arguments:{}}); console.log(JSON.stringify(result,null,2)); await client.close();"It connects, then times out after 60 seconds.
Related Existing Issues
Notes
The issue still reproduces on
mainafter fixes for #110/#119 appear to have landed. It may be a remaining edge case around Codex/MCP SDK stdio startup, multiple concurrent bridge processes, or the WebSocket request/response matching path inmcpUnity.sendRequestInternal.No local source patches are required to reproduce; avoid relying on edits under
Library/PackageCachebecause Unity can regenerate that directory.