用途
本技能用于指导使用 stdio 传输的 MCP 服务器内部的 Python 代码约定。它与通用 Python 约定技能不同:本技能只负责“因为代码是 MCP 服务器而不同”的部分,而这些差异中有两项属于协议正确性问题,而非风格偏好。它不涉及发布相关事项(入口点、uv tool install、claude mcp add、作用域选择等属于 mcp-server-shipping),只关注代码在运行时的行为。
主要能力
MCP-stdio 日志纪律
适用范围:仅限 stdio 传输的 MCP 服务器(*-polite-mcp 系列),不适用于本身没有 MCP 服务器的仓库。
相关片段:references/snippets/mcp-tool-boundary.py
默认要求:服务器包代码中绝不使用裸 print()。所有日志通过标准库 logging 模块,并在启动时显式配置写入 stderr(或交由 FastMCP 自带的 configure_logging(),其默认即写入 stderr)。
原因:MCP stdio 规范明确要求,服务器不得向 stdout 写入任何非有效 MCP 消息的内容;一次多余的 print() 或某个依赖项指向 stdout 的日志处理器都会破坏 JSON-RPC 流。stderr 是所有内容(包括日志)被允许的输出通道。
注意事项:不要以为“我的代码里没有 print()”就足够——某个依赖项自行向 stdout 写日志的情况,不会被你自己显式的 stderr 配置捕获。可靠的检查方式是端到端运行真实的 stdio 传输,而不是仅做代码审查。
模型默认行为:这是覆盖式规则,而非风格微调。这是模型没有通用 Python 理由去知道的协议特定知识;缺少它,模型会像在其他脚本中一样用 print() 调试,从而悄无声息地破坏服务器。
MCP 工具边界的错误处理
适用范围:同上,仅限 stdio 传输的 MCP 服务器。
相关片段:references/snippets/mcp-tool-boundary.py
默认要求:在内部异常即将返回客户端时,审慎决定什么内容可以安全暴露——要么重新抛出为 fastmcp.exceptions.ToolError 并附上明确手写的消息,要么让普通异常直接抛出(FastMCP 默认会将其不加遮蔽地呈现给客户端)。绝不要默认认为任意被捕获异常的 str(exc) 是安全的,尤其是在宽泛的逐项 except Exception 中(这是批处理调用中隔离单个坏项的合理模式——只是别让其中捕获异常的文本未经审查就到达客户端)。
原因:FastMCP 的默认行为(mask_error_details=False)已在面向客户端的响应中包含完整异常细节——这不是可选风险,而是开箱即用的行为。这与本技能中 SecretStr 的注意事项形状相同:一个宽泛的安全开关并不会净化你刻意选择暴露的文本。
注意事项:不要为了图省事而项目全局开启 mask_error_details=True——它会压制那些合法且有用的验证细节(如错误参数、批次大小违规),而普通 raise ValueError(...) 调用点正是依赖这些细节被调用方智能体看到。更倾向于更细粒度的逐消息 ToolError 选择。
模型默认行为:这是覆盖式规则。除非被告知,模型不知道 ToolError 存在,也不知道 FastMCP 默认会不加遮蔽地呈现异常——缺少这一点,它要么让异常原样传播(本系列目前的实际状态),要么求助于全局遮蔽开关,两者都不如逐边界的慎重选择。
MCP 工具文档字符串
适用范围:任何被装饰为 MCP 工具的函数(本系列中的 @mcp.tool())。这与通用文档字符串风格截然不同——本技能中不存在可扩展的通用文档字符串内容规则。
默认要求:按 Anthropic 的工具定义标准而非 PEP 257 来写文档字符串——说明工具做什么、与同名近邻工具的区别、何时使用/不使用、每个非显然参数的取值来源、响应形态与大小注意事项,至少 3–4 句,复杂工具需更多。具体模板和本系列自身最强的真实示例见 references/rationale.md §11。
原因:文档字符串会成为线路级的 Tool.description,供 LLM 客户端在推理时读取,以决定是否以及如何调用该工具——糟糕的文档字符串会导致选错工具、传错参数或从不被调用,这是每次未来调用都要付出的正确性代价,而非人类可读文档字符串那种理解速度代价。
升级方式:当自由文本不够用时,改用 Annotated[x, Field(description=...)] 提供逐参数描述(使 JSON-Schema inputSchema 本身携带这些描述);对任何有实际副作用的工具使用 annotations=(readOnlyHint/destructiveHint 等),因为客户端据此决定何时跳过或要求确认提示。
模型默认行为:这是覆盖式规则。模型默认的文档字符串本能是 PEP 257 式的——简洁的一行摘要——在这里反而更糟;本节的要点正是:面向 LLM 的描述标准不同于普通文档字符串风格,而不是其更严格的版本。
使用方式
安装后,本文件会被复制到 ~/.agents/skills/mcp-python-conventions-taudelta,从不使用符号链接,因此编辑已部署副本属于本地漂移——这正是本技能旨在防止的情况,且不会影响其他机器。正确的做法是在安装来源的仓库中编辑源文件,推送后重新运行 skills add <that source> --global --skill mcp-python-conventions-taudelta,以刷新每个项目的副本。如果你是从他人仓库而非自己的 fork 安装的,源就是他们的:请在那里提 issue 或 pull request。
适用场景
适用于编写 MCP 服务器内部 Python 代码、并需要决定其行为方式的场景,尤其是使用 stdio 传输的 MCP 服务器。
限制
不适用于没有自带 MCP 服务器的仓库;不涉及发布流程(入口点、安装命令、客户端添加与作用域选择)。完整依据、stdout 约束来源、错误分类推理以及文档字符串即契约的论证见 references/rationale.md。可运行的边界错误处理草稿见 references/snippets/mcp-tool-boundary.py。