考察点
这是把 MCP 从概念落到代码的题,面试官想确认你真的动手写过,而不是只读过文档。能讲清「声明工具—接传输—联调—部署」这条链路,并说出几个只有踩过坑才知道的细节,就是合格答案。追问方向:传输怎么选、怎么调试、怎么做鉴权。
参考答案
开发流程总览
官方有 TypeScript 和 Python 的 SDK,社区还有 Java、Go 等实现。以 Python 的 FastMCP 为例,一个最小 Server 几十行就能跑:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("order-server")
@mcp.tool()
def query_order(order_id: str) -> dict:
"""按订单号查询订单状态和金额。
Args:
order_id: 订单号,格式为 16 位数字
"""
return db.query("SELECT status, amount FROM orders WHERE id = %s", [order_id])
if __name__ == "__main__":
mcp.run(transport="stdio")
SDK 会自动从函数签名和 docstring 生成工具的 JSON Schema,处理 JSON-RPC 消息的编解码、能力协商和生命周期。你写的几乎只有业务函数本身。
关键工程点
1. schema 即文档。SDK 从 docstring 生成 description,所以 docstring 就是给模型看的工具说明书,要按「写什么、何时用、参数约束、返回什么」写全,别用一句话糊弄。这是 Server 质量的第一决定因素。
2. 返回值面向模型设计。返回结构化但精简的 dict,剥离模型用不到的内部字段;出错时返回可读的错误描述(「订单不存在,请核对订单号」),不要把异常堆栈直接抛给模型。SDK 支持把错误标记为 tool error 而不是协议错误,模型拿到后能自我纠正。
3. 传输方式按部署形态选。本地集成(Claude Desktop、Cursor)用 stdio,Client 配置里指定启动命令拉起子进程;给团队或跨组织提供的服务用 Streamable HTTP,挂到网关后面。SDK 通常一行参数切换。
4. 远程 Server 必须处理鉴权和多租户。Streamable HTTP 模式下用 OAuth 2.0 或 API Key 做身份校验,把调用方身份透传到业务逻辑里做数据隔离——用户 A 的会话绝不能查到用户 B 的订单。无状态模式下别在内存里存会话级状态,否则水平扩容就出问题。
5. 资源与工具的分工。只读的上下文数据(表结构、配置文档)暴露为 Resources,让 Host 侧按需读取;有副作用的动作暴露为 Tools。全塞进 Tools 会让模型产生「读个文档也要调用」的误判。
调试与联调
官方调试工具 MCP Inspector 是标配:命令行指向你的 Server,就能在网页里列出所有工具、手动发 tools/call 请求、看原始 JSON-RPC 报文。联调顺序建议:先用 Inspector 验证协议层行为正确,再接到真实 Host(比如 Claude Desktop 或自己的 Agent 框架)测端到端,最后在 Host 里观察模型选工具、填参数的实际表现,回头迭代 description。协议对了但模型用不对,是这个环节最常见的问题。
部署与发布
本地 Server 随 Host 拉起,没有部署问题。远程 Server 当普通 Web 服务运维:健康检查、日志里带 session id 方便追链路、对 tools/call 的延迟和错误率单独监控。对外发布可以提交到公开的 MCP registry 或公司内部的注册中心,附上能力说明和鉴权申请方式。
可能的追问
- SDK 自动生成的 schema 不够用怎么办? SDK 都支持显式声明 inputSchema 覆盖自动推导,复杂参数(嵌套对象、联合类型)建议显式写,别依赖类型注解推导。
- Server 需要调 LLM 怎么办? 协议支持 Server 反向发起 sampling 请求借 Host 的模型用,但要谨慎:这会引入双向依赖和成本归属问题,多数场景 Server 自己调模型 API 更清晰。
- 现有 REST API 怎么快速包成 MCP Server? 写一层薄适配:每个核心端点对应一个 tool 函数,内部调原 API,重点是重新写面向模型的 description 和裁剪返回字段,不要原样透传 OpenAPI。