2026 年,Model Context Protocol(MCP)已成为 AI 工具集成的事实标准。它允许大模型通过标准化接口调用外部工具、读取文件、操作数据库——而 Claude Code 在这一生态中扮演着独特的角色:它既可以作为 MCP 客户端,也可以作为 MCP 服务器向其他工具暴露能力。
本文将从零开始,带你完整走通"用 Claude Code 构建 MCP 服务器"的全流程,包括环境搭建、服务端启动、客户端接入、自定义工具开发,以及常见坑点排查。无论你是想把 Claude Code 的能力暴露给 Cursor、Windsurf,还是想自己搭一套 AI Agent 编排框架,这篇教程都能给你扎实的基础。
一、MCP 核心概念与双重身份
在深入操作之前,先把 MCP 的核心模型搞清楚,能省掉很多走弯路的时间。
MCP 的三层架构
MCP 协议定义了三个角色:
- MCP Host(宿主):发起连接的应用程序,如 Claude Desktop、Cursor、Windsurf。Host 里运行着 LLM,负责决定何时调用工具。
- MCP Client(客户端):内嵌在 Host 里的协议实现层,负责与 Server 通信。
- MCP Server(服务器):独立进程,暴露 Tools(工具)、Resources(资源)、Prompts(提示词)三类能力。
claude mcp serve 就能让它以服务端模式启动。Claude Code 的双重身份
Claude Code 的独特之处在于它同时具备两种身份:
作为 MCP Client
- 连接外部 MCP Server
- 调用数据库、JIRA、GitHub 等工具
- 通过
claude mcp add添加服务
作为 MCP Server
- 暴露 Bash 执行、文件读写等能力
- 运行
claude mcp serve启动 - 供 Cursor、Windsurf 等工具接入
重要的是,这两种身份是完全隔离的。当 Claude Code 作为 MCP Server 运行时,它并不会把自己正在连接的其他 MCP Server 的能力透传给上游 Host——每一层的 MCP 连接都是独立的进程边界,保证安全隔离。
三种传输方式
| 传输方式 | 适用场景 | 特点 |
|---|---|---|
stdio |
本地工具集成 | 最简单,无网络暴露,进程隔离 |
HTTP + SSE |
远程服务 | 支持多客户端,需要网络配置 |
Streamable HTTP |
云端部署 | 2025年新规范,推荐用于云服务 |
本文主要讲解最常用的 stdio 模式,这也是 claude mcp serve 默认使用的传输方式。
二、环境准备与依赖安装
正式开始之前,确认你的机器满足以下前提条件:
- 操作系统:macOS 或 Linux(Claude Desktop 目前不支持 Linux,但 Claude Code MCP Server 本身支持)
- Node.js 20+(推荐用 nvm 管理版本)
- 有效的 Anthropic API Key,或已登录 Claude 账号
如果你还没有安装 nvm,先安装它,然后用它管理 Node 版本:
# 安装 nvm
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash
# 重新加载 shell 配置
source ~/.bashrc # 或 source ~/.zshrc
# 安装并使用最新 LTS Node
nvm install --lts
nvm use --lts
# 验证版本(需要 >= 20)
node --version
Claude Code 通过 npm 分发,全局安装后即可在任意目录使用:
npm install -g @anthropic-ai/claude-code
# 验证安装
claude --version
command not found: claude,需要将 npm 全局 bin 目录加入 PATH。运行 npm config get prefix 查看路径,然后将 <prefix>/bin 加入 ~/.zshrc 或 ~/.bashrc。在作为 MCP Server 使用之前,必须至少运行一次带有 --dangerously-skip-permissions 标志的命令来完成认证和接受权限协议。这一步是无头(headless)MCP 服务端模式正常运行的前提:
# 首次运行,完成登录和权限初始化
# 注意:这会打开浏览器进行 OAuth 认证
claude --dangerously-skip-permissions "echo hello"
三、启动 Claude Code 作为 MCP 服务端
环境就绪后,用一条命令就能把 Claude Code 变成 MCP 服务器:
claude mcp serve
服务器启动后会监听 stdin,等待来自 MCP 客户端的 JSON-RPC 2.0 消息。它暴露的核心工具包括:
| 工具名 | 功能描述 | 典型用途 |
|---|---|---|
Bash |
执行 shell 命令 | 运行测试、构建、部署 |
Read |
读取文件内容 | 查看源码、配置文件 |
Write |
写入文件 | 创建、覆盖文件 |
Edit |
精确字符串替换 | 修改代码片段 |
Glob |
文件模式匹配 | 查找特定后缀文件 |
Grep |
内容搜索(ripgrep) | 全局代码搜索 |
Agent |
启动子 Agent | 复杂任务分解编排 |
手动测试 MCP 通信
可以用 @modelcontextprotocol/inspector 工具可视化测试 Server:
# 安装 MCP Inspector
npx @modelcontextprotocol/inspector claude mcp serve
浏览器会打开 Inspector UI,你可以在里面直接调用各个工具、查看返回的 JSON 响应,非常直观。
四、配置 MCP 客户端接入
服务端准备好了,下一步是让 MCP 客户端(Claude Desktop、Cursor 等)接入它。不同客户端的配置文件路径略有不同,但格式都是统一的 JSON。
Claude Desktop 接入配置
配置文件路径:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"claude-code": {
"command": "claude",
"args": ["mcp", "serve"],
"env": {}
}
}
}
Cursor 接入配置
在 Cursor 的设置里找到 MCP 配置,或直接编辑项目根目录下的 .cursor/mcp.json:
{
"mcpServers": {
"claude-code": {
"command": "claude",
"args": ["mcp", "serve"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-..."
}
}
}
}
多项目隔离配置
如果你有多个项目,可以为每个项目配置不同工作目录的 Server 实例:
{
"mcpServers": {
"project-frontend": {
"command": "claude",
"args": ["mcp", "serve"],
"cwd": "/Users/me/projects/my-frontend"
},
"project-backend": {
"command": "claude",
"args": ["mcp", "serve"],
"cwd": "/Users/me/projects/my-backend"
}
}
}
五、构建自定义 MCP 工具服务器
前面的步骤让你能使用 Claude Code 内置的工具集。但 MCP 的真正威力在于:你可以用 TypeScript 或 Python 快速编写自己的工具服务器,给 Claude 扩展任何领域的能力——无论是查数据库、调内部 API,还是执行业务逻辑。
下面我们用官方的 TypeScript SDK 实现一个真实的工具服务器。以一个"代码质量检查工具"为例,它能调用 ESLint 并返回格式化后的结果。
mkdir my-mcp-server && cd my-mcp-server
npm init -y
# 安装 MCP SDK 和必要的依赖
npm install @modelcontextprotocol/sdk zod
# TypeScript 支持
npm install -D typescript @types/node tsx
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true
},
"include": ["src/**/*"]
}
创建 src/index.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { execSync } from "child_process";
import { readFileSync, existsSync } from "fs";
import { resolve } from "path";
// 创建 MCP Server 实例
const server = new McpServer({
name: "code-quality-server",
version: "1.0.0",
});
// ── 工具 1:ESLint 检查 ──
server.tool(
"lint_file",
"对指定文件运行 ESLint 检查,返回格式化后的 lint 结果",
{
file_path: z.string().describe("要检查的文件路径(相对或绝对路径)"),
fix: z.boolean().optional().describe("是否自动修复可修复的问题,默认 false"),
},
async ({ file_path, fix = false }) => {
const absPath = resolve(file_path);
if (!existsSync(absPath)) {
return {
content: [{ type: "text", text: `错误:文件不存在 ${absPath}` }],
isError: true,
};
}
try {
const fixFlag = fix ? "--fix" : "";
const result = execSync(
`npx eslint ${fixFlag} --format=compact "${absPath}"`,
{ encoding: "utf-8", stdio: ["pipe", "pipe", "pipe"] }
);
return {
content: [{ type: "text", text: result || "✓ 没有发现 lint 错误" }],
};
} catch (err: any) {
// ESLint 发现问题时会以非零退出码退出,stdout 里有结果
return {
content: [{ type: "text", text: err.stdout || err.message }],
};
}
}
);
// ── 工具 2:读取 package.json 依赖信息 ──
server.tool(
"get_dependencies",
"读取当前项目的 package.json,返回依赖列表和版本信息",
{
project_path: z.string().optional().describe("项目路径,默认当前目录"),
type: z
.enum(["all", "dependencies", "devDependencies"])
.optional()
.describe("依赖类型,默认 all"),
},
async ({ project_path = ".", type = "all" }) => {
const pkgPath = resolve(project_path, "package.json");
if (!existsSync(pkgPath)) {
return {
content: [{ type: "text", text: `未找到 package.json: ${pkgPath}` }],
isError: true,
};
}
const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
const result: Record = { name: pkg.name, version: pkg.version };
if (type === "all" || type === "dependencies") {
result.dependencies = pkg.dependencies || {};
}
if (type === "all" || type === "devDependencies") {
result.devDependencies = pkg.devDependencies || {};
}
return {
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
};
}
);
// ── 启动服务 ──
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Code Quality MCP Server running on stdio");
}
main().catch((err) => {
console.error("Fatal error:", err);
process.exit(1);
});
在 package.json 的 scripts 中添加:
{
"scripts": {
"build": "tsc",
"dev": "tsx src/index.ts"
},
"type": "module"
}
# 编译 TypeScript
npm run build
# 验证构建产物
ls build/
npm run build,否则 MCP 客户端启动时会找不到入口文件。这是最常见的新手坑。将你的自定义 Server 添加到 Claude Desktop 配置:
{
"mcpServers": {
"code-quality": {
"command": "node",
"args": ["/absolute/path/to/my-mcp-server/build/index.js"]
}
}
}
重启 Claude Desktop,然后在对话框里试用:"帮我检查 src/utils.ts 的 lint 问题"。
FastMCP 库(pip install mcp),用装饰器声明工具,代码量更少。TypeScript SDK 适合需要类型安全的团队项目,Python 适合快速原型。六、常见问题排查指南
在实际接入过程中,有几类问题出现频率极高。下面按症状分类给出排查步骤:
npm config get prefix 获取全局安装路径,然后把 <prefix>/bin 加入 PATH:echo 'export PATH="$(npm config get prefix)/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
claude --dangerously-skip-permissions "echo test"。
,} 或 ,])。推荐用 jsonlint 校验:cat claude_desktop_config.json | npx jsonlint。
err.message 以 isError: true 的形式返回,方便调试。
command 指定的可执行文件是否存在(用绝对路径更稳定);③ 是否完全退出并重启了 Claude Desktop(不是刷新,要彻底关闭重开)。
console.error("debug info"),而不是 console.log。
查看 Claude Desktop 日志
当问题不明显时,查看 MCP 运行日志是最有效的手段:
# 查看 Claude Desktop 的 MCP 日志
tail -f ~/Library/Logs/Claude/mcp*.log
七、进阶:多实例编排与工作流集成
掌握基础配置后,下面介绍几种在生产环境中真正发挥 MCP 威力的进阶模式。
模式一:Plan → Execute → Verify 工作流
这是 Claude Code 官方推荐的高效协作模式:
- Plan:用
/plan命令让 Claude 先分解任务,生成可审阅的步骤列表 - Execute:审核 Plan 后批准执行,Claude 通过 MCP 工具完成各步骤
- Verify:用 Bash 工具跑测试,把失败信息直接 pipe 给 Claude 定位修复
.claude/settings.json 里设置权限白名单,可以精确控制 MCP Server 能执行哪些命令,避免高危操作的副作用。例如只允许读取、禁止删除文件。模式二:CLAUDE.md 项目上下文注入
在项目根目录创建 CLAUDE.md,每次启动会话时 Claude Code 会自动加载它,所有 MCP 工具调用都会带上这些上下文:
# Project: My SaaS Backend
## 技术栈
- Node.js + Fastify + TypeScript
- PostgreSQL(连接串在 .env 里)
- 测试框架:Vitest
## 编码规范
- 使用 Result 类型而非 throw 传递错误
- 所有数据库操作走 repository 层
- 新功能必须有对应的 .test.ts 文件
## 常用命令
- 跑测试:`npm test`
- 本地启动:`npm run dev`
- 数据库迁移:`npm run db:migrate`
模式三:多 Agent 编排
Claude Code 的 MCP Server 暴露了 Agent 工具,允许在任务执行中动态派生子 Agent。这使得复杂任务的并行处理成为可能:
# 在 Claude Desktop 里发送的 Prompt
请帮我同时做三件事:
1. 检查 src/ 目录下所有 TypeScript 文件的 lint 错误
2. 在 README.md 里更新 API 文档
3. 运行测试并报告覆盖率
请并行处理,不要等每步完成再开始下一步。
Token 消耗监控
长时间的 MCP 会话会积累大量上下文,影响速度和成本。养成这些习惯:
- 定期用
/cost命令查看当前会话的 Token 消耗 - 用
/compact压缩历史对话,保留核心摘要 - 用
/clear在切换任务时重置上下文 - 用
@path/file语法精确引用文件,而不是让 Claude 自己搜索
核心要点总结
- MCP 采用 Host / Client / Server 三层架构,通过 JSON-RPC 2.0 通信
- Claude Code 同时具备 MCP Client 和 MCP Server 两种身份,每层隔离
- 首次使用必须运行
--dangerously-skip-permissions完成权限初始化 claude mcp serve以 stdio 模式暴露 Bash、Read、Write 等核心工具- TypeScript SDK 或 FastMCP 可快速构建自定义工具服务器
- Server 代码绝对不能向 stdout 输出,日志必须写 stderr
- 多项目用不同
cwd的 Server 实例隔离,CLAUDE.md 注入项目上下文