SDK runtime: dsh-mcp-client missing from the runtime closure + no plugins-ready barrier before session/new #2273
Replies: 2 comments 1 reply
|
Shipped finding 1.
Finding 2 (session/new outrunning |
|
Finding 2 (the boot race) is the one I can add something real to — we solved exactly that problem, and the fix is not a sleep. Use the awaited waterfalls as the barrierDSH has two waterfalls that the agent loop awaits before the first model call: That is the shape we use: mounting is driven from But there is a trap that cost us a debugging round, and it will bite you too:
So gating alone is not sufficient — a tool registered while your gate is holding is in That detail is why "it works if I sleep" is misleading: the sleep isn't fixing ordering, it's making the registration land before the snapshot is taken. Two things worth adding to your report:
Finding 1 — I have nothing usefulThe obvious suggestion would be "use a different MCP package instead". I don't think that works for your setup: the SDK runtime closure is a fixed workspace package set, so a third-party MCP package would not be in it either, for the same reason We do not modify the SDK runtime or Disclosure: I maintain pi2dsh; the waterfall-gating pattern above is what we do internally and is pinned by our contract tests — you don't need our package to use it, it's the host's own seams. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Note: after posting I found prior reports covering each piece — #1240 / #2115 (runtime closure missing dsh-mcp-client), #1239 (boot race), #1241 (no stderr diagnostics, which is why the race is silent). Please upvote those; this thread stands as an end-to-end corroboration of the three interacting in one verified setup.
Two related findings from embedding the harness via the Python SDK (deepseek-harness-sdk, node-mode runtime) with a custom Cordis composition. Sharing here since external PRs are closed; both have small fixes.
1. The SDK runtime closure omits @deepseek-ai/dsh-mcp-client
python/sdk-runtime/package.json defines the plugin set available to custom compositions, but dsh-mcp-client is not in it — so a composition that mounts an external MCP server (arguably the most common reason to write a custom composition) fails to load on the shipped runtime, and embedders must rebuild from source. The fix is the one-line mechanism the sdk-runtime README itself documents:
added to the dependencies block. verify-runtime-closure passes with it (closed graph, 110 workspace packages), and I've exercised the result end to end: dsh-llm-pi-ai (custom provider route) + dsh-mcp-client (stdio server exposing ~96 tools) + dsh-tool-fs, driven via the Python SDK, with tools discovered, registered, and called by the model.
2. session/new can outrun MCP tool sync, silently
Calling harness.run() immediately after construction creates the session before the MCP client finishes listTools() + registration. The agent then runs its entire session without any MCP tools (the request/header session event shows only fs/todo tools). Sleeping ~5s between client.start() and the first run() reliably makes the tools appear. The mcp-client README's "registers before the composition starts its first turn" holds for the plugin fiber, but nothing makes the JSON-RPC server's session/new wait on it.
Compounding factor: the failure is silent — the jsonrpc composition mounts no logger (stdout is protocol-pure by design), so the registration-failure ctx.logger.error paths emit nothing observable. An embedder sees a healthy-looking session that simply lacks tools.
Suggestions: (a) delay session/new (or the first session/prompt) until initial plugin activation settles, or expose a readiness signal in the initialize handshake; (b) ship a minimal stderr logger in the default/jsonrpc compositions.
Repro details: macOS arm64, Node 25, runtime in node mode, master as of 2026-08-13. Happy to provide the full composition and a repro script.
All reactions