Claude Code 接 MCP 服务器实战:接一个现成的,自己写一个,再分享给团队
MCP 让 Claude Code 用到内置工具以外的东西:查文档、查工单、查数据库。本站实测了三件事:一条命令接上官方的文档服务器;用三十多行代码写一个自己的服务器并接上;改成项目级配置给团队共用,以及第一次打开时的批准提示。附每一步的真实输出和排错办法。
本站已实测,测试日期:2026-10-11。
本页目录(10 节)
这篇教程解决一个问题:你要的信息不在代码仓库里,在别的系统里,怎么让 Claude Code 自己去拿。
官方文档给的判断标准很实用:当你发现自己总在把另一个工具里的内容复制到对话里,比如工单、监控面板、数据库里的数据,就该接一个 MCP 服务器了。接上之后,它可以直接读那个系统、在那个系统里操作,不用靠你粘贴。
MCP(Model Context Protocol)是一个开放的协议。提供工具的一方叫 MCP 服务器,可以是别人托管的一个网址,也可以是在你机器上跑的一个程序。
本站实测了三件事:接一个现成的,自己写一个,再把它分享给团队。
| 实测环境 | |
|---|---|
| 日期 | 2026-10-11 |
| 版本 | Claude Code 2.1.296,Node.js 22 |
| 系统 | Ubuntu 24.04 |
| 模型 | Opus 5.5,auto 模式 |
| 连接方式 | 通过酷站AI 中转站,不是直连官方 |
| 示例仓库 | Express 的源码,v5.3.0 |
第一件事:接一个现成的服务器
流程永远是三步:添加、检查、使用。官方的快速上手用的是 Claude Code 自己的文档服务器,它不需要登录,适合第一次试。
添加
在终端里运行,不是在 claude 会话里:
claude mcp add --transport http claude-code-docs https://code.claude.com/docs/mcp
| 部分 | 意思 |
|---|---|
--transport http |
这个服务器是一个网址,不是本地程序 |
claude-code-docs |
你给它起的名字,随便起。之后工具调用会用这个名字标注 |
| 最后的网址 | 服务器的地址 |
实测的输出:
Added HTTP MCP server claude-code-docs with URL: https://code.claude.com/docs/mcp to local config
File modified: /home/ccdemo/.claude.json [project: /home/ccdemo/demo/a2-express]
local config 的意思是:它只对你、只在这个项目里生效。
检查
claude mcp list
Checking MCP server health…
claude-code-docs: https://code.claude.com/docs/mcp (HTTP) - ✔ Connected
常见的几种状态,按官方文档:
| 状态 | 意思 |
|---|---|
✔ Connected |
可以用了 |
! Needs authentication |
服务器连得上,但要先登录或者提供 token |
✘ Failed to connect |
服务器没有响应 |
⏸ Pending approval |
项目级的服务器,你还没有批准。后面会碰到 |
想看某一个服务器的细节,用 claude mcp get claude-code-docs。
使用
启动 claude,点名让它用这个服务器:
用 claude-code-docs 这个服务器查一下 MCP_TIMEOUT 是做什么的,默认值是多少。
屏幕上的记录:
Called claude-code-docs (ctrl+o to expand)
● Let me check the env-vars page for the canonical definition.
Called claude-code-docs 4 times (ctrl+o to expand)
● 我用 claude-code-docs 服务器查过了,结论如下:
MCP_TIMEOUT 是做什么的
它是 MCP 服务器启动/连接的超时时间,单位是毫秒。服务器在这个时间内没连上,这次连接就算失败。……
- 调高连接上限:服务器启动慢的时候(比如 stdio 服务器第一次用 npx 下载包)用它把上限调高,
例如 MCP_TIMEOUT=60000 claude。(/en/mcp-quickstart、/en/mcp)
……
默认值:30 秒,也就是 30000 毫秒。
顺带一提:很多页面都链接到 /en/env-vars,但那个页面里我没搜到 MCP_TIMEOUT 这个条目。
Called claude-code-docs 这一行就是凭证:答案是通过这个服务器查来的,不是模型凭记忆答的。它一共调了五次,用了 1 分 13 秒,每条结论后面带着出处的页面。
两点说明:
- 平时不用点名。 官方文档说,Claude 会自己挑合适的工具。这里点名,是为了保证演示走的是新接的服务器。
- 这次没有弹出确认框。 我们在 auto 模式下,调用直接执行了。官方文档说第一次调用服务器时可能会问你要不要批准,在 Manual 模式下你会看到。
第二件事:自己写一个
现成的服务器不一定有你要的。你们团队内部的系统、一个只有你们在用的数据文件,都可以自己包一层。
我们写一个最小的例子:Express 的仓库里有一份 History.md,记着每个版本改了什么,近四千行。做一个服务器,提供一个工具:给一个版本号,返回那个版本的更新记录。
代码
建一个目录,装两个依赖:
mkdir express-history-mcp && cd express-history-mcp
npm init -y
npm pkg set type=module
npm install @modelcontextprotocol/server zod
实测装到的版本是 @modelcontextprotocol/server 2.3.1 和 zod 4.6.5。然后是 server.js,写法照 MCP TypeScript SDK 的说明:
// 一个最小的 MCP 服务器:从 Express 的 History.md 里取出某个版本的更新记录
import { readFileSync } from 'node:fs';
import { McpServer } from '@modelcontextprotocol/server';
import { StdioServerTransport } from '@modelcontextprotocol/server/stdio';
import * as z from 'zod/v4';
const historyFile = process.argv[2];
const server = new McpServer({ name: 'express-history', version: '1.0.0' });
server.registerTool(
'get_release_notes',
{
description: 'Return the changelog entries for one Express version from History.md, for example "5.1.0".',
inputSchema: z.object({ version: z.string().describe('Version number, like 5.1.0') })
},
async ({ version }) => {
// History.md 的格式:一行版本号,下一行是一串等号,然后是条目,直到下一个版本号
const lines = readFileSync(historyFile, 'utf8').split('\n');
const isRule = (l) => /^=+$/.test(l || '');
const start = lines.findIndex((l, i) => l.startsWith(version) && isRule(lines[i + 1]));
if (start === -1) {
return { content: [{ type: 'text', text: `History.md 里没有找到 ${version}` }], isError: true };
}
let end = lines.length;
for (let i = start + 2; i < lines.length - 1; i++) {
if (isRule(lines[i + 1])) { end = i; break; }
}
return { content: [{ type: 'text', text: lines.slice(start, end).join('\n').trim() }] };
}
);
await server.connect(new StdioServerTransport());
一个工具由四样东西组成:
| 部分 | 作用 |
|---|---|
名字 get_release_notes |
工具的标识 |
description |
写给模型看的。它靠这句话判断什么时候该用这个工具,所以要写清楚能做什么 |
inputSchema |
参数的类型和说明 |
| 处理函数 | 真正干活的代码,返回一段文字 |
最后一行让它通过标准输入输出和 Claude Code 通信。这种在本机启动、通过标准输入输出通信的服务器叫 stdio 服务器。
接上
claude mcp add express-history -- node /home/ccdemo/demo/c3-history-mcp/server.js /home/ccdemo/demo/a2-express/History.md
和上一个例子有两处不同:没有 --transport,因为本地服务器用的是默认的 stdio;-- 后面的全部内容,就是 Claude Code 用来启动这个服务器的命令。
Added stdio MCP server express-history with command: node /home/ccdemo/demo/c3-history-mcp/server.js
/home/ccdemo/demo/a2-express/History.md to local config
claude mcp list 显示两个都连上了:
claude-code-docs: https://code.claude.com/docs/mcp (HTTP) - ✔ Connected
express-history: node /home/ccdemo/demo/c3-history-mcp/server.js /home/ccdemo/demo/a2-express/History.md - ✔ Connected
官方文档提醒了一点:Added 只说明配置存下来了,不代表命令跑得起来,所以一定要 list 看一眼。用 npx 启动的服务器,第一次检查可能显示连接失败,那是包还在下载,等一下再查。
使用
用 express-history 查一下 5.2.0 这个版本改了什么,用三句话以内概括。
12 秒:
Called express-history (ctrl+o to expand)
● Express 5.2.0 修复了一个安全漏洞 CVE-2024-51999(GHSA-pj86-cfqh-vqx6),并把依赖 body-parser 升到了
^2.2.1。另外,现在 res.redirect 收到 undefined 作为状态码或 URL 时会发出弃用警告,方便找到并修掉这类调用。
我们对照了 History.md 里 5.2.0 那一节:三条记录,它概括的三点和原文一一对应。
这个例子很小,但套路是通用的:把“读文件”换成查你们的内部接口、查数据库,就是一个真正有用的工具。
第三件事:分享给团队
服务器的配置存在哪
claude mcp add 有三种范围,用 --scope 指定:
| 范围 | 存在哪 | 谁能用 |
|---|---|---|
local(默认) |
~/.claude.json 里这个项目的条目下 |
只有你,只在这个项目 |
project |
项目根目录的 .mcp.json |
克隆这个项目的每个人 |
user |
~/.claude.json 顶层的 mcpServers |
只有你,所有项目 |
范围在添加时就定了。要换,就先删再加。
改成项目级
claude mcp remove express-history -s local
claude mcp add --scope project express-history -- node /home/ccdemo/demo/c3-history-mcp/server.js /home/ccdemo/demo/a2-express/History.md
项目根目录多了一个 .mcp.json:
{
"mcpServers": {
"express-history": {
"type": "stdio",
"command": "node",
"args": [
"/home/ccdemo/demo/c3-history-mcp/server.js",
"/home/ccdemo/demo/a2-express/History.md"
],
"env": {}
}
}
}
这个文件可以提交进仓库。也可以不用命令,直接手写它;网址类的服务器写成 "type": "http" 加一个 "url"。
要注意:我们的例子里写的是绝对路径,换一台机器就不对了。真要给团队共用,得换成每个人机器上都成立的写法,比如用 npx 启动一个发布了的包,或者用托管的网址。
第一次打开时的批准
这时再看 claude mcp list,状态变了:
express-history: node /home/ccdemo/demo/c3-history-mcp/server.js … - ⏸ Pending approval (run `claude` to approve)
启动 claude,先出来的是一个提示:
New MCP server found in this project: express-history
MCP servers may execute code or access system resources. All tool calls require approval.
Use this MCP server
Use this and all future MCP servers in this project
❯ Continue without using this MCP server
默认选中的是“不使用”。 这是有意的设计。官方文档解释:这个提示是为了让你克隆下来的仓库不能未经你同意就在你的机器上启动程序。
所以反过来,克隆了别人的仓库、看到这个提示时,先去看一眼 .mcp.json 里要运行的是什么命令,再决定选哪个。第二项“这个项目以后的服务器都用”要更慎重。
批准之后,在会话里输入 /mcp,可以看到两个服务器各自的来源:
Manage MCP servers
2 servers
Project MCPs (/home/ccdemo/demo/a2-express/.mcp.json)
❯ ✔ express-history 1 tool
Local MCPs (/home/ccdemo/.claude.json [project: /home/ccdemo/demo/a2-express])
✔ claude-code-docs 3 tools
/mcp 面板里也可以重新连接、登录。
要登录的服务器
上面两个都不需要登录。实际工作里接的多半是要登录的。这一节我们没有实测,按官方文档写。
用浏览器登录的(OAuth),比如 Sentry、Linear、Notion。先添加:
claude mcp add --transport http sentry https://mcp.sentry.dev/mcp
这时 list 会显示 ! Needs authentication,是正常的。启动会话,输入 /mcp,选中这个服务器,选 Authenticate,在打开的浏览器里完成登录。
用 token 的,比如 GitHub。文档给的例子是生成一个细粒度的个人访问令牌,只给它你想让 Claude 处理的那几个仓库的权限,然后:
claude mcp add --transport http github https://api.githubcopilot.com/mcp/ \
--header "Authorization: Bearer YOUR_GITHUB_PAT"
文档提醒:add 命令不会验证凭据,填个占位符也能添加成功,之后才会连接失败。所以加完还是要检查状态。
数据库。 文档举的例子是 DBHub 这个服务器,通过连接串接上数据库,并且特别强调:连接串里用一个只读的数据库用户,这样它跑的查询改不了数据。
本站补充一条:带 token 或密码的配置,不要用 --scope project 写进会提交的 .mcp.json。
它占多少上下文
接上服务器不是没有代价的。在会话里运行 /context,接着文档服务器的时候是这样:
⛁ MCP tools: 2.1k tokens (0.2%)
⛁ MCP server instructions: 319 tokens (0.0%)
MCP tools · /mcp
├ mcp__claude-code-docs__query_docs_filesystem_claude_code_docs: 1.3k tokens
├ mcp__claude-code-docs__search_claude_code_docs: 397 tokens
└ mcp__claude-code-docs__submit_feedback: 344 tokens
一个只有 3 个工具的服务器,占了两千多 token,每个会话都要带着。这里也能看到工具的完整名字,格式是 mcp__服务器名__工具名,写权限规则时用的就是这个名字。
官方文档的建议是:不用的服务器删掉,把这块空间腾出来。文档另一处还提到,工具的定义默认是按需加载的,没用到时只有工具名和服务器的说明占上下文。这和我们看到的数字怎么对应,没有进一步核对。
连不上怎么办
按官方文档,先用 claude mcp list 或者会话里的 /mcp 看状态,再对症处理。
/mcp 显示没有配置任何服务器。 最常见的三个原因:
- 你是在另一个项目里运行的
claude mcp add。local范围的服务器只在添加它的那个项目里有效。回到那个项目重新加,或者用--scope user。 - 你把配置写到了错误的路径。正确的只有两个:
~/.claude.json和项目根目录的.mcp.json。~/.claude/mcp.json、~/.claude/.mcp.json这些路径 Claude Code 是不读的。 .mcp.json里有一条写错了。它会跳过那一条,其余的照常加载;claude mcp list会给出解析警告,指出是哪个字段。
显示 Failed to connect。 先看状态后面附带的错误信息,claude mcp get 名字 也会显示服务器返回的 HTTP 状态码和错误文字,往往直接说明了问题,比如缺了请求头、token 被拒。对网址类的服务器,可以用 curl -I 网址 确认从你的机器上访问得到。
启动慢导致超时。 用环境变量 MCP_TIMEOUT 把启动的超时调高,单位是毫秒,比如 MCP_TIMEOUT=60000 claude。
用完清理
claude mcp remove express-history -s project
claude mcp remove claude-code-docs -s local
再运行 claude mcp list,显示的是:
No MCP servers configured. Use `claude mcp add` to add a server.
MCP、skill、hook 怎么分
| 你想要的 | 用什么 |
|---|---|
| 让它能访问一个外部系统:工单、数据库、内部接口 | MCP |
| 教它一套做事的步骤 | skill |
| 保证某个动作每次都发生 | hook |
skill 的写法见Claude Code skills 怎么写,hook 见Claude Code Hooks 实战。
这一趟花了多少
用自己写的服务器查那一次,/cost 显示 0.20 美元,模型工作 12 秒。查文档那一次调了五次工具,用了 1 分 13 秒,花费没有单独记。这些是 Claude Code 按官方价格估算的数字,不是中转站实际扣的金额。
这次实测没有覆盖到的
- 要登录的服务器没有实测。 OAuth、GitHub 的 token、数据库这几节按官方文档写的。
- 官方快速上手里的 Playwright 服务器没有测。 它要驱动一个浏览器,我们的服务器没有图形界面。
- Manual 模式下第一次调用工具的确认框没有看到。 我们全程在 auto 模式。
- 只在终端里测了。 桌面应用、VS Code 里添加服务器各有自己的界面。
- 自己写的那个服务器只是演示。 它没有处理文件不存在这类异常,也没有考虑一个版本号前缀匹配到多个版本的情况。