Skip to main content
PathMCP

MCP Integration

MCP (Model Context Protocol) is the open standard for AI applications to connect external data sources and tools. DSH bridges it through @deepseek-ai/dsh-mcp-client: connect to an external MCP server, register its tools into ctx.tools, and the model can call them just like local tools, named mcp__<serverName>__<rawName>.

In one sentence

"One plugin instance = one MCP server," mounted in cordis.yml/patch.

Configuration

The most common is stdio: launching a local subprocess as the server.

- id: mcp-github
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: github
transport: stdio
command: npx
args: ['-y', '@modelcontextprotocol/server-github']
env:
GITHUB_TOKEN: !!js process.env.GITHUB_TOKEN

You can also connect a remote server (streamable-http):

- id: mcp-web
name: '@deepseek-ai/dsh-mcp-client'
config:
serverName: web
transport: streamable-http
url: http://localhost:3000/mcp
headers:
Authorization: !!js '`Bearer ${process.env.MCP_TOKEN}`'

Full field list:

FieldTransportRequiredEffect
transportbothyes"stdio" or "streamable-http"
serverNamebothyesTool-name namespace, [A-Za-z0-9_-]{1,32}, unique across live instances
commandstdioyesThe executable to launch
argsstdionoArguments passed to the command
envstdionoExtra environment variables, merged on top of the scrubbed host environment
cwdstdionoSubprocess working directory
urlhttpyesMCP server address
headershttpnoExtra request headers (e.g. auth token)
toolCallTimeoutMsbothnoPer-callTool timeout (default 60000)
failOnStartupErrorbothnoReject activation when initial connection/sync fails (default false)
reconnect.enabledbothnoAuto-reconnect after a drop (default true)
reconnect.initialDelayMsbothnoFirst reconnect delay, doubled on consecutive failures (default 500)
reconnect.maxDelayMsbothnoBackoff cap, also the uptime needed to reset the reconnect budget (default 30000)
reconnect.maxAttemptsbothnoConsecutive-failure cap per disconnect (default 10)

Merging tools into the registry

Once connected, external MCP tools become ordinary tools on ctx.tools. Each tool has two names: the raw name (what tools/call sends to the server) and a public name mcp__<serverName>__<rawName> (what the model sees/calls). For example, github's create_issue becomes mcp__github__create_issue. The public name normalizes to the DeepSeek function-name contract (≤64 chars, [A-Za-z0-9_-]), appending a 12-digit hex hash derived from (serverName, rawName) on renaming to prevent name collapses; the name is a pure function of (serverName, rawName), unchanged by connection order or resync.

Name conflicts are deterministic: two servers emitting the same raw name coexist within their own namespaces; two live instances with the same serverName cause the later-mounted one to fail; a server listing the same tool name twice is an invalid list; an external registration squatting the namespace rolls back the whole generation with a loud error.

Once merged, they go through the same tool pipeline (see tool execution): tools/pre-execute gating, timeouts, and result rewriting all apply, so policies like allow/deny lists uniformly govern external tools.

Connection, reconnect, and failure semantics

  • Discovery: await listTools() on activation, then ctx.tools.register() one by one before the first round; failures are logged, and only failOnStartupError: true rejects activation.
  • Hot updates: listens for notifications/tools/list_changed to resync; a failed fetch keeps the previous generation of tools, and registration conflicts roll back the attempted generation.
  • Execution: client.callTool({ name: rawName, arguments }, { signal }) with timeout and cancellation; the public name is never sent to the server; isError goes through the registry error path.
  • Drop reconnect: the supervisor restarts per the original config with exponential backoff, rerunning discovery on success; recovery replaces the previous generation without duplicating or leaking, and the last good generation stays registered during a disconnect. After maxAttempts consecutive failures for the same disconnect, tools are deregistered and reconnecting stops until an HMR reload or Host restart.

Difference from custom tools

Local toolsMCP tools
Implementationplugin ctx.tools / defineToolexternal MCP server
Namingsnake_case namesmcp__<server>__<raw>
Lifecyclein-processbridged process/remote
Bothgo through the same pipelinego through the same pipeline

When to use

  • You already have a bunch of MCP servers (filesystem, GitHub, database, in-house tools) and don't want to write a dedicated integration for each
  • You want to bring external tools under DSH's tool governance (gating/timeout/cancellation)
  • Typical: connect a GitHub server to let the model open issues / query PRs; connect a database server to expose read-only queries; connect an in-house API gateway so dozens of operations are wired in at once, all governed uniformly under tools/pre-execute

Current boundaries

  • Only tools are bridged: Resources and Prompts have no harness consumer.
  • Startup timeout inherits the MCP SDK (60-second default); an unresponsive server slows activation and cleanup; streamable HTTP failures surface per request, with unreachability being a per-call retry rather than a restart.
  • Image is the only durable rich-result bridge (rc.7): PNG/JPEG/WebP/GIF become durable core image blocks in the model context when ctx.attachments is mounted and the calling model route explicitly declares image input; the whole batch is decoded and admitted before any member is saved, and malformed or unsupported batches become diagnostic text. Audio and embedded-resource payloads stay out of model context (the canonical value keeps the JSON block), and resource links keep only their name and URI as text.
  • Unsupported output schemas are not enforced: structuredContent falls back to JsonValue.

Verification

# see the mcp client in the composition tree
dsh web --dump-config | grep -A3 mcp
# see tool calls in the session log (mcp__ prefix naming)
zstdcat ~/.dsh/sessions/*/*/session.jsonl.zstd | grep -E '"mcp__' | head

Next steps