引子
在2024年的年初,我们使用Cursor的时候,我们可能会感觉Cursor写后端比写前端厉害,即使后端的逻辑比前端复杂多了。
因为,那时候Cursor可以读取后端的输入、输出、甚至访问数据库(我们把数据库连接给它,它自己安装Shell工具去读);但是,那时候Cursor访问不了前端。
如果页面效果不是我们想要的,我们只能截图给他(但是他图片理解能力又不强),或者只能我们口述页面效果哪里哪里不对(又讲不清)。
这个问题的根源,不是模型不够聪明,也不是上下文被污染了。
是因为,那时候Cursor调用工具的能力,无法调用浏览器看网页效果。
那么,如何拓展ClaudeCode调用工具的能力?内置工具够不着的外部系统,怎样安全地接进工具调用循环?
外部系统和ClaudeCode约定一个标准协议,外部系统按协议把能力暴露出来,ClaudeCode按协议接入。
这就是MCP。
- 官方文档:https://code.claude.com/docs/en/mcp
- 快速开始:https://code.claude.com/docs/en/mcp-quickstart
- 协议规范:https://modelcontextprotocol.io/
原理
什么是MCP
MCP(Model Context Protocol,模型上下文协议),一个开源标准协议。
外部系统实现一个MCP服务,把自己的能力以标准形式暴露出来;ClaudeCode作为MCP客户端接入外部系统。
这样在工具调用循环里就多了一批可调用的能力。
MCP服务的三类能力
MCP服务有三类能力,在ClaudeCode中各有对应的入口:
| 能力 | 是什么 | 作用 | 在ClaudeCode中的入口 |
|---|---|---|---|
| Tools(工具) | 供Claude调用的可执行函数,如查询数据、调用API | 覆盖绝大多数场景 | 进入工具调用循环,与内置工具一样被自动选用,规范名为mcp__<server>__<tool> |
| Resources(资源) | 可按需读取的数据实体,如一条Issue、一个文件 | 把一份外部数据精确拉进上下文 | 会话中用@server:scheme://id引用,如@github:issue://123 |
| Prompts(提示) | MCP服务预置的提示模板 | 把MCP服务作者写好的任务模板变成一条斜杠命令 | 成为斜杠命令/mcp__server__name,如/mcp__github__list_prs,提示名与MCP服务名中的空格会转换为下划线 |
示例
需求
一个Web项目团队,要让ClaudeCode接入GitHub、项目数据库和公司内部API。
接GitHub
用HTTP传输加Bearer token。示例代码:
1 | claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \ |
该MCP服务提供了上文所述的三类能力:
- 让Claude"把刚才的报错整理成issue提交"走的是工具调用。
@github:issue://123把一条issue精确拉进上下文。/mcp__github__list_prs直接执行MCP服务预置的提示。
接项目数据库
用项目范围让全组共享。示例代码:
1 | claude mcp add --scope project \ |
解释说明:
--scope project:把配置写进项目根目录的.mcp.json,提交后同事克隆仓库即用。--:之后是stdio MCP服务的启动命令。- 单引号:防止Shell在
add时抢先展开${DB_URL:-...},让它原样写进.mcp.json、留到运行时才按后文的环境变量展开规则取值,真实凭证不进仓库。
接公司内部API
手写.mcp.json配headersHelper。
示例代码:
1 | { |
解释说明:
headersHelper
指向的脚本在标准输出打印一个JSON对象作为附加请求头(如{"X-Token": "..."}),token的获取与刷新逻辑都在脚本里,配置文件中不出现任何凭证。timeout
超时时间30秒。alwaysLoad
该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 常用参数
我们重点讨论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凭证,见下文认证一节 |
transport 传输方式
--transport参数,传输方式。
| 传输 | 用途 | 特点 | 认证方式 |
|---|---|---|---|
| HTTP | 远程托管MCP服务(推荐) | 标准请求响应,可靠性高 | OAuth、Bearer token、headersHelper |
| SSE | 远程托管(已废弃) | Server-Sent Events单向推送,仅为兼容旧配置保留 | 静态header |
| stdio | 本地进程 | 以子进程方式启动本地程序,可访问本地文件与数据库socket | 环境变量、本地权限 |
| WebSocket | 持久连接、事件推送 | 双向通信,不支持OAuth | 静态header、headersHelper |
选型准则:
- 本地进程选stdio
- 远程一律HTTP(SSE只在迁移旧配置时会遇到)
- WebSocket留给需要持久双向连接的场景。
scope 配置范围
--scope,配置范围,包括存储位置和生效范围。
| 范围 | 存储位置 | 生效范围 | 进版本库 |
|---|---|---|---|
| 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 | { |
主要字段
| 字段 | 适用传输 | 说明 |
|---|---|---|
type |
全部 | http、sse、stdio、ws之一 |
url |
HTTP/SSE/WS | MCP服务端点 |
headers |
HTTP/SSE/WS | 静态请求头 |
headersHelper |
HTTP/WS | 指向一个脚本,运行时用其输出作为请求头,见下文认证一节 |
oauth |
HTTP | 预配置OAuth:clientId、callbackPort、scopes、authServerMetadataUrl |
command、args、env |
stdio | 本地进程的启动命令、参数与环境变量 |
timeout |
全部 | 超时,毫秒 |
alwaysLoad |
全部 | 跳过工具延迟加载,见下文性能一节 |
注意事项
- 配置值支持环境变量展开。
${VAR}在运行时替换为环境变量值,${VAR:-default}在变量未设置时使用默认值。
这是把.mcp.json安全提交进仓库的关键。(例如,上文的例子只留${GITHUB_TOKEN}这样的引用,真实凭证在每个人自己的环境变量里。) .mcp.json在会话启动时一次性读取,改动配置后必须重启会话才生效。
认证
标准OAuth流程
会话内操作
操作方法:会话内运行/mcp,选中需要认证的MCP服务,执行Authenticate。
会打开浏览器,浏览器完成登录后,token由ClaudeCode保存并自动刷新。
在SSH或没有图形界面的机器,会给一个URL,让我们在别处完成登录。
这个认证方式,很像我们在ClaudeCode上的"Claude account with subscription"认证方式。
命令行操作
也可以直接在命令行认证:claude mcp login <name>,在SSH或没有图形界面的机器上加--no-browser。
预配置
有些MCP服务不支持OAuth动态注册,需要预先配置凭证。
示例代码:
1 | claude mcp add --transport http \ |
注意:--client-secret不直接跟值,命令会提示输入,避免密钥留在shell历史里。
自定义认证
用headersHelper字段指向一个脚本,由脚本动态生成请求头。
上文的《接公司内部API》就是这种方式。
工具规范名
每台MCP服务的每个工具,在ClaudeCode里都有一个规范名,模式为mcp__<server_name>__<tool_name>。
例如GitHub MCP服务的create_issue工具就是mcp__github__create_issue。
MCP服务名与工具名中不属于A-Z、a-z、0-9、_、-的字符会被替换为_。
这个命名空间可以直接用在权限规则里:写完整工具名精确控制单个工具,写mcp__<server>__*通配整台MCP服务。
示例代码:
1 | { |
权限规则的通用语法、六种模式与deny > ask > allow的优先级参考《1.Start》。
关注性能
- 工具延迟加载(默认启用)
启动时只加载服务器名与说明,具体的工具定义在需要时才查询。
这使得配置大量服务器也不会把上下文成本抬高。
加载策略由环境变量ENABLE_TOOL_SEARCH控制。 alwaysLoad
对少数关键服务器,在配置中设"alwaysLoad": true,其工具定义始终加载,跳过按需查询。- 输出上限
MCP工具单次返回超过10000tokens会触发警告,上限可用环境变量MAX_MCP_OUTPUT_TOKENS调整。
注意安全
- 信任问题
MCP服务器有权访问Claude会话中的全部内容与工具结果,接入一台服务器等于把会话敞开给它,只连接我们信任的服务器。 - 凭证安全
OAuth token由ClaudeCode自动刷新,存储在系统密钥链(macOS)或凭证文件(Windows/Linux)中,不落入项目目录。
静态Bearer token一旦明文写进.mcp.json,就会随仓库提交而泄露。敏感值按上文的${VAR}约定引用环境变量,或改用headersHelper动态获取,不要硬编码。 - 提示注入风险
MCP服务器返回的内容会进入Claude的上下文,恶意服务器可以在返回数据里夹带指令(如"忽略之前的所有指令")。