自建一个 MCP Server 接入 Claude:从协议到代码到上线
你在公司内网有一个文档系统,Claude 不知道它的存在;你有一个只允许内部访问的 API,也没法直接让 Claude 调用。MCP(Model Context Protocol)解决的就是这个问题——它让你把自己的工具、数据、流程封装成标准接口,Claude 按规范调用,权限边界完全由你说了算。
这是 Claude 系列的第四篇:第一篇讲 Claude 的核心概念,第二篇讲 Claude Code 的整套配置,第三篇讲如何写 skill。这篇专攻 MCP server。所有 API 和命令核对自官方文档,截至 2026 年 7 月 8 日有效。
MCP 是什么:给 Claude 装上可插拔工具
先讲一个对比。Claude Code 内置了读文件、跑 bash、搜索代码这几种能力。如果你的需求超出这个范围——查询内部数据库、调用需要认证的私有 API、访问公司内网系统——Claude 就做不到了。
传统的解法是在 CLAUDE.md 里写”你可以通过运行 curl http://internal-api/... 来查询……”,然后祈祷 Claude 记得用对参数。这很脆弱:参数拼错、认证信息暴露、没有类型约束。
MCP 给了另一条路:你把这些操作封装成工具函数,按标准格式告诉 Claude 每个函数的名字、参数定义、能做什么。Claude 需要时按规范调用,你在服务端控制执行逻辑和权限。整个调用链是这样的:
sequenceDiagram
participant U as 用户
participant C as Claude Code
participant S as MCP Server(本地子进程)
participant D as 数据源
U->>C: 找关于 OAuth 的内部文档
C->>S: search_docs("OAuth")
S->>D: 读取并过滤 docs.json
D-->>S: 匹配到 2 篇
S-->>C: [{id, title}...]
C->>S: get_doc("3")
S->>D: 读取完整内容
D-->>S: 文档全文
S-->>C: # OAuth 认证规范...
C->>U: 找到了,内容如下...
和 bash tool 的本质区别是:你写的 MCP server 决定了 Claude 能做什么,而不是 Claude 随意执行任何 bash 命令。暴露什么、拦什么、怎么执行,全在你手里。
三种能力:Tools、Resources、Prompts
MCP server 可以向客户端(Claude)提供三类东西:
Tools(工具)是让 Claude 主动调用的函数,可以有副作用——查数据库、写文件、发 API 请求都算。Claude 看到你注册的工具名和描述,自己判断什么时候调用。这是最常用的能力,九成的 MCP server 只需要 Tools。
Resources(资源)是只读数据源。你可以把一个目录、一组文档、一段配置暴露为资源,Claude 读取时像读文件一样操作。适合”把整个文档目录变成 Claude 的知识库”这类场景,不需要搜索逻辑,直接按路径读取。
Prompts(提示模板)是 MCP server 侧定义的预设对话模板,Claude 可以在 / 菜单里直接触发。类似 Claude Code 的 skill,但模板逻辑在 server 端维护。起步阶段不必用,有需要时看官方文档的 Prompts 章节。
日常开发只需要记住:写 Tools,其他按需。
五分钟跑一个最小 MCP server(TypeScript)
前置要求:Node.js 18+(node --version 确认),npm。
从最小版本开始:只有一个 echo 工具,把整条路径跑通再扩展。
初始化项目
1 | mkdir my-mcp-server && cd my-mcp-server |
修改 package.json,加上模块类型和构建脚本:
1 | { |
在项目根目录创建 tsconfig.json:
1 | { |
写第一个 tool
创建 src/index.ts:
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; |
server.registerTool 三个参数:工具名、配置(description + inputSchema)、处理函数。inputSchema 里每个字段是一个 Zod schema——Claude 看到的参数说明来自 .describe(),类型校验由 Zod 保证。
构建并测试
1 | npm run build |
接入 Claude Code:注册、验证、三种 scope
注册 MCP server
在终端(不是在 claude 会话里)运行:
1 | claude mcp add my-first-mcp -- node /绝对路径/my-mcp-server/build/index.js |
注意几个细节:
- 必须用绝对路径:Claude Code 以不同工作目录启动 server,相对路径会找不到文件
--分隔符:它之后的所有内容都是启动命令,不是claude mcp add自己的参数- 没有
--transport标志,因为 stdio 是本地进程的默认传输方式
如果 server 需要环境变量(如 API key、文件路径),在命令末尾加 --env:
1 | claude mcp add my-first-mcp \ |
验证连接
1 | claude mcp list |
状态含义:
| 状态 | 含义 |
|---|---|
✓ Connected |
已连接,工具可用 |
✗ Failed to connect |
server 没跑起来,检查路径和命令 |
! Connected · tools fetch failed |
连上了但工具列表获取失败,运行 claude mcp get <名字> 看错误 |
会话内用 /mcp 命令管理和检查已注册的 server。
三种 scope
1 | # local(默认):只对你、只在当前项目生效 |
团队使用推荐 project scope——.mcp.json 提交到仓库,队友拉下来后 Claude Code 自动提示审批,批准即可用。.mcp.json 格式:
1 | { |
完整实战:内部文档搜索 MCP server
场景:团队有一份 JSON 格式的内部文档库,想让 Claude 能搜索和读取,但不暴露整个文件系统给 Claude,也不需要部署额外服务。
数据格式
创建 docs.json:
1 | [ |
完整 server 代码
1 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; |
构建并注册:
1 | npm run build |
测试效果——在 Claude Code 里直接说:
1 | > 帮我找一下关于认证的内部文档 |
Claude 的工具调用会标注 server 名字,你能清楚看到它用了哪个工具。
一个工程细节:为什么要读两次
search_docs 只返回文档列表(ID + 标题),get_doc 才返回全文。这是刻意的设计:搜索时返回所有文档全文会消耗大量 token,先让 Claude 看摘要、再按需读全文,能节省 50% 以上的上下文开销。这也是 MCP 的设计哲学:工具返回的信息量由你控制,不是越多越好。
Resources 和 Prompts:什么时候需要
Resources 适合”暴露一个数据集,让客户端决定读哪些”的场景。比如你有 100 篇文档,不想每次都搜索,希望 Claude 能像翻文件夹一样按需读取——这时候把文档目录注册为 resources 比写 search tool 更合适。注册方式和 registerTool 类似,McpServer 提供了对应的 resource 注册方法,详见 TypeScript SDK server guide。
Prompts 适合”封装一个固定的多轮对话模板”的场景,比如”代码审查请求”或”事故复盘模板”。起步可以先不用,等业务稳定了再考虑。详见 Prompts 文档。
四个高频踩坑:stdio 日志、绝对路径、启动超时、配置不刷新
**stdio 里用了 console.log()**:这是最常见的问题。stdio 传输层把 stdout 当 JSON-RPC 消息通道,console.log() 输出的文字会破坏协议,Claude 会看到解析错误。调试信息必须用 console.error()(写到 stderr):
1 | // ❌ 会破坏 stdio 通道 |
路径用了相对路径:Claude Code 在不同工作目录启动 server,相对路径会失效。DOCS_PATH 这类配置用环境变量传,路径写绝对路径。
首次 npx 包太慢导致超时:默认启动超时 30 秒。如果用 npx 启动 server(类似 Playwright MCP),首次下载包可能超时。设置 MCP_TIMEOUT 环境变量延长限制:
1 | MCP_TIMEOUT=60000 claude |
改了 .mcp.json 没生效:Claude Code 在会话启动时读配置,改完文件后退出再重开会话。
下一步
- 连接真实的内部系统:在 server 里调用内网 API、查 SQLite、读 PostgreSQL——逻辑都在你掌控的 server 里
- 官方维护的参考 server 仓库(filesystem、git、database 等):github.com/modelcontextprotocol/servers
- Python 版 SDK(
mcp[cli]+ FastMCP):适合 Python 技术栈,装饰器语法比 TypeScript 更简洁 - MCP 协议的完整规范:modelcontextprotocol.io
- 系列前三篇:Claude 全面教程、Claude Code 实战教程、从 0 到 1 写一个 Skill




