自己搭一个 MCP Server:从零到发布的完整指南
用 @modelcontextprotocol/sdk 从零搭一个 MCP Server 并发布:项目初始化、声明工具、选传输层、本地自测、OAuth 鉴权与上线清单。
操作步骤
初始化项目并装 SDK
npm init -y 后 npm i @modelcontextprotocol/sdk,package.json 设 type=module,写 src/server.ts 与 src/index.ts,配好 bin 入口。
注册 ListTools + CallTool
server.setRequestHandler(ListToolsRequestSchema, ...) 返回工具列表(名称/描述/inputSchema);CallToolRequestSchema 里实现工具逻辑并返回结构化结果。
接上传输层
本地用 StdioServerTransport 跑子进程;云端用 StreamableHTTPServerTransport + 注册 OAuth 元数据。二选一或都支持。
用 MCP Inspector 自测
npx @modelcontextprotocol/inspector 启动本地调试台,验证 ListTools → CallTool 全流程,确认 schema 与参数解析正确。
发布与安全清单
云端发布前过一遍:OAuth 鉴权、频率限制、敏感工具白名单、prompt injection 防护;README 写清各 Host 接入步骤并发布到 npm / GitHub。
MCP(Model Context Protocol)是 LLM 工具调用的开放标准,而 MCP Server 就是"把你的能力暴露出去"的那一端。本文用 TypeScript 从初始化到发布完整走一遍。
1. 从零初始化
mkdir my-mcp-server && cd my-mcp-server
npm init -y
npm i @modelcontextprotocol/sdk
在 package.json 里加 "type": "module",并声明 bin 入口:
{
"type": "module",
"bin": { "my-mcp-server": "./dist/index.js" }
}
2. 注册工具:ListTools + CallTool
一个最小 server 的核心是两个 handler。先写 src/server.ts:
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
const server = new McpServer({ name: "my-mcp-server", version: "0.1.0" });
server.registerTool(
"echo",
{
description: "原样回显输入内容,最小可用示例",
inputSchema: { message: z.string().describe("要回显的内容") },
},
async ({ message }) => ({
content: [{ type: "text", text: `你说了:${message}` }],
})
);
export default server;
SDK 的 McpServer.registerTool 会帮你自动生成 ListTools 与 CallTool 的 JSON-RPC 处理——工具带 Zod schema,输入自动校验。
3. 接传输层:stdio 还是 Streamable HTTP?
src/index.ts 里选择传输层:
import server from "./server.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("MCP server running on stdio");
- 本地子进程 →
StdioServerTransport,Host 拉起你的二进制,通过 stdin/stdout 通信。 - 云端多用户 →
StreamableHTTPServerTransport,跑一个 HTTP endpoint,配合 OAuth。
建议先 stdio 本地跑通,再按需加 HTTP。
4. 本地自测:MCP Inspector
不需要先接任何 Host,用官方调试台就能验证全流程:
npx @modelcontextprotocol/inspector node dist/index.js
在 Inspector 界面里能:查看工具列表与 schema、手动调用工具、观察 JSON-RPC 消息。确认 ListTools → CallTool 正常后再接入客户端。
5. 接进 ChatGPT / Claude / Cursor
本地开发时,把 server 加进客户端配置。以 Claude Desktop 为例(claude_desktop_config.json):
{
"mcpServers": {
"my-mcp-server": {
"command": "node",
"args": ["/path/to/my-mcp-server/dist/index.js"]
}
}
}
ChatGPT / Cursor 也有各自的 MCP 配置入口,README 里把每个 Host 的接入步骤写清楚。
6. 发布:Streamable HTTP + OAuth
给多用户或云端使用时,切到 HTTP:
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
// 在 Express / Hono 路由里挂载 transport,注册 OAuth metadata
- 注册 OAuth 2.0 metadata,对接你自己的鉴权后端(用
@modelcontextprotocol/sdk/auth)。 - 加频率限制、请求体上限与 CORS 白名单。
- 敏感工具走显式白名单 + 用户确认。
7. 上线前安全清单
- 工具返回值一律当不可信输入(防 prompt injection)。
- 破坏性操作(删除、发送、支付)让 Host 弹确认。
- 不给工具传凭据;敏感信息走 OAuth 的 authorized resources。
- 记录调用日志,定期审查谁在调哪个工具。
8. 常见错误与排查
- Host 连不上 → 先确认 stdio 命令与路径;HTTP 模式检查 OAuth metadata 与 CORS。
- CallTool 报 schema 校验失败 → Zod schema 收太紧或类型不匹配,先在 Inspector 里看参数。
- 工具不出现 → ListTools 没注册或 registerTool 抛错,检查初始化顺序。
- 响应格式错误 → 结果必须是
{ content: [...] }结构,text 类型用于纯文本。
9. 下一步
- 《Model Context Protocol 完全指南:MCP 工作机制与实战》— 协议三件套与架构细节
- 《OpenAI API 函数调用实战:Responses API 工具使用完全指南》— 在 OpenAI 生态里用工具
- 《OpenAI API 入门:第一个 GPT-5.6 调用详解》
关键要点
- 用 @modelcontextprotocol/sdk 搭一个最小 server 约 50-200 行 TypeScript,核心是注册 ListTools + CallTool
- 传输层按场景选:本地子进程用 stdio,云端多用户服务用 Streamable HTTP
- tools 是带 JSON Schema 输入的可调用函数;resources 是 URI 寻址的数据源;prompts 是可复用模板
- 本地用 MCP Inspector 自测 ListTools / CallTool 全流程,不需要先接 Host
- 上线前必做:OAuth 鉴权、频率限制、敏感工具白名单、prompt injection 防护
- 当前工具 schema 版本:MCP 2025-03-26 规范,typescript-sdk 最新稳定版
常见问题
官方参考
相关文章
订阅 GPTMap Weekly
每周一封邮件,精选 OpenAI 重要更新、深度解读与最佳实践。无广告,可随时退订。