如何构建你的第一个MCP服务器:实践指南
MCP(模型上下文协议)是给Claude提供对外部工具和数据(数据库、文件、API)结构化访问的方式,而无需塞满上下文窗口。服务器比看起来简单:安装SDK,将工具定义为JSON schema,实现处理器,通过stdio连接。30分钟内就能让Claude调用你的自定义工具。
每周三。28,400+ 读者。纯干货。
✓ 请查收邮箱 — 点击确认链接以完成订阅。
✓ 订阅成功!
✓ 您已在订阅列表中。
目录
2026年6月更新。
TL;DR: MCP(模型上下文协议)是给Claude提供对外部工具和数据(数据库、文件、API)结构化访问的方式,而无需塞满上下文窗口。服务器比看起来简单:安装SDK,将工具定义为JSON schema,实现处理器,通过stdio连接。30分钟内就能让Claude调用你的自定义工具。
[运营者视角] 我定期将新工具接入我的智能体,MCP现在是干净实现这一点的标准路径。服务器一旦构建完成,每个支持MCP的客户端——Claude Desktop、Claude Code、任何使用Anthropic SDK的应用——都可以在不修改调用代码的情况下使用它。这就是价值所在:构建一次,随处复用。
MCP究竟是什么
模型上下文协议是一个开放协议,标准化了AI模型连接外部上下文和工具的方式。把它想象成AI集成的USB-C标准:在此之前,每个想让Claude读取数据库或调用API的应用都必须自己发明一套解决方案。有了它,你构建一个MCP服务器,任何兼容的主机都可以使用它。
MCP定义了服务器可以提供的三类内容:
- 工具 — Claude可以调用的函数(读取文件、查询数据库、发送Slack消息)
- 资源 — Claude可以读取的数据(文档、数据库行、文件树)
- 提示词 — 主机可以注入的可复用提示词模板
对于大多数运营者用例,你在构建工具服务器。资源和提示词在基础工作运行后再处理。
架构是客户端-服务器模式,由客户端(Claude Desktop、Claude Code、你的自定义应用)控制一切。服务器是被动的——只是监听工具调用请求并返回结果。
每个MCP服务器的三个组成部分
你构建的每个MCP服务器都有相同的结构:
- 服务器对象 — 声明服务器的名称、版本和能力(工具、资源、提示词)
- 工具定义 — 包含名称、描述和输入JSON schema的工具列表
- 请求处理器 — Claude调用工具时运行的函数
就这些。开始时不需要数据库、HTTP栈或认证层。最小服务器不到30行TypeScript。
前置条件(2分钟)
- Node.js 18+ — 用
node --version检查 - TypeScript 5+(下面作为dev依赖包含)
- 用于测试的MCP客户端 — Claude Desktop免费,是查看服务器运行最简单的方式
运行MCP服务器本身不需要Anthropic API密钥。API密钥在客户端(Claude Desktop)中,不在你的服务器中。
第一步:设置项目(3分钟)
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm install @modelcontextprotocol/sdk
npm install -D typescript tsx @types/node添加到package.json:
{
"type": "module",
"scripts": {
"build": "tsc",
"dev": "tsx src/index.ts"
}
}创建tsconfig.json:
{
"compilerOptions": {
"target": "ES2022",
"module": "Node16",
"moduleResolution": "Node16",
"outDir": "./build",
"strict": true
},
"include": ["src/**/*"]
}第二步:编写最小服务器(5分钟)
创建src/index.ts:
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
const server = new Server(
{ name: "my-mcp-server", version: "1.0.0" },
{ capabilities: { tools: {} } }
);
// 声明此服务器提供的工具
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "get_word_count",
description: "统计文本块中的单词数。",
inputSchema: {
type: "object",
properties: {
text: {
type: "string",
description: "要统计单词的文本",
},
},
required: ["text"],
},
},
],
}));
// 处理客户端的工具调用
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "get_word_count") {
const { text } = args as { text: string };
const count = text.trim().split(/\s+/).filter(Boolean).length;
return {
content: [{ type: "text", text: `单词数:${count}` }],
};
}
throw new Error(`未知工具:${name}`);
});
// 通过stdio连接——这是Claude Desktop与服务器通信的方式
const transport = new StdioServerTransport();
await server.connect(transport);这就是完整的服务器。它注册一个工具(get_word_count)并实现它。结构才是关键。
第三步:构建并在Claude Desktop中注册(5分钟)
构建TypeScript:
npm run build在Claude Desktop的配置文件中注册它。
macOS:~/Library/Application Support/Claude/claude_desktop_config.json
Windows:%APPDATA%\Claude\claude_desktop_config.json
如果文件不存在,创建它:
{
"mcpServers": {
"my-mcp-server": {
"command": "node",
"args": ["/my-mcp-server的绝对路径/build/index.js"]
}
}
}使用绝对路径。保存后重启Claude Desktop。你会在消息输入栏看到锤子图标(🔨)——这意味着Claude已发现你的工具。
第四步:构建一个有用的工具
词数统计是用于说明的。这里有个更有用的工具:从项目目录读取文件,这是我用于汇总代码库、changelog或配置文件的上下文注入智能体的方案。
import { readFileSync, readdirSync } from "fs";
import { join, extname } from "path";
const ALLOWED_EXTENSIONS = [".md", ".txt", ".ts", ".json", ".yaml"];
const PROJECT_DIR = process.env.PROJECT_DIR ?? process.cwd();逻辑是相同的:用精确的JSON schema定义工具,实现处理器,验证输入以防止路径遍历,并向客户端返回文本。
我踩过的坑(让你不要再踩)
路径必须是绝对路径。 Claude Desktop配置中的相对路径不会按预期解析。始终使用完整路径/home/user/...。
stdio意味着服务器中不能使用console.log。 Claude Desktop通过stdin/stdout与服务器通信。调试用的console.log会损坏JSON-RPC流。改用stderr记录日志:
process.stderr.write(`调试:${message}\n`);每次配置更改后重启Claude Desktop。 MCP服务器在启动时加载。编辑的配置文件在关闭并重新打开应用之前不会生效。
工具描述就是产品。 Claude根据description字段决定是否调用你的工具。描述模糊意味着Claude不知道何时使用它。描述精确意味着Claude在正确时机使用它。在描述上花费比实现更多的时间。
我如何在生产中使用MCP服务器
stdio模式非常适合Claude Desktop和Claude Code(本地)。对于生产智能体——在Cloudflare Workers上运行的30个以上——我直接使用Anthropic SDK的tool-use API,因为我需要按步骤灵活路由到Haiku还是Sonnet。
我实际使用的模式:
- 本地开发工具 — 为Claude Code提供项目特定工具的MCP服务器
- 上下文注入 — 无需手动复制即可预加载相关文档的MCP服务器
- 原型到API的桥梁 — 先构建MCP(迭代更快),然后将逻辑移植到SDK tool-use用于生产
接下来构建什么
一旦服务器结构清晰,有用的工具就是那些访问Claude外部上下文的工具:
- 数据库读取器 — 运行只读SQL查询并以JSON格式返回结果
- Slack读取器 — 获取频道的最近N条消息
- GitHub读取器 — 列出开放的PR,读取特定提交的文件
- 内部API封装器 — 使用内置认证头调用你自己的REST API
常见问题
构建MCP服务器需要Anthropic API密钥吗?
不需要。你的MCP服务器不调用Anthropic API。它只是响应客户端的工具调用请求。API密钥在客户端,不在服务器中。
我的MCP服务器可以调用外部API吗?
可以——处理器只是异步TypeScript代码。获取天气API、查询数据库、写入文件。服务器不关心处理器内部做什么。
stdio和HTTP传输有什么区别?
stdio用于本地服务器——与Claude Desktop或Claude Code在同一台机器上。HTTP with SSE用于可以部署为Web服务的远程服务器。从stdio开始;调试更简单。
Claude如何知道何时调用我的工具?
Claude根据工具的description字段和对话上下文做出决定。如果Claude持续忽略你的工具,请精炼描述。
每周三。28,400+ 读者。纯干货。
✓ 请查收邮箱 — 点击确认链接以完成订阅。
✓ 订阅成功!
✓ 您已在订阅列表中。
将AI实战手册发送到您的邮箱
每周三。28,400+ 读者。纯干货。
请查收邮箱。
我们已向您发送确认邮件 — 点击其中的链接以完成订阅。如果一分钟内没收到,请检查垃圾邮件。
订阅成功。
欢迎 — 下一期很快就会送达您的邮箱。
您已在订阅列表中 — 每周三留意查收。