Skip to content

Model Context Protocol(MCP)让 dsh 无需为每个服务器编写适配器即可与外部工具服务器通信。在 dsh 中这是一个单一包,@deepseek-ai/dsh-mcp-clientpackages/mcp/mcp-client),一个桥接插件:连接一个 MCP 服务器、发现服务器的工具,并把每个工具以服务器限定的名字注册为原生 dsh 工具。每台 MCP 服务器一个插件实例,在 cordis.yml 中配置。

字段版本 / 角色
packages/mcp/mcp-clientMCP 客户端桥

官方参考见 packages/mcp/mcp-client/README.md;没有独立的子系统页面,因此本页直接取材自该 README 与 packages/mcp/mcp-client/src/*

MCP 工具如何浮现

每个 MCP 工具都有两个名字

  • 原始 MCP 名——在 wire 上的 tools/call 中发送;
  • 公开名 mcp__<serverName>__<rawName>——注册在 ctx.tools 上,也是模型所见。

公开名被规范化为 DeepSeek 函数名契约(64 字符,[A-Za-z0-9_-]);当规范化改变名字时,会追加 (serverName, rawName) 的确定性 12 位十六进制哈希,使不同工具绝不合二为一。名字是 (serverName, rawName)纯函数——连接顺序、重新同步、其他服务器都不会改名。这正是 Claude Code 与 Codex 所用的形态,例如 mcp__github__create_issuemcp__web__search

连接时,插件激活会 await listTools() 并在组合启动首轮之前通过 ctx.tools.register() 注册每个广告的工具。在工具注册表中的生命周期:每个 MCP 工具都是普通的 ToolDefinition,其 execute 以超时 + 中止支持调用 client.callTool({ name: rawName, arguments }, { signal })——公开名绝不发给服务器。

传输与配置

两种传输。两者都经由 Model Context Protocol 生成/发起来自真实 MCP 客户端的连接:

yaml
- 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' }

- 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}`' }
配置字段适用于必填说明
transport两者"stdio""streamable-http"
serverName两者工具名的命名空间;[A-Za-z0-9_-]{1,32},在存活实例间唯一
commandstdio要启动的可执行程序
args / env / cwdstdio不经 shell 传参;净化后的环境 + env 覆盖;工作目录
urlhttpMCP 服务器 URL
headershttp附加 HTTP 头(如认证 token)
toolCallTimeoutMs两者每次 callTool 超时(默认 60000)
failOnStartupError两者初始连接/同步失败时拒绝激活(默认 false
reconnect.enabled / initialDelayMs / maxDelayMs / maxAttempts两者指数退避重连:500 → 30000 ms 上限,10 次尝试

stdio 启动会故意过滤环境:名称通常标识凭据的环境变量及所有 DSH_* 变量在启动前被移除;其他环境变量保持继承。

生命周期、重新同步与重连

  • 发现:初始 listTools() 门控激活;失败会记日志,且除非 failOnStartupError,否则插件以 with no tools 激活。
  • 重新同步:客户端监听 notifications/tools/list_changed 并重新同步。抓取阶段失败会保留上一代注册;注册冲突会回滚整代且不留下该服务器的任何工具。
  • 重连:断开/崩溃时,监督器以指数退避(initialDelayMs 翻倍至 maxDelayMs)重启原服务器配置,并在成功后重新发现——恢复的一代替换之前的一代,因此工具既不重复也不泄漏。中断期间最后一代良好注册保持存活(调用直到恢复前都失败)。重连按代/outage 预算:连失 maxAttempts 次后该服务器工具被注销,重连停止,直到 HMR 重载或 Host 重启;存活超过 maxDelayMs 的连接会重置预算。
  • HMR:编辑条目会触发断开 + 重连,无需进程重启;serverName 不变则复现出相同的工具名。

面向模型的行为

  • 工具结果:规范成功值为 { content: JsonValue[], structuredContent? };完整 JSON 块对程序化调用方存活。当广告的 outputSchema 受支持时,structuredContent 会据其校验;不支持的 schema 词汇回退为无约束的 JsonValueisError 经由注册表错误路径拒绝该调用。
  • 原生文本投影:文本块以换行连接;图像、音频、资源与不支持块变为短占位符(其完整 JSON 块仍留在执行本地值中)。参数与映射文本保留到压缩为止;二进制/资源负载被丢弃而非加入上下文。
  • KV 缓存:当发现的集合/schema 不变时前缀稳定;改变某工具的重新同步会替换定义,并可能从首个被改变的 schema 起使复用失效。恢复不变列表则保持前缀稳定。

示例:examples/mcp-memory

仓库在 examples/mcp-memory/ 下随附三个默认关闭的参考配置,通过本客户端把第三方内存服务器接到 dsh:

文件系统传输
memorix.cordis.ymlMemorixstdio
mcp-reference-memory.cordis.ymlMCP Reference Memorystdio
engram.cordis.ymlEngramstdio

dsh web --patch 'examples/…/<name>.cordis.yml' 启用其一。dsh 解析 Cordis overlay、启动 stdio 命令(或连接 URL)、发现工具并把它们暴露为 mcp__<serverName>__<tool>。dsh 下载服务器、初始化其数据库、选择模型,也不监督独立的 HTTP 服务;对 stdio,通用客户端随 dsh 插件生命周期启动并停止子进程。

已知局限

  • 工具是唯一被桥接的 MCP 能力——Resources 与 Prompts 没有 harness 消费方,被推迟。
  • 启动超时继承自 MCP SDK——dsh 不暴露自己的连接/发现超时;每次 initialize 或分页 tools/list 用 SDK 的 60 秒默认值。
  • 重连在传输关闭时触发——HTTP 失败经由 SDK 的 SSE 流恢复按请求浮现,而非被监督器重生。
  • 原生非文本渲染有损,且不支持的 MCP 输出 schema 不被强制(回退为 JsonValue)。

延伸阅读

  • 工具注册表与执行流水线——已注册 MCP 工具运行之处
  • 设置与配置——cordis.yml/cordis.patch.yml 如何配置插件
  • SDK 协议——面向程序化调用方的 mcp__<server>__<tool> 命名规范化
  • packages/mcp/mcp-client/README.md——桥接插件的完整行为与配置
  • packages/mcp/mcp-client/src/connection.ts——连接监督器与重连
  • examples/mcp-memory/README.md——三个内存服务器参考配置