@epoch-agent/plugin-mcp

中文文档
6.2.0发布于 2026/11/13Apache-2.0TypeScriptES Module近 30 天下载 4583

epoch-agent MCP 客户端插件

原始使用文档
文档目录10 节
  1. 支持 Transport
  2. 配置示例
  3. 字段
  4. server 是从哪儿来的: McpServerStatus.source
  5. 功能
  6. ⚠️ 写 MCP server 的人请处理 notifications/cancelled
  7. 还没做
  8. 明确不做的三条( 带判据,不是「以后再说」 )
  9. 依赖
  10. 开发

@epoch-agent/plugin-mcp

MCP (Model Context Protocol) 客户端插件。连接外部 MCP server 扩展工具集。

配置文件位置由 @epoch-agent/infra 的 mcpConfigPath() 决定 (认 EPOCH_HOME / EPOCH_PROFILE),默认 ~/.epoch/mcp.json。

支持 Transport

Transport配置场景
Stdiocommand + args本地 MCP server 进程
SSEurl远程 MCP server
Streamable HTTPurl + transport: "http"(或 streamable)远程 HTTP 流式

⚠️ stdio 那档要机器上有 Node。 command 是从 PATH 解析的 (SDK 用 cross-spawn、shell: false),而官方配置几乎都是 npx -y @modelcontextprotocol/server-xxx —— PATH 上没有 npx / node 就是 ENOENT, 那台 server 起不来(stderr 里那行会进日志)。 CLI 用户天然有 Node;嵌入宿主的用户没有,那边要宿主自己把 ship 的 node 目录 prepend 到 process.env.PATH,见 EMBEDDING.md 的 「用户机器上没装 Node」一节。HTTP / SSE 那两档不起子进程,不受这条影响。

transport 不写时按 url 有无推断:有 url 走 SSE,没有走 stdio。 type 是 transport 的别名(MCP 生态里多数客户端的 mcp.json 用的是 type), 两个都写时听 transport 的。收它不是为了顺手:不收的话 {"type":"http","url":…} 会掉进上面那条「按 url 推断」的路,一个 Streamable HTTP server 被静默连成 SSE。

配置示例

servers 是以 server 名为键的对象,不是数组:

这份文件现在有两条写法:手写,或者 epoch web 的连接器页那枚「添加 server」 (2026-08-18,POST /api/mcp)。

界面那条只收三样(传输类型 / 命令或 URL / 环境变量)—— 下面那几格 (timeout / oauth / headers …)仍然只能手写,所以它加完会把 「写进了哪个文件」印出来,让你接着去补。

⚠️ 界面那条往原文里插一段,你的注释、键序、缩进、以及 connect_timeout / type 这类别名一个字节都不动(它不是「读进来 → 改 → 整份写回」)。 判据全文在 runtime/src/mcp-config-write.ts。

⚠️ 界面那条给的 server 名收得比这份文件严(只许字母数字和 _ -)—— 手写的不受这条管。理由同下面「插件带的名字为什么更严」:名字会原样进工具名。

{
  "servers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
      "env": { "LOG_LEVEL": "warn" }
    },
    "remote": {
      "transport": "http",
      "url": "https://mcp.example.com/mcp",
      "headers": { "Authorization": "Bearer xxx" }
    }
  }
}

字段

字段类型说明
transport / typestdio|sse|http不写按 url 推断;互为别名
command / argsstring / string[]stdio 必填
urlstringsse / http 必填
streamableboolean远程用 Streamable HTTP 而非 SSE
headersRecord<string,string>远程请求头(如 auth)
envRecord<string,string>子进程环境变量
timeout秒单次请求超时,默认 300
connect_timeout秒建连(含握手)超时,默认 60
keepalive_interval秒心跳间隔,默认 180
idle_timeout_seconds秒空闲自动断开,0 表示不断
max_lifetime_seconds秒连接最大寿命,0 表示不限
supports_parallelboolean是否允许并行调用
skip_preflightboolean跳过启动预检

snake_case 和 camelCase 两种写法都收。未知字段会进启动诊断(多半是拼错了), 配置写错不再静默变成「没有 MCP」—— 每条问题都带文件名 + 字段路径。

⚠️ source 不是这张表里的字段,写在 mcp.json 里不生效。 那一格在 McpServerStatus 上(不在配置上),由调用方在 connectAll(configs, source) 那一下填死。分开是刻意的:来源要是配置的一个字段,用户就能给自己那台贴上 「宿主注入」的标 —— 同角色那条「命名空间由装配层拼,宿主自己写的不算数」。

server 是从哪儿来的:McpServerStatus.source

三档:

source谁带来的名字长什么样
user上面那份 ~/.epoch/mcp.json你自己写的那个
host嵌入宿主 buildRuntime({hostCapabilities: {mcpServers}})<namespace>__<server>
plugin已装插件根下那份 mcp.json(方案 44 PR-3)<插件名>__<server>

