如何构建MCP服务器:TypeScript与Python双版本实现对比
【免费下载链接】skillsPublic repository for Agent Skills项目地址: https://gitcode.com/GitHub_Trending/skills3/skills
本文以接入GitHub等外部服务的MCP服务器为例,讲清TypeScript与Python两种MCP服务器实现的选型、工具设计、输入校验、分页、错误处理、测试与部署要点,每个结论都对应可落地的工程做法和最小代码。
为什么AI助手需要一个MCP服务器
让模型"给这个bug建一张Jira工单",它只能回复"你需要登录Jira然后点……"——它听得懂,但做不了。MCP(Model Context Protocol)服务器补的就是这一环:把外部服务的操作封装成一组标准化的"工具"注册到服务器上,模型按名称挑选工具、传入参数、拿到结果,整个过程和普通函数调用很像。
衡量一个MCP服务器好不好,不是它包了多少API端点,而是模型能不能顺畅地用这组工具把真实任务做完。所以命名、校验、响应格式、分页、错误处理这些细节都有明确的工程要求,下面逐一拆开。
TypeScript还是Python:MCP服务器语言怎么选
两种语言都有官方SDK,差异集中在开发体验和约束上:
| 维度 | TypeScript | Python |
|---|---|---|
| 官方框架 | @modelcontextprotocol/sdk 的McpServer | FastMCP(Python SDK 的高层封装) |
| 工具注册 | server.registerTool()显式调用 | @mcp.tool()装饰器 |
| 输入校验 | Zod schema | Pydantic 模型 |
| 工具描述 | 必须显式写在description字段 | 由函数签名和 docstring 自动生成 |
| 项目命名 | {service}-mcp-server(连字符) | {service}_mcp(下划线) |
| 适合场景 | 远程服务、需要静态类型和编译检查的项目 | 快速原型、中小规模项目 |
官方技能库的 mcp-builder 指南把 TypeScript 列为首选:SDK 质量高、静态类型对 AI 生成代码更友好、社区示例多。Python 的优势是快——FastMCP 从 docstring 直接生成工具描述,一个工具往往不到十行。真正影响决策的只有一条:服务器要作为多客户端共享的远程服务,选 TypeScript;只是本地自用的集成,选 Python。
MCP工具设计的5个关键决策
命名用"服务前缀+动作动词"
工具名用 snake_case,格式是{service}_{action}_{resource},写github_create_issue而不是create_issue。原因是模型环境里常常同时挂着好几个 MCP 服务器,不带前缀会重名,模型会拿错工具。名字还要以动词开头(get、list、search、create),让模型按任务就能定位。
服务器命名同理:Python 用{service}_mcp,Node 用{service}-mcp-server,取通用名、不带版本号,从服务名就能推断出用途。
用Zod或Pydantic做输入校验
不要相信模型传进来的参数。所有入参都该经过 schema 在运行时校验:
const SearchInputSchema = z.object({ query: z.string().min(2).max(200) .describe("搜索关键词,例如 'mcp server'") });z.object声明输入结构,.min()/.max()约束长度,越界的输入会被直接拦下,报错信息还能回传给模型。Python 侧用 Pydantic 模型,并建议打开两个配置:
class SearchInput(BaseModel): model_config = ConfigDict(str_strip_whitespace=True, extra="forbid") query: str = Field(..., min_length=2, description="搜索关键词")str_strip_whitespace=True自动去掉首尾空格,extra="forbid"拒绝未知字段,防止模型悄悄塞进来没声明过的参数。
同一份数据,准备两种响应格式
返回数据的工具最好支持response_format参数,让调用方二选一:JSON 格式面向程序处理,字段和元数据全量给出;Markdown 格式面向模型阅读,用标题和列表组织,时间戳转成可读形式,显示名后括号里带 ID。Markdown 版能省上下文 token,也更好理解。
分页给默认值,别一次拉全量
列出资源的工具一律尊重limit参数,默认 20~50 条,并在响应里带上分页元数据:
{ "total": 150, "count": 20, "offset": 0, "items": [], "has_more": true, "next_offset": 20 }has_more说明后面还有没有,next_offset告诉调用方下一页从哪开始。数据集大时尤其不能把全量结果读进内存再返回。
错误信息要"可操作"
工具失败时,返回的错误要给出具体建议而不是堆栈:404 就写"资源未找到,请确认 ID 是否存在",限流就附上可重试的时间。官方实践还要求把工具错误放进结果对象内部上报,而不是抛成协议级错误——这样模型能看到失败原因并自行调整重试。
另外,每个工具都应声明四个注解:readOnlyHint、destructiveHint、idempotentHint、openWorldHint,告诉客户端这个工具是否只读、会不会破坏性修改、能否重复调用。它们只是提示不是安全保证,但能帮客户端决定调用前要不要找用户确认。
TypeScript与Python的MCP最小实现
TypeScript:registerTool显式注册
TypeScript MCP 实现的骨架是 package.json、tsconfig.json,加src/(入口index.ts,按域拆分的tools/、共享的services/、Zod schema 所在的schemas/),编译产物在dist/。核心注册模式:
server.registerTool( "github_search_repos", { title: "Search GitHub Repositories", description: "按关键词搜索仓库,返回名称、星标数与简介。", inputSchema: SearchInputSchema, annotations: { readOnlyHint: true, destructiveHint: false } }, async ({ query }) => fetchRepos(query) );registerTool向服务器注册一个可被调用的操作,第三个参数是真正的执行函数。注意用新的register*系列 API,旧的server.tool()已废弃。
Python:FastMCP装饰器少写样板
mcp = FastMCP("github_mcp") @mcp.tool(name="github_search_repos") async def github_search_repos(params: SearchInput) -> str: """按关键词搜索 GitHub 仓库,返回名称、星标数与简介。""" ...FastMCP("github_mcp")完成服务器初始化,参数即服务器名。函数的 docstring 自动成为工具描述,Pydantic 参数类型自动变成输入 schema,不用手写字段——这是它和 TypeScript 版最大的差别。
MCP服务器测试:编译检查、MCP Inspector与评估题
测试分三层做:
- 编译与语法检查:TypeScript 跑
npm run build确认没有类型错误;Python 跑python -m py_compile server.py验证语法。 - MCP Inspector 功能测试:
npx @modelcontextprotocol/inspector打开一个本地可视化调试页,能看到全部已注册工具,并逐个手动调用、检查校验与响应格式,这是 MCP 服务器教程里最直接的功能验证手段。 - 10道复杂评估题:编写 10 道真实、独立、只读、答案稳定的问题,让模型纯靠工具自己作答,再按答案比对打分。这一步检验的是"任务完成度",补上了单工具测试覆盖不到的组合能力,写法细则见 评估指南。
发布前再对照检查:所有工具是否都用了 schema 校验?列表类工具是否都有分页?错误信息是否带下一步建议?大响应是否做了字符限制和截断?
MCP服务器部署:本地stdio与远程Streamable HTTP
| 场景 | 传输方式 | 说明 |
|---|---|---|
| 本地开发、单用户集成 | stdio | 服务器作为客户端子进程,走标准输入输出,无需网络配置 |
| 远程服务、多客户端共享 | Streamable HTTP | 基于 HTTP 的双向通信,用无状态 JSON 更易于扩展 |
选择标准很简单:本机跑就用 stdio,服务多人就上 Streamable HTTP。两个容易踩的坑⚠️:stdio 服务器的 stdout 被协议独占,日志必须打到 stderr;Streamable HTTP 服务若在本机运行,绑定127.0.0.1并校验 Origin 头,防止 DNS rebinding 攻击。更多细节见 最佳实践文档。
两种语言在传输层的写法一致:TypeScript 是npm run build后npm start,Python 直接拉起进程即可。选型和五个设计决策定下来之后,一个能用的 MCP 服务器,一下午就能跑起来。
【免费下载链接】skillsPublic repository for Agent Skills项目地址: https://gitcode.com/GitHub_Trending/skills3/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考