avatar


6.MCP

引子

在2024年的年初,我们使用Cursor的时候,我们可能会感觉Cursor写后端比写前端厉害,即使后端的逻辑比前端复杂多了。
因为,那时候Cursor可以读取后端的输入、输出、甚至访问数据库(我们把数据库连接给它,它自己安装Shell工具去读)。
但是,那时候Cursor访问不了前端。如果页面效果不是我们想要的,我们只能截图给他(但是他图片理解能力有不强),或者只能我们口述页面效果哪里哪里不对(又讲不清)。

这个问题的根源,不是模型不够聪明,也不是上下文被污染了。是那时候Cursor调用工具的能力,无法调用浏览器看网页效果。

那么,内置工具够不着的外部系统,怎样安全地接进工具调用循环?

外部工具和Cursor约定一个标准协议,外部系统按协议把能力暴露出来,ClaudeCode按协议接入,两边各实现一次。这就是MCP。

原理

什么是MCP

MCP(Model Context Protocol,模型上下文协议)是一个开源标准协议。外部系统实现一个MCP服务,把自己的能力以标准形式暴露出来;ClaudeCode作为MCP客户端接入外部系统,循环里就多了一批可调用的能力。数据库、Jira、GitHub、浏览器,接法完全一致。

MCP服务的三类能力

MCP服务有三类能力,在ClaudeCode中各有对应的入口:

能力 是什么 在ClaudeCode中的入口
Tools(工具) 供Claude调用的可执行函数,如查询数据、调用API 进入工具调用循环,与内置工具一样被自动选用,规范名为mcp__<server>__<tool>
Resources(资源) 可按需读取的数据实体,如一条Issue、一个文件 会话中用@server:scheme://id引用,如@github:issue://123
Prompts(提示) MCP服务预置的提示模板 成为斜杠命令/mcp__server__name,如/mcp__github__list_prs,提示名与MCP服务名中的空格会转换为下划线

其中:

  • Tools覆盖绝大多数场景。
  • Resources适合把一份外部数据精确拉进上下文。
  • Prompts则把MCP服务作者写好的任务模板变成一条斜杠命令。

示例

需求

一个Web项目团队,要让ClaudeCode接入GitHub、项目数据库和公司内部API。

第一步:接GitHub

用HTTP传输加Bearer token。示例代码:

1
2
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
--header "Authorization: Bearer YOUR_GITHUB_TOKEN"

添加后三类能力全部就位:让Claude"把刚才的报错整理成issue提交"走的是工具调用;@github:issue://123把一条issue精确拉进上下文;/mcp__github__list_prs直接执行MCP服务预置的提示。

第二步:接项目数据库

用项目范围让全组共享。示例代码:

1
2
claude mcp add --scope project \
mydb -- npx -y @bytebase/dbhub --dsn '${DB_URL:-postgresql://readonly@localhost:5432/appdb}'

这条命令有三个关键点:

  • --scope project:把配置写进项目根目录的.mcp.json,提交后同事克隆仓库即用。
  • --:之后是stdio MCP服务的启动命令。
  • 单引号:防止Shell在add时抢先展开${DB_URL:-...},让它原样写进.mcp.json、留到运行时才按后文的环境变量展开规则取值,真实凭证不进仓库。

第三步:接公司内部API

手写.mcp.jsonheadersHelper。示例代码:

1
2
3
4
5
6
7
8
9
10
11
{
"mcpServers": {
"corporate-api": {
"type": "http",
"url": "https://internal.company.com/mcp",
"headersHelper": "/usr/local/bin/mcp-sso-headers.sh",
"timeout": 30000,
"alwaysLoad": true
}
}
}

三个字段各管一件事:

  • headersHelper
    指向的脚本在标准输出打印一个JSON对象作为附加请求头(如{"X-Token": "..."}),token的获取与刷新逻辑都在脚本里,配置文件中不出现任何凭证,见后文认证一节。
  • timeout
    按内网延迟收紧到30秒。
  • alwaysLoad
    让这台高频MCP服务的工具始终加载,见后文性能一节。

改完重启会话,claude mcp list确认三台MCP服务都在线。

实践

claude mcp 命令族

MCP服务用claude mcp命令族管理:

命令 说明
claude mcp add 添加MCP服务;远程形式为claude mcp add <name> <url>,本地stdio形式把启动命令放在--之后
claude mcp list 列出所有已配置MCP服务及连接状态
claude mcp get <name> 查看单台MCP服务的详细配置与错误详情
claude mcp remove <name> 删除MCP服务,可用--scope指定从哪个范围删
claude mcp add-json <name> '<json>' 用一段JSON直接配置MCP服务
claude mcp add-from-claude-desktop 从Claude Desktop导入已配置的MCP服务
claude mcp login <name> / claude mcp logout <name> OAuth登录与清除凭证,见下文认证一节
claude mcp serve 把ClaudeCode自身作为一台MCP服务启动,供其他MCP客户端调用
claude mcp reset-project-choices 重置项目级MCP服务的批准状态

claude mcp add 常用参数

参数 说明
--transport {http\|sse\|stdio\|ws} 传输方式,默认stdio,远程推荐http
--scope {local\|project\|user} 配置存储范围,默认local
--header "Key: Value" 附加请求头,常用于传Bearer token
--env KEY=value 传递给MCP服务的环境变量
--client-id--client-secret--callback-port <PORT> 预配置OAuth凭证,见下文认证一节

传输方式

