MCP 服务器实战让模型连上外部 API【免费下载链接】skillsPublic repository for Agent Skills项目地址: https://gitcode.com/GitHub_Trending/skills3/skills你让模型查一下这个仓库的 Issue顺便打个 bug 标签它却连 API 都不会调只能你每次手写请求、再把结果贴回去。skills 仓库里的 mcp-builder 技能给了一套完整的 MCP 服务器搭建流程用 TypeScript 或 Python 把任何外部服务接进模型API 调用从此不用手写胶水代码。30 秒跑起来把下面内容存成mcp.py这是可用服务器的最小骨架from mcp.server.fastmcp import FastMCP mcp FastMCP(github_mcp) mcp.tool(namegithub_list_issues, annotations{readOnlyHint: True}) async def github_list_issues(repo: str) - str: 列出指定仓库的 Issue。 return f{repo} 的 Issue这是占位实现稍后接真实 API if __name__ __main__: mcp.run()python mcp.py # 启动默认 stdio 传输 npx modelcontextprotocol/inspector mcp.py # 打开可视化测试页Inspector 打开后工具列表里会出现github_list_issues点一下执行立刻返回字符串说明服务器活了。整个流程里你只做了声明工具这一件事协议握手、JSON-RPC 封包、传参全是框架干的。执行结果能正常回显就证明收到请求、调用函数、返回结果这一圈走通了之后把函数体换成真实 API 调用协议层一行不用动。核心机制拆解工具声明的最小代码每个工具就像插在模型身上的标准插座设备是什么无所谓插头形状对得上就能用。落到协议上工具由名字、描述、输入 schema 和处理器四件事组成。TypeScript 与 Python 写法同构只是形态不同TypeScript官方 SDKPythonFastMCPconst server new McpServer({ name: github-mcp-server })server.registerTool(github_list_issues,{ title: List Issues, description: 列出仓库全部 Issue,inputSchema: IssueSchema, annotations: { readOnlyHint: true } },async (params) callApi(params))mcp FastMCP(github_mcp)mcp.tool(namegithub_list_issues,annotations{readOnlyHint: True})async def github_list_issues(params: IssueQuery) - str:return await call_api(params)命名规范两者不同TS 服务器名用连字符{service}-mcp-serverPython 用下划线{service}_mcp。工具名两种语言保持一致服务前缀加蛇形命名比如github_list_issues、slack_send_message前缀的作用是防止和同一客户端下的其他工具撞名。四件事各有各的用途。name 是模型调用的入口description 是模型选工具的依据input schema 不止用来校验它还会原样发给模型模型看着字段约束生成合法参数handler 才是你唯一要写业务逻辑的地方。annotations 字段则提前声明工具危不危险查询类工具把readOnlyHint设为true删除类把destructiveHint设为true客户端可以据此决定是否弹确认框。输入校验Zod 与 Pydantic 怎么写你可能会问模型乱传的参数怎么办校验层就是答案也是两种语言最像的地方。TS 用 Zod 写结尾加.strict()拒绝多余字段const IssueSchema z.object({ repo: z.string().min(2, 仓库名至少 2 个字符) .describe(格式 owner/repo如 vercel/next.js), limit: z.number().int().min(1).max(100).default(20) .describe(每页最多返回条数默认 20), offset: z.number().int().min(0).default(0) }).strict();Python 用 Pydantic模型类一份代码兼任校验规则和参数文档class IssueQuery(BaseModel): model_config ConfigDict(str_strip_whitespaceTrue, extraforbid) repo: str Field(..., min_length2, description格式 owner/repo) limit: int Field(default20, ge1, le100, description每页最多返回条数) offset: int Field(default0, ge0)两种语言里校验报错都不用你亲自 catchSDK 会先拦截转成模型能看懂的错误响应。但报错质量取决于你写在 schema 里的文案仓库名至少 2 个字符明显比框架默认提示有用。这里容易踩的坑TS 的 SDK 不会从 JSDoc 注释自动提取 description 字段不显式写出来模型就只看得见参数名传参全靠猜。Python 侧相反docstring 会被自动收进工具描述所以把返回值结构、错误情形、什么时候别用本工具直接写进 docstring这段文字就是模型的说明书。返回值长什么样返回值不是给你看的是给模型看的。上下文窗口是模型的短期记忆装什么、怎么装都得讲究。通行做法是支持两种格式默认 markdown时间戳转成人类可读ID 写在显示名括号后面冗余元数据砍掉客户端要程序化处理时传 json返回完整结构化字段字段名保持稳定。字段选取本身也是设计markdown 格式里一个用户对象只留 id、name、team别把各种尺寸的头像 URL 全塞回去json 格式则保留完整字段把过滤工作留给客户端。两种格式共用同一份数据源只是渲染不同。列表类工具的 JSON 返回值遵循一组固定字段{ total: 42, count: 20, offset: 0, items: [], has_more: true, next_offset: 20 }模型拿has_more判断还要不要再翻拿next_offset直接填进下一次调用不用猜。这里容易踩的坑只返回数组不带元数据模型不知道数据是否拿全要么反复调用要么在残缺数据上做错误判断。生产级加固错误响应怎么设计才不踩坑问题下游 API 返回 429你把原始堆栈一抛模型读不懂只会原地重试。做法错误文案统一收口到一个函数每条信息都带下一步动作。def _handle_api_error(e: Exception) - str: if isinstance(e, httpx.HTTPStatusError): code e.response.status_code if code 404: return 错误资源未找到请检查 ID 是否正确 if code 429: return 错误触发限流请稍后再试 return f错误API 返回状态码 {code} if isinstance(e, httpx.TimeoutException): return 错误请求超时请重试TS 侧思路相同捕获AxiosError按状态码分支超时时用ECONNABORTED识别。状态码之外超时与连接失败也要单独分支否则网络抖动会被当成 500 类错误上报模型会做错误的重试决策。错误文案的标准和维修店贴条一样请带证件明日再来是好的错误交易失败是坏的。分页与截断的字段约定问题一个仓库几千个 Issue一次全返回会撑爆上下文单次调用成本失控。做法limit上限压到 100每页默认 20对返回文本设CHARACTER_LIMIT示例里这个常量取 25000超了截半并附说明。const CHARACTER_LIMIT 25000; if (result.length CHARACTER_LIMIT) { response.truncated true; response.truncation_message 响应已截断请使用 offset 参数获取更多结果。; }六个分页字段各司其职total 是总量count 是本次条数offset 是当前起点items 是数据has_more 表示还有没有下一页next_offset 是下一页该填的值。模型不理解翻页这个概念但它理解还有下一页参数在这里。这里容易踩的坑是静默截断truncated标记和截断说明就是逼着模型去补数据或加过滤条件。验证与上线本地调试用 stdio 就够两步走完npm run build node dist/index.js # TS先编译再走 stdio npx modelcontextprotocol/inspector mcp.py # 或启动 Python 版做可视化测试远程上线切换 Streamable HTTPTS 用StreamableHTTPServerTransport配合 express每个请求新建一个 transport走无状态 JSON不持有会话横向扩容省事Python 只要mcp.run(transportstreamable_http, port8000)。工具代码一行不改传输层只是服务器穿的衣服工具本身不关心对端是管道还是网络。HTTP 起好后把 Inspector 指向远程端点验证路径与本地完全一致。单工具跑通之后下一步是把另一个服务前缀接进来或把过大的工具拆成职责更小的两个。mcp-builder 流程里还有一步值得做写 10 个真实业务问题让模型只用你的工具作答看它在哪里卡住。更多模式细节可以看仓库里的 TypeScript 实现指南 与 Python 实现指南。【免费下载链接】skillsPublic repository for Agent Skills项目地址: https://gitcode.com/GitHub_Trending/skills3/skills创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考