Special Topic · Inside DeepSeek Harness

MCP & Extensions: Two Paths to External Tools

How bridging the ecosystem standard and native extensions divide the work

THE QUESTION THIS PAGE ANSWERS

ANSWER FIRST

What is the key idea behind “MCP & Extensions: Two Paths to External Tools”?

How bridging the ecosystem standard and native extensions divide the work

DECISION RULE

Make the claim earn its place. Use this page as a decision aid, not a definition to memorize. Connect the idea to one real task, one observable result, and one failure that would change your mind.

TRY NEXT

Write one question you could answer with evidence after trying this idea.

WATCH FOR

A conclusion that sounds complete but leaves the key assumption untested.

Course goalAfter reading, you can state three things clearly: DSH has two paths to external capability — the MCP bridge connects ready-made tool servers in the protocol ecosystem, while Extensions let the model write and run plugins live inside the harness; why the MCP bridge deliberately bridges only tools, how tool names use a hash to avoid collisions, and what happens to tools in the model’s hands when a server disconnects; and where the two trust models differ — one keeps risk outside the process, the other relies on approval and a sandbox.
Interactive demo · Integration approach comparison board

Play first, then we explain. The same external capability — “check the weather” — wires in on the left via the MCP bridge and on the right via a native Extension, both at once. Watch three things: how tool names are generated, what the model sees when the server disconnects, and how far the two capability surfaces differ. Hit “Play” to run through automatically, or “Step” frame by frame.

Path A · MCP bridge (external process)generation G1
Outside world
weather server (not started yet)
Raw tool name get_forecast(only appears on the wire)
ctx.tools registry inside the harness
Public name mcp__weather__get_forecast
Tools Events Services UI
Path B · Native Extension (in-process)
Model's action
Calls cordis_define, submits plugin source
Waiting for user approval: allow this plugin to run?
The two running halves
Host half: logic runs in the node:vm sandbox
Browser half: renders a weather panel in the page
Tools Events Services UI
Hit “Play” to see the same capability wired into the harness via both paths.
How it works · Path A: MCP bridge, plugging in someone else’s server

First, the terms. MCP (Model Context Protocol) is an open protocol: anyone can write a tool server, and any MCP-capable client can connect and use its tools. DSH’s dsh-mcp-client plugin is that protocol’s client — one plugin instance per server, supporting both stdio subprocess and streamable-http transports. Once connected, what it does is straightforward: listTools() pulls the tool list, registers each under a public name into ctx.tools, and from then on the model uses them as native tools.

Naming is the first design point. Every MCP tool has two names: the raw name appears only on the wire (tools/call uses it); the public name the model sees is mcp__serverName__rawName. That format matches Claude Code and Codex — the mcp-client README says so itself. Names must satisfy DeepSeek’s function-name rules: at most 64 characters, letters/digits/underscore/hyphen only. If character replacement or truncation changes the name, a 12-hex-digit SHA-256 hash is appended so two distinct tool identities never collapse into one name. The whole function is pure over (serverName, rawName): connection order, re-sync, or other servers cannot rename a tool.

packages/mcp/mcp-client/src/tools.tslines 96–102
export function publicToolName(serverName: string, rawName: string): string {
  const joined = `mcp__${serverName}__${rawName}`
  const normalized = joined.replace(INVALID_NAME_CHARS, '_')
  if (normalized === joined && normalized.length <= MAX_PUBLIC_NAME_LENGTH) return normalized
  const hash = createHash('sha256').update(`${serverName}\0${rawName}`).digest('hex').slice(0, HASH_LENGTH)
  return `${normalized.slice(0, MAX_PUBLIC_NAME_LENGTH - HASH_LENGTH - 1)}_${hash}`
}
Source snapshot note: Based on the local deepseek-harness-master repo; verified against packages/mcp/mcp-client/src/tools.ts, verified on 2026-08-13. Code blocks keep the original source text.

The second design point is generation. A server’s tool list can change, and when it does you re-sync. Sync has two phases: first pull and build the full next-generation tool definitions — any failure leaves the registry untouched, so the previous generation stays as-is; only after that succeeds do you swap — unregister the old generation, then register the new.

The swap phase is worth a close look. In the registration loop, every successful register stores its unregister function in a table. If any registration throws a conflict (meaning some foreign registration has seized this server’s namespace), the catch branch unregisters everything already in that table — not a single tool left — then logs an error. The comment states the intent plainly: rollback so the model sees either a complete generation or nothing at all — never a half set.

Source: the register-and-rollback branch at packages/mcp/mcp-client/src/tools.ts lines 159–172, verified on 2026-08-13.

