Repository navigation
Conversation
parseFrames() understood Content-Length framing only, while both of its peers speak newline-delimited JSON: the host (dsh-mcp-client via the MCP SDK StdioClientTransport, whose serializeMessage() appends a newline) and the cloudbase-mcp child. The same function parses process.stdin (host -> proxy) and child.stdout (child -> proxy), so the omission stalled the initialize handshake on both legs: the proxy never replied, the SDK request timed out after 60s, and no mcp__cloudbase__* tool was ever registered. parseMcpFrames() in src/server/mcp-client.ts already carries this fallback (lines 73-84); the standalone proxy script never got it. Copy that logic verbatim. The Content-Length path is untouched. tests/proxy-stdio-framing.test.ts covers the fallback, keeps the proxy and the in-process bridge in sync, and drives the real proxy process end to end against a newline-speaking stub child, using the existing CLOUDBASE_MCP_COMMAND injection point so no network or npx cache is needed.
binggg
left a comment
There was a problem hiding this comment.
Verified locally — approving.
- Root cause confirmed:
parseFrames()indsh-plugin/scripts/mcp-env-proxy.mjsunderstood Content-Length framing only, while both peers speak newline-delimited JSON. The in-process bridge (parseMcpFrames()insrc/server/mcp-client.ts, lines 73–84) already carries the newline fallback; this copies it verbatim. - Both inbound legs use the same parser: host → proxy (MCP SDK
StdioClientTransportserializes with a trailing\n) and child → proxy (cloudbase-mcpreplies with bare JSON lines). The omission stalled the initialize handshake on both. - Outbound (Content-Length replies) is unaffected: SDK client/server
processReadBuffer()catches the per-line parse error, reports viaonerror, and keeps reading — real messages still get through. - Tests: ran the new suite plus the three neighbors locally —
proxy-stdio-framing4/4,mcp-bridge+patch-contract+patch-js-path13/13, no regressions.
Two nits, not blocking:
- Tests 1–2 assert on source text (
indexOf(0x0a)), so renames/reformatting would false-fail. Fine as a drift guard; feel free to leave as-is. - After merge,
@cloudbase/dsh-pluginneeds a version bump past 0.1.2 for the npm release so users actually pick this up.
|
A follow-up on this one: the fix shipped, and then the thing it repaired went away.
So this change went out in 中文摘要:这个修复随 |
What breaks
mcp-env-proxy.mjsparses stdio withparseFrames(), which understands Content-Length framing only:Both of its peers speak newline-delimited JSON, which is the framing the official MCP stdio spec uses:
dsh-mcp-clientuses the MCP SDKStdioClientTransport, whoseserializeMessage()isJSON.stringify(message) + "\n";@cloudbase/cloudbase-mcpreplies with a bare JSON line.The same
parseFrames()runs onprocess.stdin(host → proxy) and onchild.stdout(child → proxy), so the omission breaks both legs.Symptom
The host's
initializeis never parsed, so the proxy never replies. The SDK request times out after 60s andmcp__cloudbase__*tools are never registered — the plugin looks installed and configured (its patch composes, its system-prompt section is present) but no CloudBase tool ever reaches the model.Measured against
@cloudbase/dsh-plugin@0.1.2as published on npm, driving the proxy with the same MCP SDK clientdsh-mcp-clientuses:client.connect()tools/listMcpError -32001)The fix
parseMcpFrames()insrc/server/mcp-client.ts— the in-process bridge in this same package — already carries this fallback (lines 73–84). The standalone proxy script never got it. This change copies that logic verbatim intoparseFrames():The Content-Length path is untouched, so nothing that works today regresses.
Tests
tests/proxy-stdio-framing.test.tsadds four cases:parseMcpFramesdecode the same framing;initializeagainst a stub child that speaks newline-delimited JSON;tools/listthe same way.The stub child uses the proxy's existing
CLOUDBASE_MCP_COMMAND/CLOUDBASE_MCP_ARGSinjection points, so the test needs no network and no npx cache.Red/green, run locally:
mainproxy-stdio-framing.test.tsmcp-bridge.test.tspatch-contract.test.tspatch-js-path.test.tsnpm testpasses for the touched suites (17 passed across the four files above)中文摘要
mcp-env-proxy.mjs的parseFrames()只认 Content-Length 分帧,而宿主(dsh-mcp-client经 MCP SDKStdioClientTransport,其serializeMessage()追加的是换行)和子进程(cloudbase-mcp回的是裸 JSON 行)说的都是换行分帧。同一个函数同时解析process.stdin和child.stdout,所以两个方向都被卡住:initialize永远解析不出来 → SDK 请求 60 秒超时 →mcp__cloudbase__*一个工具都不注册。同包内的
src/server/mcp-client.ts的parseMcpFrames()一直都有这段回退(73–84 行),是独立脚本mcp-env-proxy.mjs漏了。本次按原样补齐,Content-Length 老路径不动。已实测(npm 上发布的 0.1.2 版本、用
dsh-mcp-client同款 SDK 客户端驱动):修复前connect()60.0 秒超时;修复后 0.38 秒连上并返回 40 个工具。