传输 用途 特点 认证方式
HTTP 远程托管MCP服务(推荐) 标准请求响应,可靠性高 OAuth、Bearer token、headersHelper
SSE 远程托管(已废弃) Server-Sent Events单向推送,仅为兼容旧配置保留 静态header
stdio 本地进程 以子进程方式启动本地程序,可访问本地文件与数据库socket 环境变量、本地权限
WebSocket 持久连接、事件推送 双向通信,不支持OAuth 静态header、headersHelper

选型准则:

  • 本地进程选stdio
  • 远程一律HTTP(SSE只在迁移旧配置时会遇到)
  • WebSocket留给需要持久双向连接的场景。

配置范围

同一台MCP服务登记在哪个范围,决定了它对谁生效、存在哪个文件里:

范围 存储位置 生效范围 进版本库
local ~/.claude.json中当前项目的条目 仅当前项目、当前用户
project 项目根目录的.mcp.json 克隆该仓库的所有人
user ~/.claude.json顶层的mcpServers 当前用户的所有项目
plugin 插件内打包的.mcp.json 插件启用时自动加载,见《7.Plugin》 随插件分发
claude.ai 云端(claude.ai的connectors配置页) 登录该账户的ClaudeCode 否(云端)

同名MCP服务同时存在于多个范围时,按local>project>user>plugin>claude.ai取高优先级的那个。

不想加载claude.ai连接器时,可在settings.json中设disableClaudeAiConnectors: true,或以环境变量ENABLE_CLAUDEAI_MCP_SERVERS=false启动。

范围的选择有个简单次序:个人通用工具放user,团队共享放project,单项目试验用默认的local。

.mcp.json

例子

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${GITHUB_TOKEN}"
}
},
"mydb": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@bytebase/dbhub", "--dsn", "${DB_URL:-postgresql://localhost:5432/appdb}"]
}
}
}
  • 只留${GITHUB_TOKEN}这样的引用,真实凭证在每个人自己的环境变量里

主要字段

字段 适用传输 说明
type 全部 httpssestdiows之一
url HTTP/SSE/WS MCP服务端点
headers HTTP/SSE/WS 静态请求头
headersHelper HTTP/WS 指向一个脚本,运行时用其输出作为请求头,见下文认证一节
oauth HTTP 预配置OAuth:clientIdcallbackPortscopesauthServerMetadataUrl
commandargsenv stdio 本地进程的启动命令、参数与环境变量
timeout 全部 超时,毫秒
alwaysLoad 全部 跳过工具延迟加载,见下文性能一节

注意事项

  • 配置值支持环境变量展开:${VAR}在运行时替换为环境变量值,${VAR:-default}在变量未设置时使用默认值。这是把.mcp.json安全提交进仓库的关键。
  • .mcp.json在会话启动时一次性读取,改动配置后必须重启会话才生效。

会话内管理

会话内运行/mcp打开交互面板,可以查看各MCP服务的连接状态与工具数量、发起认证、手动重连或切断连接。

认证

标准OAuth流程

会话内操作

远程MCP服务的标准认证是OAuth,流程是:

  1. 添加MCP服务,如claude mcp add --transport http <name> <url>
  2. 会话内运行/mcp,选中该MCP服务,执行Authenticate
  3. 浏览器完成登录后,token由ClaudeCode保存并自动刷新。

命令行操作

也可以直接在命令行认证:claude mcp login <name>

在SSH或没有图形界面的机器上加--no-browser,会改为给出URL让我们在别处完成登录。

这个认证方式,很像我们在ClaudeCode上的"Claude account with subscription"认证方式。

退出登录

claude mcp logout <name>清除已存储的凭证。

预配置

有些MCP服务不支持OAuth动态注册,需要预先配置凭证。

示例代码:

1
2
3
claude mcp add --transport http \
--client-id <ID> --client-secret --callback-port 8080 \
my-server https://internal.example.com/mcp

注意:--client-secret不直接跟值,命令会提示输入,避免密钥留在shell历史里。

自定义认证

headersHelper字段指向一个脚本,由脚本动态生成请求头。

上文的《第三步:接公司内部API》就是这种方式。

权限与命名

工具规范名

每台MCP服务的每个工具,在ClaudeCode里都有一个规范名,模式为mcp__<server_name>__<tool_name>
例如GitHub MCP服务的create_issue工具就是mcp__github__create_issue
MCP服务名与工具名中不属于A-Za-z0-9_-的字符会被替换为_

这个命名空间可以直接用在权限规则里:写完整工具名精确控制单个工具,写mcp__<server>__*通配整台MCP服务。示例代码:

1
2
3
4
5
6
{
"permissions": {
"allow": ["mcp__github__*"],
"deny": ["mcp__dangerous_server__*"]
}
}

权限规则的通用语法、六种模式与deny>ask>allow的优先级见《1.Start》,本节只是MCP命名空间下的增量。

项目级MCP服务的批准

项目级.mcp.json来自仓库、可能由别人提交,所以其中的MCP服务首次使用前需要我们显式批准,未批准的会显示为"Pending approval"。
在交互式claude会话里完成确认即可。
需要重新决定时,用claude mcp reset-project-choices整体重置批准状态。

文章作者: Kaka Wan Yifan
文章链接: https://kakawanyifan.com/12806X
版权声明: 本博客所有文章版权为文章作者所有,未经书面许可,任何机构和个人不得以任何形式转载、摘编或复制。

留言板