前两档一个字节都不落盘 / 落在插件目录里,能力页的连接器那一栏就是按这一格分组的。

⚠️ 加一档要连着改能力页那张 MCP_GROUPS 数组(web/src/capability/connectors.tsx) —— 那是 satisfies readonly {…}[],多一格不会编译红,而页面按组过滤后渲染, 漏改的表现是那一档一行都不显示、也没有任何报错。PR-2 实测复现过一次。

后两档的名字都由装配层拼,用两个下划线,而不是专家 / 技能那条路上的 <namespace>:。这不是两套风格:

  • server 名会原样变成工具名的一部分(prefixedName() 拼的 mcp__<server>__<tool>),而工具名是真的发给 provider 的;
  • 2026-08-17 实测:带 : 的工具名被硬拒 —— tools.0.custom.name: String should match pattern '^[a-zA-Z0-9_-]{1,128}$', 同一发换成 mcp__gh__search_issues 就 200 正常回;
  • 角色名 / 技能名不上网线进 provider,所以那边拼 : 一直没事。

判据全文(含「为什么这两批的名字收得比 mcp.json 严」、两个前缀的来路差别 (宿主那个是 buildRuntime 的参数、装配时校验;插件那个是插件名、安装时就被 PLUGIN_NAME_PATTERN 卡过了)、以及为什么这一格是必填)在 types.ts 的 McpServerStatus.source 上。

