教程2026-10-24 · 智涌AI

MCP 是什么、怎么配?2026 新协议实测与 4 个坑

终端里 MCP filesystem 服务器响应 server/discover 和 tools/call、claude mcp list 显示已连接的示意

MCP(Model Context Protocol)是一套让 AI 应用接外部工具的开放协议:工具方写一个 MCP 服务器,Claude Code、OpenCode 这些客户端就都能调用,不用每家各接一遍。7 月 28 日发布的新版规范把握手去掉了,很多老教程已经对不上。我们在沙箱里用官方的 filesystem 和 memory 两个服务器从头走了一遍:先手发 JSON-RPC 看清协议,再接进 Claude Code 和 OpenCode,最后让一个本地 4B 小模型真去调用。

MCP 解决的是「一个工具接 N 遍」

没有 MCP 的时候,想让编码 Agent 查数据库、读 Sentry、改 Notion,每个 Agent 都得自己写一套集成。MCP 把这件事拆成三方:宿主应用(Claude Code、OpenCode)里跑着 MCP 客户端,工具方提供 MCP 服务器,两边用 JSON-RPC 说话。服务器对外暴露三类东西:工具(tools,让模型调用)、资源(resources,给模型读的数据)和提示词模板(prompts)。日常用得最多的是工具。

连法有两种。本地服务器走 stdio:客户端把它当子进程拉起来,从标准输入输出收发消息,适合读写本机文件、跑脚本。远程服务器走 Streamable HTTP,适合 SaaS 服务,通常带 OAuth 登录。老的 HTTP+SSE 传输在新规范里被正式列为弃用。

官方仓库 modelcontextprotocol/servers 现在只维护 7 个参考实现:Everything、Fetch、Filesystem、Git、Memory、Sequential Thinking、Time。仓库首页写明它们是教学示例,不是生产级方案;GitHub、Slack、PostgreSQL 等老服务器已归档,找第三方服务器要去 MCP Registry。

前置条件

第一步:先绕开客户端,直接跟服务器说话

想弄懂 MCP,最快的是自己当一回客户端。stdio 服务器就是个命令行程序,每行读一条 JSON-RPC 请求、写一条响应。我们写了个十几行的 rpc.py,把 filesystem 服务器拉起来,只允许它访问 demo/ 目录:

npm install @modelcontextprotocol/server-filesystem@2.0.0
# 服务器参数就是允许访问的目录
node_modules/.bin/mcp-server-filesystem ./demo

按新协议,第一条请求不再是 initialize,而是 server/discover;之后每个请求都在 _meta 里带上协议版本和客户端能力:

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{
  "_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28",
           "io.modelcontextprotocol/clientCapabilities":{}},
  "name":"read_text_file","arguments":{"path":"/abs/path/demo/note.txt"}}}
filesystem 服务器同时响应旧版 initialize 握手和新版 server/discover,越界读取被拒,未知版本返回 -32022
同一个 filesystem 2.0.0 服务器:旧握手和新协议都能答;读 /etc/hostname 被拒;协议版本写 2027-01-01 时返回 -32022。

输出里有几处要留意。server/discover 报告只支持 2026-07-28,结果里多了必填的 resultType: complete;tools/list 带上了新加的 ttlMs 和 cacheScope 缓存字段。服务器同时还认旧客户端:发 2025-11-25 版的 initialize,它照样回 protocolVersion: 2025-11-25,只是在 stderr 里提示客户端不支持 Roots,改用启动参数里的目录。把版本号写成不存在的 2027-01-01,它回错误码 -32022,并附上支持的版本列表。

新规范还改了这些:Mcp-Session-Id 和协议级会话被删掉,ping、logging/setLevel 被移除,Tasks 挪进了官方扩展,Roots、Sampling、Logging 三个功能进入弃用期(规范承诺至少 12 个月)。Claude Code 文档写明,它的 v2 运行时基于 TypeScript SDK 2.0,会先问服务器支不支持新版本,支持就用新协议,不支持就退回旧握手。

第二步:接进 Claude Code,先选对作用域

Claude Code 用 claude mcp add 加服务器,-- 后面是启动命令,环境变量用 --env 传:

claude mcp add fs -- npx -y @modelcontextprotocol/server-filesystem@2.0.0 /path/to/demo
claude mcp add memory --env MEMORY_FILE_PATH=/path/to/memory.jsonl \
  -- npx -y @modelcontextprotocol/server-memory@2.0.0
claude mcp add fetch -- uvx mcp-server-fetch==2026.10.19
claude mcp list

不加 --scope 时默认是 local。三个作用域和 OpenCode 的写法对比如下:

写在哪谁能用适合我们实测
Claude Code local(默认),~/.claude.json 里当前项目下只有你,只在这个项目带密钥的、试验性的服务器3 个服务器全部 ✔ Connected
Claude Code project,项目根目录 .mcp.json提交进仓库,全队共享团队统一工具3 个都显示 ⏸ Pending approval
Claude Code user,~/.claude.json 顶层只有你,所有项目个人常用工具未测
OpenCode,opencode.json 的 mcp 段看文件放在项目还是全局OpenCode 用户2 个服务器 ✓ connected