Reconnect-after-disconnect is also built on generations. When a stdio subprocess crashes, the supervisor restarts it with exponential backoff: first delay defaults to 500 ms, doubles each time, caps at 30 s, at most 10 attempts per outage (README.zh.md config table). During the outage the last healthy generation stays registered — calls fail, but tool names don’t vanish; after a successful reconnect, rediscovery replaces the old generation wholesale, so tools neither duplicate nor leak. If serverName is unchanged, the new generation’s names match character for character, so KV-cache prefixes survive. Budget matters too: if a connection lives past 30 s, the attempt budget resets — so an occasionally crashing server can recover forever, while a crash-looping one eventually exhausts the budget and gets unregistered instead of restarting forever.

The last design point is easiest to miss: this bridge deliberately bridges only MCP’s tools capability. The protocol also has resources and prompts (prompt templates); DSH wires up neither. The README’s “Known limitations and deferred items” section is frank:

“Only bridge MCP tools: resources and prompts have no harness consumer interface, deferred.” Source: packages/mcp/mcp-client/README.zh.md line 111, verified on 2026-08-13

The logic is easy to reconstruct: nothing inside the harness consumes an external resource or external prompt, so building those bridge piers first would be pointless. Tools have a clear consumer (the agent loop’s tool calls), so tools get bridged first. That’s bridging on demand. Non-text results like images and audio also get a lossy projection — placeholders in model context; binary payloads stay out.

How it works · Path B: Extensions, letting the model grow its own plugins

The second path is entirely different. Cordis is DSH’s plugin framework; the whole harness is a Cordis plugin tree. The Extensions subsystem lets the model write a Cordis plugin in-session and run it on the spot: before coding, cordis_inspect queries which services and interfaces the current runtime exposes; then cordis_define submits source, cordis_run starts it, and when done cordis_stop or cordis_undefine. These five tools are registered by packages/extensions/tool-cordis.

A dynamic plugin has two halves. The Host half runs logic in a Node-side node:vm sandbox; the Browser half renders UI in the page; both lifecycles are owned by ctx.dynamicCordisRunner (from packages/extensions/cordis-host-runner/src/index.ts line 124 on). Starts that include a Browser half need approval: the cordis/request-run event sends the request to the page; only after the user allows does it continue, and they can also check “approve future versions” of this plugin (runHostHalf’s approveFutureVersions). Each Package version is immutable — editing code means appending a new version.

Side by side, the two paths are orthogonal — each owns one end. The MCP bridge faces ready-made capability outside the process; its trust model is isolation: crashes, garbage returns, and disconnects are kept outside the bridge by generations and error paths — but all it can give the model is tools. Extensions face model-generated code running in-process, with a much larger surface: add tools, emit events, register services, draw UI — at the cost of approval and sandbox on every run. One plugs into outside power; the other generates its own.

Names are a pure function

The public name is decided only by (serverName, rawName). Two servers each exposing a tool called search coexist in their own namespaces; connection order and re-sync never rename tools.

Generations are all-or-nothing

A failed pull leaves the registry untouched; a registration conflict rolls back the whole generation. The model always sees a complete tool set — never a half set. During disconnect the old generation stays registered: calls fail, but names remain.

The bridge bridges only tools

resources and prompts are deliberately deferred — the harness has no consumer interface for them. The capability gap is filled by Extensions: tools, events, services, and UI can all be added.

Side-by-side · How three products wire external capability

Claude Code: a full-spec MCP client

The restored-source MCP implementation is much thicker than DSH’s: six transports (stdio, sse, sse-ide, http, ws, sdk — see restored-src/src/services/mcp/types.ts lines 23–26), seven config-source layers (local, user, project, dynamic, enterprise, claudeai, managed), OAuth plus a 15-minute cache. Tool naming matches DSH’s shape, mcp__server__tool, with permission rules down to tool or server. One defense DSH lacks: tool descriptions truncated to 2048 characters, after observing OpenAPI-generated servers stuffing 15–60KB of docs into descriptions (comment at services/mcp/client.ts lines 217–219). Source: claude-code-sourcemap-main/study/chapters/08-mcp.md.

The difference is orientation. Claude Code treats MCP as the sole official extension point and goes deep and wide; DSH keeps the MCP bridge thin (tools only) and leaves heavy capability to native Extensions. The former’s extensions run out-of-process; the latter adds an in-process path.

Grok Build: the plugin-marketplace route

In the Grok Build repo, an MCP client (crates/codegen/xai-grok-mcp/) and a plugin marketplace (crates/codegen/xai-grok-plugin-marketplace/) coexist: MCP for protocol compatibility, the marketplace for distribution and trust — a centrally reviewed ecosystem route. Its MCP connect/discover/recover mechanics were already line-checked in the on-site Grok series — see MCP connect, discover & recover; marketplace discovery and trust is in Plugin Marketplace discovery & trust. We won’t repeat that here.