功能

  • 三 transport(stdio / SSE / Streamable HTTP)
  • 工具名前缀 mcp__<server>__<tool>,撞名交 ToolRegistry 处理
  • 配置校验:语法错误 / 类型错误 / 缺必填字段都进诊断,逐 server 隔离
  • tools/list annotations + title 透传到 EpochTool.annotations(权限系统消费)
  • schema 缓存:内存优先,磁盘(0600)作降级;按连接配置指纹失效
  • 看门狗式重连:断连不阻塞工具调用,重连在后台按 1s/2s/4s 退避
  • 取消得掉:ToolContext.signal 一路递到 SDK 的 RequestOptions.signal, 用户按停时 server 当场收到 notifications/cancelled(见下面那一节)
  • timeout 对每一条请求都算数:tools/call / tools/list / resources/* / prompts/* 用的是同一个 McpClient.requestOptions()。 ⚠️ resources/list 这种翻页的是逐页给 —— SDK 的超时按请求算,只给第一页的话 第二页起又落回它那个 60 秒默认值
  • keepalive 心跳、idle 超时断开、最大生命周期
  • OAuth(oauth/):epoch mcp login / logout 的后端,本机回调 server + token 刷新(带 skew)+ 0600 存储。认证过不去时置 needsLogin——重连解决不了 这个问题,只有重新登录能
  • resources:包成每个 server 一对工具 mcp__<server>__list_resources / mcp__<server>__read_resource
  • prompts:McpRegistry.listPrompts() / getPrompt()
  • 一台一台地断 / 问它此刻按的哪份配置(2026-08-18): McpRegistry.disconnect(name) / configOf(name)。在这之前只有 disconnectAll() —— 而「让一台 server 在这个进程里消失」是装配层那条「应用 mcp.json 的改动」 必须做到的事(runtime 的 applyMcpConfig):全断再全连会把宿主注入的和插件带来的 那两批也连带断掉,而它们一个字节都不在那份文件里。 ⚠️ disconnect() 连带失效 schema 缓存(同 reconnect()),但不碰工具表 —— 把 mcp:<名字> 那一组工具从 ToolRegistry 里摘掉是装配层的事

resources 和 prompts 都先看 capability 再问(server 没声明就别问,问了多半得到 -32601 Method not found),都翻页(nextCursor,上限 50 页),都把 method-not-found 当空处理——有些 server 声明了 capability 却没实现, 「没有 resources」比「MCP 初始化失败」更贴近事实。

resources 包成工具而不是注入上下文:一个 server 挂几十份文档是常态,全量注入等于 每一轮都为「模型多半用不到的东西」付 token;而工具是按需调用的,天然懒加载。

⚠️ 写 MCP server 的人请处理 notifications/cancelled

一次 tools/call 有两种结束不掉的方式,两种我们都会发那条通知:

  • 用户按停(ToolContext.signal → SDK 的 RequestOptions.signal)
  • timeout 到了(上面那张表里的 timeout 秒)

通知的形状是 JSON-RPC 规范里那一条:

{ "method": "notifications/cancelled", "params": { "requestId": 2, "reason": "…" } }

不认它的 server 会继续把活干完,而客户端这侧已经没人在等了。实测过一趟真跑的 代价:4 次 invoke → 后端 4 条「收流结束」一条不少,两份跑完的完整报告被扔掉, 外加一次白烧的后端算力。用 SDK 写的 server 自动就有这个行为;手写 JSON-RPC 的 要自己接(按 requestId 记一张在飞表,收到通知就中断那次活,且取消之后 result 和 error 都不发)。

⚠️ 这件事不因为 timeout 配得多长而消失:只要还有超时,「客户端放弃了而 server 还在跑」这个窗口就一直在。

还没做

notifications/tools/list_changed 收得到,但不是热更新:AgentLoop 的工具集是 构造参数,本进程内换不掉。registry 只把「工具表已经不是启动时那份了」冒泡给宿主, 真正换掉要重启。

明确不做的三条(带判据,不是「以后再说」)

  • sampling / elicitation(server 反过来请求 client:帮我调一次模型 / 帮我问用户 一句)。它要一个新的 AgentEvent 变体加一道权限闸门 —— 也就是动 protocol, 而那是全仓最贵的改动面。硬门槛在权限那一侧而不是协议那一侧:一个 server 能让我们 代它调模型,等于它能花我们的钱、并且把内容塞进我们的上下文,那需要先有一套 「这次反向请求要不要问用户」的语义。要做就先定那套语义,别从 SDK 那头往回接。
  • MCP server 的目录 / 市场(对标 hermes 的 mcp_catalog.py + mcp_picker.py)。 ⚠️ 别和方案 32 的插件市场 混为一谈:32 管的是我们自己的插件(~/.epoch/plugins/),这一条管的是 「上哪儿找第三方 MCP server」。两件事,两套来源,两套信任模型。
  • MCP server 模式(把 epoch 自己暴露成 MCP server 给别的 agent 用)。 hermes 有 mcp_serve.py、codex 有整个 codex-mcp/ crate,但那是「被集成」 而不是「集成」。更强的版本连同一条永久红线(真做也只暴露 epoch_run, 不把内置工具逐个转出去 —— 那等于让对方绕过我们的权限层)写在 方案 28 验收记录第五章(那一版 epoch mcp serve 已经砍掉,红线连同重开的条件一起记在那儿)。

依赖

  • @modelcontextprotocol/sdk
  • zod(配置校验,走 infra 的 parseLenient)
  • protocol 和 infra —— 四个都是 dependencies (本包没有 peerDependencies —— 2026-11-03 核)

开发

pnpm --filter @epoch-agent/plugin-mcp test

__tests__/orphan-reap.test.ts 真起 server、真查残留,钉的是 closeTransportAndReap() 那三步(拍快照 → 优雅关 → 清扫快照)。Windows 和 macOS 都跑,改 disconnect 路径必须跑它。

⚠️ 用例里那个「启动器」中间层必须是 shell(Windows 生成一个 .cmd,POSIX 用 /bin/sh -c),换成 node 写的启动器用例就是空的:Windows 上 node 起的非 detached 子进程会被 libuv 的全局 Job Object 连坐收掉,父进程一死孙进程自动没,把清扫整段 删掉照样全绿。shell 也更接近真实形态——npx -y mcp-remote … 在 Windows 上就是被 cross-spawn 改写成 cmd.exe /c npx.cmd … 的。细节记在 验收记录 的「追加二」。

版本与发布记录

@epoch-agent/plugin-mcp 共发布 57 个版本,首次发布于 2026/08/19;过去 12 个月发布了 57 个版本。

版本发布日期距今
6.2.0latest2026/11/13今天
6.1.02026/11/112 天前
6.0.02026/11/112 天前
5.0.02026/11/103 天前
4.1.12026/11/067 天前
4.1.02026/11/067 天前

关于 @epoch-agent/plugin-mcp 的常见问题

@epoch-agent/plugin-mcp 是什么?

epoch-agent MCP 客户端插件

如何安装 @epoch-agent/plugin-mcp?

在项目目录运行 npm install @epoch-agent/plugin-mcp,或使用 pnpm add / yarn add / bun add。

@epoch-agent/plugin-mcp 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@epoch-agent/plugin-mcp 支持 ESM 还是 CommonJS?

以 ES Module 形式发布,推荐使用 import 引入。在 CommonJS 项目中,Node.js 20.19+ / 22.12+ 可以直接 require() 不含顶层 await 的 ES Module,更早的版本需要改用动态 import()。

@epoch-agent/plugin-mcp 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=22.0.0。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@epoch-agent/plugin-mcp 可以商用吗?

@epoch-agent/plugin-mcp 使用 Apache-2.0 许可。宽松许可:允许商业使用、修改和再分发,并附带明确的专利授权;分发时需保留许可与 NOTICE 文件,修改过的文件要注明改动。以上为概括,不构成法律意见,请以许可原文为准。

@epoch-agent/plugin-mcp 的下载量有多少?

根据 npm 官方下载统计,@epoch-agent/plugin-mcp 在 2026/10/14 – 2026/11/12 这 30 天内被下载 4,583 次,日均约 153 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@epoch-agent/plugin-mcp 还在维护吗?

最新版本 6.2.0 发布于 2026/11/13(今天);至今共发布 57 个版本,其中过去 12 个月发布了 57 个;首次发布于 2026/08/19。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。