同名服务器在多个作用域都定义时,Claude Code 按 local、project、user 的顺序取第一个,整条配置覆盖,不做字段合并。

第三步:OpenCode 的写法

OpenCode 没有 add 命令,直接改配置。本地服务器 type 写 local,command 是数组,环境变量放在 environment 里:

{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "fs": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-filesystem@2.0.0", "/path/to/demo"],
      "enabled": true
    },
    "memory": {
      "type": "local",
      "command": ["npx", "-y", "@modelcontextprotocol/server-memory@2.0.0"],
      "environment": { "MEMORY_FILE_PATH": "/path/to/memory.jsonl" },
      "enabled": true
    }
  }
}

远程服务器写 "type": "remote" 加 url,需要 OAuth 时用 opencode mcp auth 名字 登录。暂时不想用某个服务器,把 enabled 改成 false 就行,不用删配置。

claude mcp list 显示项目级服务器待批准、本地级已连接,opencode mcp list 显示两个服务器已连接
同样三个服务器:项目级 .mcp.json 卡在待批准,local 作用域直接连上;OpenCode 两个服务器都连上。

第四步:让模型真的去调用

连上了只说明进程起得来,模型会不会用得另外看。我们用 claude -p 非交互模式接本地 Qwen3.5-4B,传一个只含 fs 和 memory 的配置文件,让它读 note.txt,再在 memory 里建一个实体:

claude -p "读 note.txt,再用 memory 的 create_entities 建实体 demo-note" \
  --model qwen35-4b-r --mcp-config mcp.json --strict-mcp-config \
  --allowedTools "mcp__fs mcp__memory"
本地 4B 模型 12 次调用 MCP 工具、8 次报错后成功读文件并写入 memory
4B 小模型 13 轮、228 秒做完:12 次工具调用里 8 次报错,靠服务器返回的错误信息一步步改对。

最后结果是对的:模型答出「hello mcp」,memory.jsonl 里也写进了 demo-note 实体。中间绕了不少弯:参数名填成 file_path(服务器要的是 path),去读允许目录之外的路径,把数组写成字符串。每次出错服务器都回了具体的校验信息,模型照着一点点改对。换成更强的模型,这种来回会少很多,我们这次没测。

常见坑

坑 1:项目级 .mcp.json 一直「待批准」。我们在 .claude/settings.local.json 里先后写了 enabledMcpjsonServers 和 enableAllProjectMcpServers: true,claude mcp list 仍是 ⏸ Pending approval。Claude Code 文档给了原因:在没信任过的目录里,Claude Code 要先弹信任对话框才会读这个文件里的批准,仓库里自带的批准也不算数。解决办法是在项目里交互式运行一次 claude,接受信任并批准;或者把批准写进用户级 ~/.claude/settings.json。文档还写了,claude -p 非交互运行会不经询问直接加载项目级服务器,不想加载的要写进 disabledMcpjsonServers。

坑 2:权限规则只写单个工具名,模型偏偏调别的。第一次我们只放行了 mcp__fs__read_text_file 和 mcp__memory__create_entities。模型连着三次去调已标记弃用的 read_file,三次都被拒,最后回了一句「需要您的权限」就结束了(5 轮、241 秒)。改成 mcp__fs mcp__memory,按服务器整体放行,第二次就跑通了。整台服务器放行等于把写文件、移动文件也交了出去,要配合服务器自己的允许目录一起用。

filesystem 服务器的允许目录是最后一道墙:模型两次想列上层目录,都被 Access denied 挡了回来。

坑 3:工具清单会吃上下文。filesystem 服务器一共 14 个工具,tools/list 的 JSON 有 13201 字节;memory 有 9 个工具、11529 字节。挂上这两个服务器后,Claude Code 首轮请求是 11123 个 token,本地 CPU 光读这一轮就要 90 秒上下。我们又用一句「回复 ok」单独测了三次:不挂 MCP 是 10857 个 input token;挂上这两个服务器、用 ENABLE_TOOL_SEARCH=false 关掉 tool search 后是 21300;默认开着 tool search 是 11070,工具定义被推迟到用的时候再加载,只多了两百来个。OpenCode 文档也提醒,GitHub 这类工具多的服务器很容易把上下文撑爆,用不上的服务器就关掉。

坑 4:密钥别直接写进 .mcp.json。这个文件是要提交进仓库的。Claude Code 支持在里面写 ${API_KEY} 或 ${VAR:-默认值},从环境变量展开;文档还说明,ANTHROPIC_API_KEY 这类凭据变量在远程服务器的 url 和 headers 里会被读成空,防止项目配置把你的凭据发给第三方。

完成标准

最后

先从 filesystem 这种本地服务器起步,用 local 作用域加上、跑通一次真实调用,再考虑把它写进 .mcp.json 分给团队。远程服务器、OAuth 和自己写服务器,可以接着看我们之前那篇40 行写 MCP 服务器接进 OpenCode 实测。

关注公众号「智涌AI速递」

每天的 AI 快讯、实用教程和 AI项目实测,也会同步发到微信公众号。在微信里搜索「智涌AI速递」就能关注;不用微信的话,可以用 RSS 订阅本站。