用途:面向为 LLM 客户端(如 Claude Desktop、Claude Code)构建 Python MCP 服务器的开发者,总结工具设计、错误处理、子进程封装、打包与测试中反复出现的坑与模式。
主要能力与要点: 错误契约:不要抛出未捕获异常,改为返回统一结构(常见为含 error 键的 dict),并让调用方检查;批量工具必须返回逐项 skipped/errors 列表,不能静默 continue。注意 YAML 会把未加引号的 ISO 日期解析为 date 类型,校验时需枚举解析器可能产生的所有类型。
子进程/CLI 封装:非零退出码不等于失败,应同时返回 stdout 与 stderr 交给模型判断;固定所封装工具的实际版本并核对子命令;参数用 shlex.split,传 argv 列表,禁用 shell=True,并校验客户端提供的路径。
结构:避免模块级全局状态与导入时解析 CLI 参数,用工厂函数注入配置;工具只在一处注册,防止重复注册。
事件循环:不要假设框架会把同步工具放到工作线程,阻塞的数据库/文件/网络操作应改为 async 并用 asyncio.to_thread 移出事件循环;注意连接归属,避免跨线程共享线程亲和连接。测试应验证慢工具阻塞时轻量请求仍能完成,而非只断言慢调用结果。
采样:ctx.sample 是可选客户端能力,需在工具内捕获异常并转换为统一错误结构,try 块保持窄范围,并分别测试不支持采样与处理器抛错两种情况。
分发:避免 server.py 与 server/ 包同名冲突;构建配置需包含整个包与数据文件;PEP 723 单文件服务器应在内联脚本头固定版本并与 pyproject.toml 同步。
测试:至少保留一个调用真实工具的集成测试,避免只 mock argv;测试错误契约与批量 skipped。
安全:工具输入、文件内容与其他工具描述都可能被攻击者影响,构成提示注入面,输出应视为建议而非可信指令,限制文件系统/网络权限并校验路径。
限制:资料中的 FastMCP 装饰器示例不直接适用于该仓库的 mcp/server.py(手写 stdio JSON-RPC 服务器),但多数原则可迁移;事件循环一节不适用于同步 stdio 服务器。具体安装命令与版本号资料未提供。