Put all three together and the spectrum appears: Grok centralizes trust in a marketplace; Claude Code spreads trust across seven config layers and permission rules; DSH splits the two paths, each with its own trust model — isolation outside the bridge, approval inside.

Classroom Exercise
01

Walk through a full disconnect-and-reconnect timeline

The weather server crashes right after the model gets the tool list; 8 seconds later the supervisor brings it back, and this time the list includes an extra get_alerts. Walk the timeline in order: what’s in the registry at the crash instant? What does the model get calling mcp__weather__get_forecast during the outage? After reconnect succeeds, what operations hit the registry, and does get_forecast’s public name change? Then: if two different servers weather and weather2 both expose get_forecast, do they collide, and why? (Hint: generation swap; names are a pure function of (serverName, rawName).)

Takeaway: The MCP bridge wires someone else’s capability; Extensions extend your own runtime — orthogonal paths, each with its own trust model. Bridging only tools is deliberate: no consumer, no bridge pier. Tool names are a pure function of (serverName, rawName); generation swap guarantees the model’s tool set is either complete or empty — never an in-between state.

The handoffs inside “Interactive demo · Integration approach comparison board”

“Play first, then we explain.” shows that an Agent is not defined by the model alone. Each handoff between model, context, tools, state, permissions, and people affects both progress and recovery.

Write the state before adding capability

Starting from “First, the terms.”, split the workflow into starting state, next action, tool result, state update, and stop condition. Debugging then means finding the first lost piece of information or authority instead of saying vaguely that the model “got worse”.

A happy path is not reliability

Use “The weather server crashes right after the model gets the tool list;” to replay one successful and one failed run. Record the context, tool result, and owner at each turn; the workflow is maintainable when a second person can follow it without the original builder.

From “Interactive demo · Integration approach comparison board” to “How it works · Path A: MCP bridge, plugging in someone else’s server”

“Interactive demo · Integration approach comparison board” grounds the problem in “Play first, then we explain. The same external capability — “check the weather” — wires in on the left via the MCP bridge and on the right via a native Extension, both at once. Watch three things: how tool name…”. “How it works · Path A: MCP bridge, plugging in someone else’s server” then moves it toward “First, the terms. MCP (Model Context Protocol) is an open protocol: anyone can write a tool server, and any MCP-capable client can connect and use its tools. DSH’s dsh-mcp-client plugin is that protocol’s clien…”. Together, they show that the lesson is not just a conclusion to remember, but a claim with conditions.

Carry the judgment into the next situation

When analyzing an Agent, trace state, action, tool result, and next step in order. Each handoff should explain where information came from, who confirmed it, and where failure stops.

  • “Interactive demo · Integration approach comparison board”: Play first, then we explain. The same external capability — “check the weather” — wires in on the left via the MCP bridge and on the right via a native Extension, both at once. Watch three things: how tool name…
  • “How it works · Path A: MCP bridge, plugging in someone else’s server”: First, the terms. MCP (Model Context Protocol) is an open protocol: anyone can write a tool server, and any MCP-capable client can connect and use its tools. DSH’s dsh-mcp-client plugin is that protocol’s clien…
  • “The closing point”: The logic is easy to reconstruct: nothing inside the harness consumes an external resource or external prompt, so building those bridge piers first would be pointless. Tools have a clear consumer (the agent loo…

The final “The closing point” brings the discussion to “The logic is easy to reconstruct: nothing inside the harness consumes an external resource or external prompt, so building those bridge piers first would be pointless. Tools have a clear consumer (the agent loo…”. The useful thing to carry forward is knowing which judgments must be revisited when input, scale, or risk changes.

Mark as learned Your reading progress updates automatically
← PreviousNext →

Keep reading

The next useful article in the thread.

ARTICLE DISCUSSION

Leave one useful thought here.

Keep the idea that clicked, the question that stayed open, or a small note for the next learner.

Discussing MCP & Extensions: Two Paths to External Tools Inside DeepSeek Harness
3discussionsArticle discussion · synced with the Circle
View in the learning circle
AM
Asha MorganContent editor
INSIGHTField note

I turned one judgment from this article into a small experiment I could run today. Knowing what to observe next is more useful than simply remembering the conclusion.

ARTICLE DISCUSSION7 helpful
LH
Lin HarperIndie developer
INSIGHTInsight

After reading this, I first looked for the conditions behind the idea instead of copying the method into a project. That order made the later trade-offs much clearer.

ARTICLE DISCUSSION5 helpful
KM
Kiki MooreProduct operations
QUESTIONQuestion

When this judgment reaches real work, which constraint should be added first? I am curious which step matters most between reading and the first practical attempt.

ARTICLE DISCUSSION4 helpful