第 15 章:MCP 协议与服务器
第 14 章结束时,我们提到一个关键问题:如何在保证安全的前提下,让 Claude Code 连接更广阔的外部世界? 文件系统和 Shell 命令已经覆盖了大量日常场景,但当 Claude 需要查阅最新的 React 文档、查询你的生产数据库、或者调用公司内部的 API 服务时,仅靠 Read/Write/Bash 是不够的。你需要一个标准化的扩展机制——这就是 MCP。
本章是第四篇"生态篇"的第一章,也是整个扩展体系的基石。MCP(Model Context Protocol)是 Claude Code 最核心的扩展机制,Plugins、Skills 甚至部分 Hooks 都建立在它的基础上。理解了 MCP,你就理解了 Claude Code 是如何"长出"新能力的。
本章目标:理解 MCP 协议的架构与工作原理,掌握配置 MCP 服务器的完整流程,能够使用 Context7 等常用 MCP 服务器,并具备开发简单自定义 MCP 服务器的能力。
15.1 什么是 MCP(Model Context Protocol)
MCP 的全称是 Model Context Protocol,由 Anthropic 于 2024 年底提出并开源。它是一个开放协议,定义了 AI 模型(如 Claude)与外部工具、数据源之间交互的标准方式。
一句话定义
MCP 是一套让 AI 安全地连接外部世界的标准接口协议。
如果把 Claude Code 比作一台电脑,那么 MCP 就是它的 USB-C 接口——统一的插拔标准,让任何符合协议的外部设备(服务器)都能即插即用。
为什么需要 MCP?
在没有 MCP 之前,如果你想让 Claude Code 查询某个数据库,你只能:
- 自己写一段脚本,把数据库内容导出为文件
- 让 Claude Code 读取这个文件
- Claude Code 分析后给出结论
- 如果数据库更新了,你要重新导出
这本质上是一个"数据搬运"的过程——你充当了 Claude Code 和外部世界之间的"人工适配器"。MCP 消除了这个中间人:Claude Code 通过 MCP 直接与数据库通信,实时获取数据,无需你的手动干预。
没有 MCP:
Claude Code → 只能操作文件 + Shell → 你手动搬运外部数据进来
有 MCP:
Claude Code → MCP 协议 → 数据库 / API / 文档 / 搜索 / 定制工具MCP 的三个核心角色
MCP 协议定义了三个角色,它们的关系类似于客户端-服务器架构:
Claude Code (MCP Client)
│
├── MCP Server 1: Filesystem(安全文件访问)
├── MCP Server 2: PostgreSQL(数据库查询)
├── MCP Server 3: Context7(实时文档查询)
└── MCP Server 4: Custom(你自定义的工具)| 角色 | 说明 | 示例 |
|---|---|---|
| MCP Client(客户端) | 发起请求的一方,通常是 AI 应用 | Claude Code、Claude Desktop、其他 AI Agent |
| MCP Server(服务器) | 接收请求并提供能力的一方,是一个独立进程 | Context7 服务器、PostgreSQL 服务器、自定义服务器 |
| Resource(资源) | 服务器暴露的数据或功能 | 数据库表、API 端点、文件目录、工具函数 |
Claude Code 作为 Client,通过 MCP 协议发现和调用各个 Server 提供的工具和资源。每个 Server 是一个独立的进程,通过标准输入/输出(stdio)或 HTTP 与 Client 通信。
MCP 解决了什么核心问题
回顾第 10 章讲到的工具系统,Claude Code 内置了 Read、Write、Edit、Bash、WebSearch 等十几种工具。这些工具覆盖了"一个 AI 编程助手最常见的需求"。但现实世界的需求远超这十几种:
- 你的项目数据在 PostgreSQL 里,Claude 需要直接查表来分析数据关系
- 你在写 React 代码,需要查阅 React 19 的
use()hook 最新文档 - 你的公司有一个内部的 CI/CD 系统,你希望 Claude 能触发构建并查看结果
- 你需要 Claude 操作浏览器来验证前端页面的交互行为
这些需求都有一个共同特点:它们需要访问"文件系统和 Shell 之外"的世界。MCP 就是为这个场景设计的。它把"如何安全地让 AI 接触外部世界"这个复杂问题标准化了:
- 标准化:所有 MCP Server 遵循统一的协议,Claude Code 无需知道每个 Server 的内部实现
- 安全性:Server 是独立进程,权限隔离;你可以精确控制哪些 Server 被启用
- 可扩展性:任何人都可以编写 MCP Server,生态可以无限生长
- 可组合性:多个 MCP Server 可以同时运行,互不干扰,Claude Code 自动发现和调度
15.2 MCP 架构
MCP 的架构设计遵循经典的客户端-服务器模式,但在细节上有不少值得理解的设计决策。
整体架构
五个核心概念
MCP 协议定义了五个核心概念,理解它们就理解了整个协议:
1. Client(客户端)
Client 是协议的使用方。在 Claude Code 的场景中,Claude Code 本身就是 Client。它的职责包括:
- 服务发现:读取配置文件中定义的 MCP Server 列表,启动对应的 Server 进程
- 能力查询:向每个 Server 询问"你能提供哪些工具/资源/提示?"
- 请求路由:当 Claude 需要调用某个工具时,将请求路由到正确的 Server
- 结果聚合:收集各个 Server 的返回结果,统一呈现给 Claude 模型
2. Server(服务器)
Server 是一个独立的进程,实现了 MCP 协议的服务端。每个 Server 向 Client 暴露一组能力(工具、资源、提示)。Server 进程由 Client 启动和管理——当 Claude Code 启动时,它根据配置文件启动所有 MCP Server;当 Claude Code 退出时,这些 Server 进程也随之终止。
// 配置文件中定义一个 MCP Server
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["./mcp-server.js"]
}
}
}command + args 定义了启动这个 Server 的命令。Claude Code 会执行这个命令,启动一个子进程,然后通过 stdio 与它通信。
3. Transport(传输层)
传输层定义 Client 和 Server 之间如何交换数据。MCP 支持两种传输方式:
| 传输方式 | 场景 | 特点 |
|---|---|---|
| stdio | 本地 Server | 通过标准输入/输出通信,低延迟,无需网络。Server 以子进程方式运行 |
| HTTP(SSE) | 远程 Server | 通过 HTTP + Server-Sent Events 通信,Server 可以部署在远程机器上 |
绝大多数本地 MCP Server 使用 stdio 传输。HTTP 传输通常用于文档查询服务(如 Context7)或部署在服务器上的团队共享 MCP 服务。
4. Tool(工具)
Tool 是 MCP Server 暴露给 Client 的可执行操作。每个 Tool 有三个要素:
- name:工具名称,Client 用这个名称来调用它
- description:工具描述,Claude 模型根据描述来决定何时使用这个工具
- inputSchema:输入参数的 JSON Schema,定义了调用这个工具时需要传入哪些参数及其类型
举个实际的例子——Context7 MCP Server 暴露的"查询文档"工具:
{
"name": "query-docs",
"description": "检索并查询来自 Context7 的最新文档和代码示例",
"inputSchema": {
"type": "object",
"properties": {
"libraryId": {
"type": "string",
"description": "Context7 兼容的库 ID,如 '/mongodb/docs'"
},
"query": {
"type": "string",
"description": "需要帮助的问题或任务"
}
},
"required": ["libraryId", "query"]
}
}Claude 模型看到这个工具定义后,就会知道"当我需要查某个库的文档时,我可以调用 query-docs 工具,并传入库 ID 和问题"。
5. Resource(资源)与 Prompt(提示模板)
Resource 是 Server 暴露的数据,而非操作。例如:
- 一个数据库 Server 可能将每个数据表暴露为一个 Resource
- 一个文件系统 Server 可能将目录结构暴露为 Resource
- Claude 可以通过
resources/read请求来获取 Resource 的内容
Prompt 是 Server 提供的提示模板。Server 可以说"我有一个名为 code-review 的 Prompt 模板,建议用户在审查代码时使用"。当用户选择这个 Prompt 时,Server 返回一段结构化的提示文本,供 Claude 参考。
在 Claude Code 的实际使用中,Tool 是 MCP 最重要、最常用的能力。Resource 和 Prompt 在特定场景下有用,但绝大多数 MCP Server 的核心价值体现在它们提供的 Tool 上。
服务发现与调用流程
Claude Code 是如何"发现"并使用 MCP 工具的?整个流程分为启动和运行时两个阶段:
启动阶段:
1. Claude Code 启动
2. 读取 settings.json 中的 mcpServers 配置
3. 为每个配置的 Server 启动子进程
4. 向每个 Server 发送 tools/list 请求
5. 收集所有 Server 返回的工具列表
6. 将所有工具合并到 Claude Code 的工具注册表中运行时(当 Claude 需要调用某个 MCP 工具时):
1. Claude 模型判断需要调用某个工具(如 Context7 的 query-docs)
2. Claude Code 识别该工具属于哪个 MCP Server
3. Claude Code 向该 Server 发送 tools/call 请求(包含工具名和参数)
4. Server 执行操作,返回结果
5. Claude Code 将结果传递给 Claude 模型
6. Claude 模型基于结果继续推理或执行下一步这个流程对用户完全透明——你不需要手动指定"请使用 Context7 服务器",你只需要说"帮我查一下 React 19 的 use() hook",Claude 会自动判断这个需求最适合使用哪个工具。
15.3 配置 MCP 服务器
理解了架构之后,来看如何实际配置 MCP 服务器。配置的核心是在 settings.json 的 mcpServers 字段中定义服务器列表。
配置位置
MCP 服务器可以在两个层级配置:
| 配置位置 | 作用域 | 适用场景 |
|---|---|---|
~/.claude/settings.json(全局) | 所有项目 | 通用工具:Context7 文档查询、网络搜索等 |
.claude/settings.json(项目) | 当前项目 | 项目专用工具:连接项目数据库、项目特定的 API |
全局 MCP Server 对所有项目生效,适合文档查询、网络搜索等通用能力。项目级 MCP Server 仅对当前项目生效,适合数据库连接、内部 API 等与项目强绑定的工具。
基本的 stdio 配置
大多数 MCP Server 以 stdio 方式运行——也就是通过命令行启动一个子进程。配置格式如下:
{
"mcpServers": {
"my-database": {
"command": "node",
"args": ["./mcp-servers/db-server.js"],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/mydb"
}
}
}
}逐字段说明:
| 字段 | 必填 | 说明 |
|---|---|---|
command | ✅ | 启动 Server 进程的命令(如 node、npx、python、uvx) |
args | ✅ | 命令行参数数组。第一个参数通常是入口文件或包名 |
env | ❌ | 传递给 Server 进程的环境变量。适合传递数据库连接字符串、API 密钥等 |
cwd | ❌ | Server 进程的工作目录。默认为项目根目录 |
HTTP 配置
对于远程 MCP 服务器,使用 HTTP 传输:
{
"mcpServers": {
"context7": {
"type": "http",
"url": "https://mcp.context7.com/sse"
}
}
}HTTP 配置的关键字段:
| 字段 | 说明 |
|---|---|
type | 固定为 "http" |
url | MCP Server 的 SSE 端点 URL |
headers | 可选的 HTTP 请求头(如认证 Token) |
通过 npx 启动(推荐方式)
对于 Node.js 生态的 MCP Server,推荐使用 npx 启动——无需预先安装,自动下载和缓存:
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"postgres": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-postgres", "postgresql://localhost/mydb"]
},
"playwright": {
"command": "npx",
"args": ["-y", "@playwright/mcp"]
}
}
}-y 参数表示自动确认安装(不需要手动输入 y)。首次启动时 npx 会下载对应的包,后续启动会使用缓存,速度很快。
对于 Python 生态的 MCP Server,推荐使用 uvx(类似 npx 的 Python 工具运行器):
{
"mcpServers": {
"my-python-server": {
"command": "uvx",
"args": ["my-mcp-server"]
}
}
}enableAllProjectMcpServers 设置
enableAllProjectMcpServers 是一个重要的安全设置,控制在进入项目时是否自动启用项目配置中的所有 MCP Server:
{
"enableAllProjectMcpServers": false
}| 值 | 行为 |
|---|---|
true | 进入项目时自动启动所有项目 MCP Server |
false(默认) | 需要手动确认后才启动项目 MCP Server |
安全考虑:这个设置默认为 false 是有原因的。MCP Server 本质上是可执行程序——如果克隆了一个恶意项目,项目的 .claude/settings.json 中可能配置了会执行危险操作的 MCP Server。保持此设置为 false,Claude Code 会在启动项目 MCP Server 前提示你确认。
第 14 章花了大量篇幅讲权限和安全。MCP Server 的"自动启用"设置正是权限体系在扩展生态中的体现——deny 规则阻止危险操作,而
enableAllProjectMcpServers阻止危险的自动连接。两层防线,互不替代。
完整配置示例
一个结合了全局和项目级的完整 MCP 配置:
// ~/.claude/settings.json(全局配置)
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
},
"brave-search": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-brave-search"],
"env": {
"BRAVE_API_KEY": "your-brave-api-key"
}
}
},
"enableAllProjectMcpServers": false
}// .claude/settings.json(项目配置,提交 Git)
{
"mcpServers": {
"project-database": {
"command": "node",
"args": [".mcp/postgres-server.js"],
"env": {
"DATABASE_URL": "postgresql://localhost:5432/project_db"
}
}
},
"enableAllProjectMcpServers": true
}在这个例子中:
- Context7 和 Brave Search 在全局配置,所有项目都能用——它们是通用工具
- project-database 在项目配置,只对这个项目生效——它是项目专用工具
- 全局的
enableAllProjectMcpServers为false——你控制了"克隆新项目不会自动启用其 MCP Server" - 项目的
enableAllProjectMcpServers为true——但对于你自己信任的项目,进入时自动启用
15.4 Context7 文档查询实战
在所有 MCP 服务器中,Context7 是使用频率最高、体验最直观的一个。它提供了"实时文档查询"能力——让 Claude 能够查阅最新的库、框架、API 文档,而不是依赖训练数据中可能过时的知识。
Context7 是什么
Context7 是一个专门为 AI 编程工具设计的文档查询服务。它维护了一个庞大的文档索引库,覆盖了几乎所有主流编程库和框架的最新版本文档。通过 MCP 协议,Claude Code 可以直接查询这些文档。
核心价值:Claude 模型的训练数据有截止日期。对于训练数据之后发布的 API(如 React 19 的 use() hook)、小版本更新、刚发布的库,模型的知识是缺失的。Context7 弥补了这个 Gap——它提供"实时文档",让 Claude 能够基于最新文档给出准确的代码。
配置 Context7
{
"mcpServers": {
"context7": {
"command": "npx",
"args": ["-y", "@upstash/context7-mcp"]
}
}
}配置完成后,重启 Claude Code。在对话中可以这样确认它是否生效:
你现在能访问 Context7 来查询文档吗?Claude 会确认它可以通过 Context7 查询最新文档。
实战示例
场景:你在写 React 项目,需要了解 React 19 中 use() hook 的用法。你只知道它叫 use(),不确定它的 API 签名和最佳实践。
你输入:
帮我查一下 React 19 的 use() hook 的用法,给出示例代码背后发生了什么:
1. Claude 分析你的需求:"查 React 19 use() hook" — 这需要最新文档
2. Claude 判断:Context7 MCP 可以查询 React 文档
3. Claude 调用 Context7 的 resolve-library-id 工具,传入 "React"
4. Context7 返回 React 的库 ID:/facebook/react
5. Claude 调用 Context7 的 query-docs 工具,传入库 ID 和查询 "use() hook"
6. Context7 返回 use() hook 的文档:API 签名、使用示例、注意事项
7. Claude 基于文档内容组织回答,给出准确的代码示例Claude 的最终回复会包含基于最新文档的准确代码:
// React 19 的 use() hook —— 在组件中读取 Promise 和 Context
import { use, Suspense } from 'react';
async function fetchUser(id) {
const res = await fetch(`/api/users/${id}`);
return res.json();
}
function UserProfile({ userId }) {
// use() 可以直接读取 Promise,在 resolve 之前组件会 suspend
const user = use(fetchUser(userId));
return <div>{user.name}</div>;
}
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<UserProfile userId={1} />
</Suspense>
);
}如果没有 Context7,Claude 可能基于训练数据(可能截止于 React 18 时代)给出过时的建议,或者无法提供关于 use() API 的准确信息。
Context7 的使用技巧
- 描述具体:不要只说"查一下 React",而要说"查 React 19 的 use() hook API 签名和示例"
- 信任结果:Context7 返回的内容来自官方文档,可以直接采用
- 结合代码:最好的用法是"查文档 → 用查到的知识写当前项目的代码"——一个自然衔接
- 不要滥用:对于你很熟悉的库、常见的 API(如
useState),不需要特意查询 Context7。它最适合的场景是:新版本特性、不熟悉的库、需要确认的 API 细节
其他文档查询 MCP 服务器
除了 Context7,还有其他文档相关的 MCP Server:
| 服务器 | 说明 | 适用场景 |
|---|---|---|
| Context7 | 通用文档查询,覆盖数千个库 | 日常工作首选 |
| MCP Docs | Anthropic 官方文档查询 | 查询 Anthropic SDK、Claude API |
| DevDocs | 基于 devdocs.io 的离线文档 | 需要离线查询时使用 |
15.5 常用 MCP 服务器推荐
MCP 生态正在快速成长。以下是根据社区使用频率和实用性整理的推荐清单。
推荐列表
| 服务器 | 用途 | 配置方式 | 推荐度 |
|---|---|---|---|
| Context7 | 实时文档查询,覆盖数千个库的最新文档 | npx -y @upstash/context7-mcp | ⭐⭐⭐⭐⭐ |
| Filesystem | 安全的文件系统访问,限制在指定目录内 | npx -y @anthropic/mcp-server-filesystem /path | ⭐⭐⭐⭐ |
| PostgreSQL | 数据库查询:执行 SQL、查看表结构、分析数据 | npx -y @anthropic/mcp-server-postgres | ⭐⭐⭐⭐ |
| GitHub | GitHub API 集成:读 Issue、查 PR、搜索代码 | npx -y @anthropic/mcp-server-github | ⭐⭐⭐⭐ |
| Brave Search | 网络搜索(通过 Brave Search API) | npx -y @anthropic/mcp-server-brave-search | ⭐⭐⭐ |
| Puppeteer | 浏览器自动化:打开网页、截图、点击、表单填写 | npx -y @anthropic/mcp-server-puppeteer | ⭐⭐⭐ |
| Sequential Thinking | 复杂推理:引导模型进行多步骤的深度思考 | npx -y @anthropic/mcp-server-sequential-thinking | ⭐⭐⭐ |
逐个详解
1. Context7(⭐⭐⭐⭐⭐)
第 15.4 节已经详细介绍了 Context7。它是日常使用频率最高的 MCP 服务器,强烈推荐每个人都配置。
2. Filesystem(⭐⭐⭐⭐)
Filesystem MCP Server 让 Claude 安全地访问项目外的文件系统路径。在 Claude Code 中,沙箱默认限制了对项目目录外文件的访问(见第 14.5 节)。如果你需要 Claude 操作全局配置文件或共享目录中的资源,可以通过 Filesystem MCP Server 精确授权:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-filesystem", "/Users/me/shared-configs"]
}
}
}使用场景:让 Claude 帮你管理跨项目的共享配置文件、操作存储在项目外的媒体资源、编辑全局的 Dotfiles。
3. PostgreSQL(⭐⭐⭐⭐)
PostgreSQL MCP Server 让 Claude 直接查询和分析数据库。它暴露了表结构查询、SQL 执行、数据浏览等工具:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/mydb"
}
}
}
}使用场景:
- 让 Claude 分析表关系,帮你写 JOIN 查询
- 排查数据质量问题
- 根据表结构自动生成 TypeScript 类型定义
- 分析生产数据库的慢查询(连接只读副本)
⚠️ 安全提醒:生产数据库的连接字符串应放在
settings.local.json(不提交 Git),并且建议连接只读副本,避免误操作。
4. GitHub(⭐⭐⭐⭐)
GitHub MCP Server 提供 GitHub API 的完整访问能力:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-github"],
"env": {
"GITHUB_TOKEN": "ghp_xxxxxxxxxxxx"
}
}
}
}使用场景:
- 让 Claude 帮你分析 Issue 列表,总结用户反馈
- 审查 PR 时获取更多上下文(关联 Issue、Blame 历史)
- 搜索当前仓库的相似代码或历史修改
5. Brave Search(⭐⭐⭐)
Brave Search MCP Server 提供网络搜索能力。注意 Claude Code 本身已有 WebSearch 工具,但 Brave Search 可能返回不同来源的结果:
{
"mcpServers": {
"brave-search": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-brave-search"],
"env": {
"BRAVE_API_KEY": "your-api-key"
}
}
}
}适用场景:需要 Claude 搜索最新技术动态、查阅 Stack Overflow 上的解决方案、获取 Claude 训练数据之后发布的文档。
6. Puppeteer(⭐⭐⭐)
Puppeteer MCP Server 提供浏览器自动化,让 Claude 能够操作真实的浏览器:
{
"mcpServers": {
"puppeteer": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-puppeteer"]
}
}
}使用场景:
- 让 Claude 帮你验证前端页面的交互逻辑
- 自动抓取需要 JS 渲染的页面内容
- 生成页面的截图进行视觉对比
7. Sequential Thinking(⭐⭐⭐)
Sequential Thinking MCP Server 不同于其他"获取外部数据"的服务。它提供的是一个思维框架——引导模型进行结构化的多步骤推理:
{
"mcpServers": {
"sequential-thinking": {
"command": "npx",
"args": ["-y", "@anthropic/mcp-server-sequential-thinking"]
}
}
}适用场景:复杂算法设计、系统架构决策、多因素权衡——任何需要"一步一步想"而不是"一步到位"的深度问题。
如何选择
对于大多数开发者,建议的配置优先级:
第一层(必装):Context7 — 实时文档,每天都会用到
第二层(常用):根据你的技术栈选择 — PostgreSQL(数据库项目)、GitHub(协作项目)
第三层(按需):Puppeteer、Brave Search、Sequential Thinking — 特定场景下的利器不需要一次性配齐所有 MCP Server。从 Context7 开始,当你遇到"Claude 需要访问 X 但我不知道怎么让它访问"的场景时,再去寻找对应的 MCP Server。
15.6 自定义 MCP 服务器开发入门
除了使用社区提供的 MCP Server,你也可以开发自己的 MCP Server 来接入公司内部 API、自定义工作流、或者任何你希望 Claude 能够操作的特定工具。本节从零开始,带你构建一个可用的自定义 MCP 服务器。
开发环境准备
MCP Server 的开发只需要 Node.js(≥18)。使用官方的 @modelcontextprotocol/sdk 包:
mkdir my-first-mcp && cd my-first-mcp
pnpm init
pnpm add @modelcontextprotocol/sdk一个最简 MCP 服务器
以下是一个完整的、可运行的 MCP 服务器,它只提供一个工具 hello——接收一个名字,返回问候语:
// server.js —— 你的第一个 MCP 服务器
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
// 1. 创建 Server 实例
const server = new Server({
name: "my-first-mcp",
version: "1.0.0"
}, {
capabilities: { tools: {} }
});
// 2. 注册 tools/list 处理器 —— 告诉 Client 这个 Server 有哪些工具
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "hello",
description: "向指定的人打招呼。当你需要问候某人时使用这个工具。",
inputSchema: {
type: "object",
properties: {
name: {
type: "string",
description: "要问候的人的名字"
}
},
required: ["name"]
}
}]
}));
// 3. 注册 tools/call 处理器 —— 当 Client 调用工具时执行实际逻辑
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "hello") {
const greeting = `Hello, ${args.name}! 这是来自你的第一个 MCP 服务器的问候。`;
return {
content: [{ type: "text", text: greeting }]
};
}
throw new Error(`Unknown tool: ${name}`);
});
// 4. 启动 stdio 传输,开始监听来自 Client 的请求
const transport = new StdioServerTransport();
await server.connect(transport);运行你的 MCP 服务器
- 将上述代码保存为
server.js - 确保
package.json中有"type": "module"(因为用了 ES Module) - 在 Claude Code 的配置中添加这个服务器:
{
"mcpServers": {
"my-first-mcp": {
"command": "node",
"args": ["/absolute/path/to/my-first-mcp/server.js"]
}
}
}- 重启 Claude Code,然后在对话中输入:
用 hello 工具向 Claude Code 打个招呼Claude 会调用你的 hello 工具,传入 name: "Claude Code",然后收到 "Hello, Claude Code! 这是来自你的第一个 MCP 服务器的问候。"
MCP 协议的核心请求/响应
MCP 协议定义了四个核心的请求类型。理解它们就理解了如何开发任何 MCP Server:
| 请求 | 方向 | 说明 | Server 需要实现的 |
|---|---|---|---|
tools/list | Client → Server | "你有哪些工具?" | ✅ 必须 |
tools/call | Client → Server | "请执行工具 X,参数是 Y" | ✅ 必须 |
resources/list | Client → Server | "你有哪些资源?" | 可选 |
resources/read | Client → Server | "请读取资源 X 的内容" | 可选(配合 resources/list) |
进阶:带网络请求的 MCP 服务器
一个更实际的例子——创建一个天气查询 MCP Server,让 Claude 能够查询某个城市的天气:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "weather-mcp",
version: "1.0.0"
}, {
capabilities: { tools: {} }
});
server.setRequestHandler("tools/list", async () => ({
tools: [{
name: "get_weather",
description: "获取指定城市的天气信息。当用户询问某个城市的天气时使用。",
inputSchema: {
type: "object",
properties: {
city: {
type: "string",
description: "城市名称(英文),如 'Beijing'、'Tokyo'"
}
},
required: ["city"]
}
}]
}));
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_weather") {
// 使用 wttr.in 的免费天气 API(不需要 API Key)
const url = `https://wttr.in/${encodeURIComponent(args.city)}?format=3`;
const response = await fetch(url);
const weather = await response.text();
return {
content: [{ type: "text", text: `${args.city} 的天气:${weather}` }]
};
}
throw new Error(`Unknown tool: ${name}`);
});
const transport = new StdioServerTransport();
await server.connect(transport);为工具写好 description
工具描述(description)是 MCP Server 开发中最重要也最容易被忽视的环节。Claude 模型根据 description 来决定"何时使用这个工具"。一个好的 description 应该:
- 说清楚这个工具做什么
- 给出使用场景:什么时候应该用这个工具
- 描述参数含义:每个 input 参数都应有自己的 description
对比两个 description:
// ❌ 糟糕的 description —— Claude 看不懂
{
name: "query",
description: "查询数据",
inputSchema: {
properties: {
q: { type: "string", description: "" }
}
}
}
// ✅ 好的 description —— Claude 知道何时调用
{
name: "query_database",
description: "在项目 PostgreSQL 数据库中执行只读 SQL 查询。" +
"当用户询问关于数据库中的数据、表结构、或需要统计分析时使用。" +
"注意:此工具只支持 SELECT 查询,不支持 INSERT/UPDATE/DELETE。",
inputSchema: {
properties: {
sql: {
type: "string",
description: "要执行的只读 SQL 查询语句(仅 SELECT)"
}
},
required: ["sql"]
}
}关键认知:你不是在写给人看的注释,你是在写给 Claude 模型看的"工具说明书"。Claude 根据这段描述来判断"当前用户的问题是否需要调用这个工具"。
调试 MCP 服务器
开发 MCP Server 最常见的调试技巧:
1. 用 stderr 打日志
MCP 的 stdio 传输中,stdout 用于协议通信,所以你不能向 stdout 打印日志。使用 stderr:
console.error("[DEBUG] Tool called:", name, "with args:", args);2. 逐步测试
先在 Claude Code 中问"你有哪些 MCP 工具可用?"来确认 Server 的 tools/list 返回了正确的工具定义。确认工具被注册后,再测试实际调用。
3. 使用 JSON Schema 验证工具
确保 inputSchema 是合法 JSON Schema。VSCode 的 JSON 支持能帮你检查结构,但语义正确性需要手动验证。
发布与分享
当你的 MCP Server 完善后,可以分享给团队或社区:
- npm 发布:将 Server 发布为 npm 包,团队成员通过
npx your-package-name使用 - MCP Marketplace:提交到 MCP 官方市场(https://github.com/modelcontextprotocol/servers),让更多人发现
- 团队内部:放在私有 npm registry 或 Git 仓库中,通过
npx或本地路径引用
15.7 MCP 服务器最佳实践
开发和使用 MCP 服务器的实践中,社区已经总结出了以下的最佳实践。这些原则帮助你在享受 MCP 扩展能力的同时,保持系统的安全和可靠。
1. 最小权限原则
MCP Server 应该只暴露它确实需要的工具和数据。不要因为"反正能实现"就把整个数据库的所有表、一个文件系统的所有路径都暴露出去。
// ✅ 好的做法:精确控制
{
name: "read_user_orders",
description: "查询指定用户的订单列表(只读)",
inputSchema: {
properties: {
userId: { type: "string", description: "用户 ID" }
}
}
}
// ❌ 坏的做法:什么都能做
{
name: "execute_sql",
description: "执行任意 SQL",
inputSchema: {
properties: {
sql: { type: "string" }
}
}
}2. 输入验证
永远不要信任从 Claude(Client)传来的参数。在 Server 端做完整的输入验证:
server.setRequestHandler("tools/call", async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_user") {
const userId = args.userId;
// ✅ 验证输入
if (!userId || typeof userId !== "string" || userId.length > 100) {
return {
content: [{ type: "text", text: "错误:userId 无效" }],
isError: true
};
}
// 使用参数化查询,防止 SQL 注入
const user = await db.query("SELECT * FROM users WHERE id = $1", [userId]);
return { content: [{ type: "text", text: JSON.stringify(user) }] };
}
});3. 错误处理
返回清晰的错误信息,让 Claude 能够理解问题并自我纠正:
// ✅ 好的错误返回
return {
content: [{
type: "text",
text: "错误:数据库连接失败。请检查 DATABASE_URL 环境变量是否正确设置。"
}],
isError: true // 标记为错误,Claude 会尝试用不同方式重新调用
};
// ❌ 坏的错误返回
throw new Error("Connection refused");4. 性能:保持工具调用快速
MCP 工具的响应时间直接影响 Claude Code 的使用体验。建议:
- 目标响应时间:< 5 秒(越短越好)
- 如果操作需要更长时间,考虑返回"操作已提交,请稍后检查结果"的方式
- 在工具 description 中提示"此操作可能需要较长时间",让 Claude 做好预期
5. 日志记录
在 Server 端记录所有工具调用,方便调试和安全审计:
function logToolCall(toolName, args, result) {
const entry = {
timestamp: new Date().toISOString(),
tool: toolName,
arguments: args,
result: result.content?.[0]?.text?.substring(0, 200) // 只记录前 200 字符
};
console.error("[MCP]", JSON.stringify(entry));
}6. 安全性
- 永远不要在 Server 代码中硬编码密钥。使用环境变量传递
- 限制 Server 的网络访问范围。如果 Server 需要访问外部 API,明确限定允许的域名
- 定期审查依赖。MCP Server 的 Node.js 依赖也可能有安全漏洞
- 为生产环境使用只读连接。数据库 MCP Server 应该连接只读副本,而非主库
7. 文档清晰
Server 的使用文档应包含:
- 是什么:Server 的用途和提供的工具列表
- 怎么配:完整的配置示例(
command、args、env) - 需要什么权限:涉及哪些文件路径、网络请求、数据库表
- 有什么限制:并发限制、速率限制、已知的兼容性问题
15.8 本章小结
MCP 是 Claude Code 扩展体系的基石。理解了它,后续的 Plugins、Skills、Hooks 都会更容易理解——因为它们都建立在 MCP 的"标准化扩展"理念之上。
核心知识回顾
- MCP 是什么:一个开放协议,定义了 AI 模型与外部工具/数据源交互的标准方式。类比成"AI 工具的 USB-C 接口"。
- 三大角色:Client(Claude Code)→ Transport(stdio/HTTP)→ Server(独立进程)。Server 通过 Tools、Resources、Prompts 向 Client 暴露能力。
- 配置位置:全局配置放通用工具(Context7、Brave Search),项目配置放项目专用工具(数据库连接、内部 API)。
- Context7 是必装的 MCP Server:它让 Claude 能够查询最新文档,弥补模型训练数据的时效性。
- 自定义 MCP Server 开发不难:核心就是实现
tools/list和tools/call两个处理器。@modelcontextprotocol/sdk封装了协议细节。 - 安全原则:最小权限、输入验证、清晰错误、日志记录——这些通用软件开发原则在 MCP 领域同样适用。
MCP 在生态篇中的位置
MCP 是 Claude Code 扩展体系的最底层:
Skills(技能/工作流)
↓ 依赖
Plugins(MCP 插件)
↓ 依赖
MCP(Model Context Protocol) ← 本章
↓ 依赖
Hooks(事件钩子)
↓ 依赖
斜杠命令 / 快捷键理解了这个层次关系,你就理解了为什么 MCP 是第四篇的第一章——它是所有上层扩展的共同基础。
下一步
配置好 MCP 服务器(特别是 Context7)之后,你已经让 Claude Code 的能力扩展到了"文件系统 + Shell + 实时文档"之外。第 16 章将探索 MCP 的上一层抽象——插件系统:Plugins 如何将 MCP Server 封装成更方便安装和管理的形态,以及如何利用官方和社区插件市场来快速增强 Claude Code 的能力。
章节小结:本章覆盖了 MCP 协议从概念到实践的完整路径。你学习了 MCP 的架构原理、学会了配置和使用 MCP 服务器(以 Context7 为核心实战)、了解了社区中最有价值的几个 MCP 服务器、掌握了自定义 MCP 服务器的开发方法、并建立了 MCP 安全使用的最佳实践框架。从下一章开始,我们将探索构建在 MCP 之上的更高层扩展形态——让"添加新能力"这件事变得更简单、更安全、更标准化。