API → MCP 的目的是把一个 API 包装成“真正好用”的本地 MCP 服务器:工具数量少、每个工具回答一个完整问题,并且诚实地说明自己不知道什么。文档中的规范提炼自工作区中已经在运行的三个服务器(fitcrm-mcp/server.py、tidycal-mcp/server.py、victor-mcp/server.py),它们被视为事实基准,本文档是摘要。
一、先判断:是否真的需要服务器 在动手前按顺序检查:是否已有官方 MCP(很多产品已提供,若有且覆盖需求则优先采用,维护成本更低);若官方存在但受限或残缺(只读、仅 Pro、缺少所需端点),则本地服务器是合理的,并应在 README 中说明,tidycal-mcp 即如此处理;单用户单机用本地 stdio 服务器,多租户、客户端各自登录则属于 OAuth 2.1 + DCR + PKCE 加三个 well-known 端点的另一类更大工程,应改用 agents-sdk 技能;是否一个普通脚本就够——用户每月只取一个数字时脚本优于服务器,只有当 Claude 需要在对话中反复、主动地访问数据时服务器才值得存在。
二、步骤 1:侦察 API 绝不要凭对 API 的记忆设计工具,先拿到真实表面。需要确定:鉴权(头部形式、令牌类型、用户从哪里获取、套餐是否限制 API 访问);基础 URL 以及是否带账户前缀(如 https://<tenant>.example.com/rest/);分页方式(页码、游标或无分页)与每页上限;枚举值(不少 API 遇到一个未知枚举会直接拒绝整个查询,例如 Twenty 返回裸 400,应从元数据端点读取而非猜测);单位与结构(金额用分还是微单位、时间戳时区、ID 是数字还是 UUID);响应体量(若列表行内联 4 KB 嵌套对象,工具输出必须瘦身);限流与 429 的形态;写操作的副作用(哪些调用会发邮件、扣费或不可逆)。若厂商提供 OpenAPI 规范,保存到 server.py 旁边(<service>_openapi.json);若只有 Redoc 页面,则从中提取并在 README 注明是提取而非抓取。
对于文档稀缺的细分 SaaS,侦察本身就是主要工作量:基础 URL 常常只在产品内部(如 设置 → 集成 → API),应先请用户去那里查看再探测;403 与 404 含义不同——404 表示端点不存在,403 表示存在但凭证类型不对(通常是管理员/浏览器会话路由,API key 永远打不开),盲目探测前先分清;文档 slug 不等于真实路径,路径应从请求示例和侧边栏获取;分页要实证验证而非相信参数名——用两页取交集、对比并集与 total,注意参数被静默忽略是常态而非报错;每个数字在工具上线前都要与一个已知真值核对,返回合理值的字段不等于真实字段;限流可能返回 HTML 而非 JSON,应放慢请求并把非 JSON 响应体当作真实可报告的结果;未来/空记录会扭曲聚合值,工具计算时必须明确哪些行在范围内。
三、步骤 2:设计工具表面 端点到工具的机械一一映射是默认的失败方式,会产出 40 个各带噪声的工具。应按“任务”而非“端点”设计。规则包括:工具命名在薄包装时用 <service><verb><thing>,在组合型服务器上用任务名(如 queue_today、account_card),前缀可避免两个服务器都暴露 list_contacts 的混淆;至少加一个组合工具,一次调用回答真实问题;对载荷瘦身,例如 tidycal_agenda 相当于去掉内联的预约类型、邮件模板与分享 URL 后的 list_bookings,数据相同但体积约为 1/30;用注解区分读写(ToolAnnotations(read_only_hint=True, ...)),写操作由环境变量开关控制,默认表面不能改动任何东西;对写入真实系统的操作使用两步确认:第一次调用返回 {preview, confirm_token} 且不改动任何东西,第二次以相同参数加令牌才应用,守卫在服务器而非提示词中;当任务需要按特定顺序组合多个工具时提供 get_guide(task),把流程写进服务器;任何消耗额度或金钱的操作前提供免费的 estimate_*;空结果是结果而非沉默,无数据的桶应返回 count: 0 与 empty_because,以区分“没有行”和“该字段从未被填充”;降级而非崩溃,若第二个集成未配置,其工具返回 {"<x>_wired": false, "reason": ...} 而服务器其余部分继续工作;把陷阱写进 docstring,因为工具 docstring 是模型调用那一刻唯一读到的文档,应注明哪个参数有问题及替代做法、哪个返回字段不可信、哪个字段已用真实数字验证、两次读取之间的差异意味着什么;instructions 块(MCPServer 的 instructions= 参数)会加载进每个会话,应放置领域名词表、两三个核心工作流以及诚实的标准,避免让模型多花用户额度的倾向性表述;编码前把计划中的工具清单(名称、一句话用途、读/写)给用户确认。
四、步骤 3–7:脚手架、密钥、验证与注册 用 scripts/scaffold.py 生成目录,参数包括 --slug、--server-name、--title、--base-url、--env-prefix、--dir;生成的 server.py 可执行、带 uv shebang 与 PEP 723 内联依赖(无需 venv 与 requirements.txt),并已包含请求层、错误映射、令牌加载、写门、get_guide、确认令牌助手与 --check。先保持单文件,当出现共享依赖的同级模块(报表脚本、缓存、导出)再改为带 pyproject.toml 的目录形式。密钥有两个已知陷阱:Claude Code 从 GUI 启动,不会 source ~/.zshrc,因此必须支持 0600 令牌文件作为回退(~/.config/<slug>/token);用户往往只粘贴裸 key 而非 KEY="...",加载器应去空白并接受两种形式,否则令牌会静默为空导致 403。交付密钥分两步,先创建并打开文件,再让用户粘贴后保存。注册前用 uv run --script "<path>/server.py" --check 验证,它会调用最便宜的需要鉴权的端点并打印账户身份与写是否启用,绝不打印令牌。注册始终使用 --scope user,项目作用域会写入共享/提交的 .mcp.json 造成密钥泄露且绑定确切 cwd。服务器仅在会话开始时加载,需提示用户重启 Claude Code。README 需包含 Requirements & integrations 表、带默认值的环境变量表、设置步骤、--check 行、按读写拆分的工具清单,以及侦察中发现的 API 怪癖说明;再为服务器写一份记忆文件,记录它包装什么、令牌在哪里、发现的陷阱与尚未测试的内容。
五、发布前清单与参考文件 清单包括:--check 通过且不打印密钥;读工具标注为只读、写操作由环境变量开关控制;至少一个节省往返的组合工具;大的列表响应已瘦身;空结果带 empty_because;可选集成以原因降级而非抛错;令牌可从环境变量与 0600 文件加载且接受裸 key;以 --scope user 注册、会话已重启、工具可见;README 含 Requirements & integrations 表;任何可能公开推送的内容中都没有令牌、客户端名或密钥。参考文件:references/recon.md(找真实基址与路径、探测鉴权、实测分页、发现枚举、用已知真值验证数字,步骤 1 阅读)、references/patterns.md(完整服务器模式与理由,设计工具前阅读)、scripts/probe.py(只读探测:带 403/404 判定的路径扫描,以及报告页面重叠与不同 ID 的分页测试)、scripts/scaffold.py(生成仓库,其渲染模板为 assets/server_template.py 与 assets/README_template.md)。
关于支持的 API 类型、平台限制、收费与价格等信息,现有资料暂未提供。