1. 为什么团队内部系统总缺一个 MCP Server
你可能已经用 Claude Code 连过 Jira、GitHub、Postgres,这些现成的 MCP Server 开箱即用,体验很顺。但真正卡住大多数人的,是团队内部那套没人写 Server 的系统:自研工单、私有知识库、内部脚本、某个只有你懂的本地工具。它们没有官方 MCP 实现,你只能眼睁睁看着 Claude 在对话里"知道"有这个东西,却没法真正调用。
mcp-builder 就是为这个缺口准备的。它是 Anthropic 在 anthropics/skills 仓库里维护的官方 Skill,注意它的定位——不是代码生成器,而是一套工程方法论。它教你的不是"复制粘贴一段模板",而是四件事:怎么规划 tool 的命名和 API 覆盖范围、怎么用 FastMCP(Python)或 MCP SDK(TypeScript)落地实现、怎么用 MCP Inspector 单独调试、怎么设计 Eval 验证 Agent 是否真的会用你的 Server。
我试过直接手写 MCP Server,最容易翻车的地方不是代码本身,而是 tool 的 docstring 写得太随意,导致 Claude 填参数时全靠猜。mcp-builder 的价值就在于把这些隐性规范显性化:tool 名要有前缀加动作、docstring 要说清每个参数含义、错误要返回可行动文案而不是抛异常、只读 tool 不写盘。这些规则听起来琐碎,但决定了你的 Server 是"能跑"还是"Agent 真的会用"。
这篇聚焦一条完整实操路径:从零用 FastMCP 搭一个本地笔记 Server,走完脚手架生成、MCP Inspector 调试、本地联调、接入 Claude Code、对话验收。全程 80 行 Python,任何机器都能跑通,不需要 API Key。适合已经会用 Claude Code、想给自己内部工具补一个 MCP 接口的开发者。读完你能独立完成一次端到端跑通,而不是停留在"知道有这么个东西"。
2. 前置准备:安装 mcp-builder 与 FastMCP 环境
在动手写 Server 之前,先把两样东西装好:Claude Code 里的 mcp-builder Skill,以及本机的 Python MCP 运行环境。这两件事分开做,别混在一起,否则后面排错会很痛苦。
先说 Skill 安装。在 Claude Code 里分两条命令走,第一条是添加 marketplace:
/plugin marketplace add anthropics/skills第二条是安装 example-skills 包,mcp-builder 就在这个包里:
/plugin install example-skills@anthropic-agent-skills如果你只想装 mcp-builder 这一个 Skill,不想把整个 example-skills 都拉下来,可以用 npx 单独装:
npx skills add anthropics/skills --skill mcp-builder --agent claude-code装完之后,你在 Claude Code 里就能通过 Skill 的方式调用 mcp-builder 的规划指引。它不会替你写代码,但会在你规划 tool 命名、设计 docstring 时给出规范建议,这部分后面 Phase 1 会用到。
再说本机环境。写 Python 版 Server 需要 Python 3.10 及以上,然后装 mcp 包,FastMCP 框架就在里面:
python --version pip install mcp这里有个坑要提前说:pip install mcp 装到的环境,必须和你后面运行 server.py 的 python 是同一个。很多人机器上有多个 Python(系统自带、conda、venv),装的时候用了一个,跑的时候用了另一个,结果就是ModuleNotFoundError: No module named 'mcp'。建议直接建一个干净的虚拟环境:
python -m venv .venv source .venv/bin/activate # Windows: .venv\Scripts\activate pip install mcp激活后which python(Windows 用where python)确认路径指向 .venv,再往下走。这一步花两分钟,能省掉后面半小时的排错。
关于 TaoToken 的前置说明:本篇的 MCP Server 是纯本地 stdio 工具,不依赖任何远程模型网关就能跑通 Inspector 和 Claude Code 联调。如果你后续想把 Server 接到远程模型做 Eval,或者团队要共享一个 streamable HTTP 的 Server,可以先把 TaoToken 的 API Key 准备好,接入文档在 https://taotoken.net/api ,Key 在 https://taotoken.net/api-keys 生成。本地 stdio 这条链路不需要它,但提前备着不亏。
环境确认清单:Python 3.10+、mcp 包已装、虚拟环境已激活、Claude Code 已装 mcp-builder Skill。四项都打勾,进入下一步。
3. 可复制配置:用 FastMCP 写一个 pocket-notes Server
这一节是全文的核心,直接给你可复制的完整代码和配置片段。我们做一个 pocket-notes MCP Server,功能是让 Claude 帮你管理本地纯文本笔记:添加、列表、搜索。数据存在用户目录的 JSON 文件里,不需要 API Key,任何机器都能跑通。
先建目录:
mkdir pocket-notes-mcp && cd pocket-notes-mcp然后创建 server.py,下面是完整可运行代码:
import json from pathlib import Path from mcp.server.fastmcp import FastMCP mcp = FastMCP("pocket-notes") NOTES_FILE = Path.home() / ".pocket-notes" / "notes.json" def _load(): if not NOTES_FILE.exists(): return [] return json.loads(NOTES_FILE.read_text(encoding="utf-8")) def _save(notes): NOTES_FILE.parent.mkdir(parents=True, exist_ok=True) NOTES_FILE.write_text( json.dumps(notes, ensure_ascii=False, indent=2), encoding="utf-8") @mcp.tool() def notes_add(title: str, content: str) -> str: """Add a note. title: note title; content: note body.""" title = title.strip() if not title: return "Error: title cannot be empty. Provide a title and retry." notes = _load() note_id = len(notes) + 1 notes.append({"id": note_id, "title": title, "content": content.strip()}) _save(notes) return f"Added note #{note_id}: {title}" @mcp.tool() def notes_list() -> str: """List all notes (id and title only).""" notes = _load() if not notes: return "No notes yet. Use notes_add first." return "\n".join(f"#{n['id']} {n['title']}" for n in notes) @mcp.tool() def notes_search(keyword: str) -> str: """Search notes by keyword in title or content.""" kw = keyword.strip().lower() if not kw: return "Error: keyword cannot be empty." hits = [n for n in _load() if kw in n["title"].lower() or kw in n["content"].lower()] if not hits: return f"No notes matching '{keyword}'." return "\n\n".join(f"#{n['id']} {n['title']}\n{n['content']}" for n in hits) if __name__ == "__main__": mcp.run(transport="stdio")对照 mcp-builder 的规范,这段代码有几个刻意的设计点值得说。Tool 名用notes_前缀加动作,Agent 在发现工具时更容易归类;docstring 里明确写了每个参数的含义,Claude 靠它填参,写含糊了它就会瞎猜;错误返回的是可行动文案("Provide a title and retry"),而不是抛未捕获异常,这样 Agent 能自己纠正;只读 tool(notes_list、notes_search)不写盘,写盘 tool(notes_add)边界清晰。
Transport 选型上,个人本地工具用 stdio 就够了。如果你要团队远程共享,才需要换成 streamable HTTP,那是进阶场景,本篇先不展开。
本地先验证一下能不能起来:
python server.py如果挂起没有报错,说明 Server 正常启动,按 Ctrl+C 退出。这一步只是确认进程能跑,真正的功能验证交给下一节的 Inspector。
接入 Claude Code 有两种方式,先给命令行方式(个人 scope,推荐先试):
claude mcp add --transport stdio pocket-notes -- python /绝对路径/pocket-notes-mcp/server.pyWindows 示例:
claude mcp add --transport stdio pocket-notes -- python E:\pocket-notes-mcp\server.py再给项目级配置方式,适合团队共享、可以提交 Git。在项目根目录建.mcp.json:
{ "mcpServers": { "pocket-notes": { "type": "stdio", "command": "python", "args": ["E:/tools/pocket-notes-mcp/server.py"] } } }注意 args 里的路径用正斜杠,Windows 下反斜杠在 JSON 里要转义,容易出错。项目级配置首次加载时 Claude Code 可能会弹交互让你批准,这是正常的安全机制。
4. 验证请求:MCP Inspector 调试与对话验收
代码写完不等于能用。接入 Claude 之前,先用官方 MCP Inspector 单独测 tool,把 Server 逻辑和 Claude 的调用行为分开验证,这样出问题时你能快速定位是 Server 的锅还是配置的锅。
启动 Inspector:
npx @modelcontextprotocol/inspector python server.py它会启动一个本地服务并打印一个浏览器地址,打开后你会看到 Inspector 界面,左侧列出你的三个 tool。按顺序测三步:
第一步,调 notes_add,参数 title=购物清单,content=牛奶、鸡蛋。预期返回Added note #1: 购物清单。
第二步,调 notes_list,预期返回#1 购物清单。
第三步,调 notes_search,参数 keyword=牛奶,预期返回完整条目,包含标题和内容。
三步全过,说明 Server 逻辑正确,可以接入 Claude Code 了。如果某一步失败,先看 Inspector 里的错误信息,再对照下一节的排查表。
接入后完全重启 Claude Code,输入/mcp,你应该能看到 pocket-notes 以及它下面的 3 个 tool。如果没看到,先claude mcp list查状态。
然后是对话验收,在 Claude Code 里依次说三句话:
第一句:"用 pocket-notes 添加笔记:标题「学习计划」,内容「本周完成 MCP 教程」"。
第二句:"列出我所有笔记"。
第三句:"搜索包含 MCP 的笔记"。
成功标志有两个:一是 Claude 实际调用了 MCP tool(你会在对话里看到工具调用记录),二是打开~/.pocket-notes/notes.json(Windows 是C:\Users\你的用户名\.pocket-notes\notes.json),内容与对话一致。
这里补一句关于 Eval 的思路。mcp-builder 的 Phase 4 强调设计 Eval 验证 Agent 能否真正用好你的 Server。最简单的 Eval 就是上面这三句话:如果 Claude 能正确选 tool、正确填参、正确解读返回,说明你的 docstring 和 tool 设计到位了。如果它选错 tool 或者参数填错,回去改 docstring,而不是改代码逻辑。
5. 常见报错排查:401、local proxy failed 与 reading choices
这一节对照真实报错,把最容易踩的坑列出来。注意,本篇的本地 stdio Server 本身不涉及远程鉴权,所以 401 这类错误通常出现在你后续接远程模型或 HTTP transport 的场景,这里一并说清。
先看 Inspector 连不上的情况。最常见原因是路径问题:python server.py用的是相对路径,但 Inspector 启动时工作目录可能变了。解决办法是统一用绝对路径,npx @modelcontextprotocol/inspector python /绝对路径/server.py。第二个原因是环境不一致,pip install mcp 装的环境和运行 server.py 的 python 不是同一个,回到第 2 节用 venv 统一。
再看/mcp里看不到 Server。先跑claude mcp list查状态,如果显示未连接,重启 Claude Code。项目级.mcp.json首次加载需要交互批准,如果你跳过了批准,Server 不会生效。另外检查 JSON 语法,多一个逗号都会导致整个配置解析失败。
Tool 调用失败时,看终端里的 MCP 日志。FastMCP 会把异常打到 stderr,如果日志里出现ModuleNotFoundError,还是环境问题;如果出现文件权限错误,检查~/.pocket-notes/目录是否可写。
关于 401 和 local proxy failed:这两个报错一般出现在你把 Server 接到远程模型网关做 Eval 的时候。401 是 Key 无效或过期,去 https://taotoken.net/api-keys 重新生成;local proxy failed 通常是本地网络配置或 Base URL 写错,确认你填的是 https://taotoken.net/api 而不是别的地址。如果你在 Claude Code 里配了远程模型,检查 settings 里的 Base URL、Key、Model ID 三件套是否齐全,缺一个都会失败。
关于reading choices报错:这通常出现在调用远程模型返回体解析时,说明返回结构和你预期的不一致,多半是 Base URL 指向了错误的端点,或者 Model ID 填了一个不存在的模型。对照接入文档 https://taotoken.net/doc 确认端点格式。
关于 OAuth 报错:如果你用的是需要 OAuth 的远程 MCP Server,token 过期会报这个。本地 stdio Server 不涉及,但如果你在 Cline MCP 或 Codex 的 auth.json 里配了远程 Server,检查 token 是否刷新。
想换 TypeScript 实现的话,mcp-builder Skill 里有 node_mcp_server.md,适合做远程 HTTP Server。Python 版适合本地快速验证,TypeScript 版适合团队共享和部署。
| 现象 | 处理 |
|---|---|
| Inspector 连不上 | 用绝对路径;确认 python 和 pip install mcp 在同一环境 |
| /mcp 无 Server | 重启 Claude;claude mcp list 查状态;检查 .mcp.json 语法 |
| Tool 调用失败 | 看终端 MCP 日志;确认 venv 路径一致 |
| 401 | Key 无效,去 api-keys 重新生成 |
| local proxy failed | 检查 Base URL 是否为 https://taotoken.net/api |
| reading choices | 端点或 Model ID 错误,对照接入文档 |
| OAuth 报错 | 远程 Server token 过期,刷新 token |
| 想换 TypeScript | 看 Skill 内 node_mcp_server.md |
6. 把 Server 接到长期编码流:Coding Plan 与后续扩展
跑通第一个 Server 之后,你大概率会想把它接到日常编码流里,让 Claude 在写代码时顺手调用你的内部工具。这时候有几个方向可以扩展。
第一个方向是把 stdio 换成 streamable HTTP,让团队共享。stdio 是单机进程,每个人都要本地装一份;HTTP transport 可以部署到内网,团队成员通过 URL 接入。mcp-builder 的 Skill 里有对应的指引,TypeScript 版更适合这个场景。
第二个方向是扩充 tool 覆盖范围。pocket-notes 只有三个 tool,真实内部系统往往需要十几个。mcp-builder 的 Phase 1 规划方法在这里很关键:先列出所有 API 端点,再决定哪些暴露成 tool、怎么命名、怎么分组。不要一股脑全暴露,Agent 面对太多 tool 会选错。
第三个方向是接远程模型做 Eval。本地 stdio 不需要远程模型,但如果你想批量测试 Agent 在不同模型下的 tool 调用准确率,就需要一个稳定的模型网关。这时候 TaoToken 的 Coding Plan 比较合适,适合长期编码和 Agent 场景,地址在 https://taotoken.net/coding-plan 。模型对话调试可以用 https://taotoken.net/models ,控制台在 https://taotoken.net/console 。
如果你用的是 Claude Code 的 Anthropic 兼容接入,配置片段大致是这样,注意 Base URL、Key、Model ID 三件套要齐全:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "你的Key", "ANTHROPIC_MODEL": "你的ModelID" } }Claude Code 的 Anthropic 接入文档在 https://taotoken.net/claudecode-anthropic ,里面有完整的 settings 示例。Cline MCP 和 Codex 的 auth.json 配置同理,都是 Base URL 加 Key 加 Model ID,缺一不可。
最后说一个真实经验:MCP Server 的调试成本,八成花在 docstring 和错误文案上,而不是业务逻辑。业务逻辑你写十行就完了,但让 Agent 正确选 tool、正确填参、正确解读返回,需要反复打磨 docstring。mcp-builder 的价值就在这——它把 MCP 工程规范沉淀成了可复用的方法,你照着走,能少踩很多坑。80 行 Python 走完编写、Inspector、Claude Code 全链路,这就是你的第一个 MCP Server。