- 桌面应用
- RPA
- 计算机视觉
【免费下载链接】ZenlessZoneZero-OneDragon
绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄
本文是对 mcp-implementation.md 的深度展开。绝区零一条龙(ZenlessZoneZero-OneDragon)通过 MCP 适配器把游戏自动化 backend(
ZzzBackendContext)暴露给 Claude Code 等 AI 编码工具,本文是该适配器内所有@mcp.tool的「代码怎么写」落地规范:涵盖 annotations 分类标注、Field 参数描述、结构化返回与错误兜底、docstring 三要素、命名、evaluation 缺口与改动同步 checklist。读完本文,你将掌握为本项目新增 / 修改 MCP tool 时逐项对照的完整实现基准,并能结合源码理解每条约束背后的原因。
适用范围:src/zzz_od/backend/mcp/ 下的
app.py/service_app.py/prompts.py中所有@mcp.tool。SDK 基线为官方mcp>=2,<3包内置的MCPServer(from mcp.server import MCPServer)。
定位:与设计原则配对的「实现层规范」
本项目 backend 文档体系分三层:design-principles.md是「设计原则」(agent 能力视角,回答为什么这么设计、tool 该不该有),mcp.md/http.md是「现状 spec」(回答现在有哪些能力),而本文是「代码怎么写」的落地规范。三者关系如下:
- design-principles.md:MCP tool 设计的纲领,从「智能体能做什么 / 做不到什么」推导 tool 该提供什么。其中 P3(操作 vs 观察分离)、P9(docstring 是筛选 prompt)、P11(MCP / HTTP 对称暴露)、P13(观察类可选持久化)、P14(能力边界提示)等原则在本文都有对应的代码级落地。
- mcp.md:22 个
@mcp.tool的工具表现状,本文第 7 节 checklist 的「同步工具表」对象。 - http.md:并行 HTTP 适配器,是返回结构对称性的比对基准。
通用 MCP tool 设计方法论(tool 命名 / description 契约 / 严格 input·output schema / annotations / 结构化返回 / actionable error / 读写分离 / token 经济)遵循 Anthropic 官方mcp-server-devplugin 的tool-design.md,本文只讲项目特化写法,不重复通用知识。写 / 改 MCP tool 前建议先安装该 plugin,安装方式见 docs/develop/setup/ai_coding.md。
1. annotations:本项目 tool 的分类标注
双标原则(对应 design P3,缺一不可)
- docstring 首句点明「观察类 / 操作类」——给人 + 模型读的筛选 prompt;
@mcp.tool(annotations=ToolAnnotations(...))机器可读——给客户端按副作用筛选 / 自动确认 / 缓存。
两个标注服务于不同消费者(人 / 机器),任何新 tool 都必须同时具备。从 app.py 源码可以看到实际写法,例如:
@mcp.tool(annotations=ToolAnnotations(read_only_hint=True, title="检查游戏窗口")) def check_game_window() -> WindowStatus | dict: ...本项目三分类
| 类别 | read_only_hint | destructive_hint | 本项目 tool |
|---|---|---|---|
| 纯观察(只读,不改状态) | True | — | check_game_window/capture_game_screen/analyze_screen/get_run_status/list_applications/list_operations/describe_operation/list_mcp_usage_guides/get_mcp_usage_guide |
| 操作游戏 / 触发运行 / 改配置(改状态非破坏) | 不标(默认非 read_only) | — | click_game/key_tap/drag/input_text/open_game/run_one_dragon/run_standalone_app/run_operation/stop_run/upsert_screen_area |
| 不可逆 / 破坏性 | 不标 | True | delete_screen_area(删 screen_info area)/close_game(关游戏) |
本项目特化:两个 hint 默认不标
open_world_hint/idempotent_hint默认不标——本项目 tool 都操作本地游戏运行时(属「外部世界」交互):open_world保持 MCP 默认语义即可;idempotent标了也无决策价值(click 幂等无需声明、run 不幂等)。判据只有一个:只在「客户端会因此改变确认 / 缓存策略」时才标。这个「不标」本身也是经过决策的约定,避免为标注而标注。
导入与命名细节
- 导入:
from mcp.types import ToolAnnotations; - Python 参数和属性使用 snake_case:
read_only_hint/destructive_hint/idempotent_hint/open_world_hint/title;SDK 序列化到 MCP JSON 时自动转成 camelCase(如readOnlyHint); - 工厂注册的 tool 同理:
mcp.tool(annotations=...)(make_xxx(backend)),见 service_app.py 中make_run_one_dragon/make_list_applications等模块级工厂被 app.py 注册的方式:mcp.tool(annotations=ToolAnnotations(read_only_hint=True, title="列出可运行应用"))(make_list_applications(backend))
2. Field 参数描述:哪些参数必须加
背景:MCPServer 不解析 docstring 的 Args 段
MCPServer 把函数签名转成 JSON schema,但不解析 docstring 的Args:段成字段 description——参数级说明只能靠Annotated[type, Field(description=...)]。这是很多 MCP server 实现容易踩的坑:docstring 写得再全,模型在 tool-call 时看到的参数描述来自 Field。
本项目必须加 Field description 的(智能体不靠参数名 + 类型就懂不了的)
- 布尔开关的隐式语义:
save_image/pc_alt/block/enter/use_clipboard——save_image=True会落盘并回传screenshot_path,pc_alt=True需要按住 Alt 解锁光标,use_clipboard=None跟配置走,这些语义仅靠bool类型完全无法表达; - 单位 / 默认特殊的:
press_time单位是秒(click 默认 0.1 是游戏识别下限、0=极短按可能无效,key 默认 0.0 是短按 tap); - 定位符格式:
op_id的<module>.<ClassName>格式、screenshot的路径 / 图名规则(纯名字到.debug/images/<名字>.png读); - 结构化入参:
args的 JSON 可序列化约束(@dataclass+from_dict参数可传 dict,其余复杂数据类走 application)。
不必加:纯坐标(x/y,docstring 已说明是 1080p 游戏空间)、无歧义标量。
分工不重复
- Field description写「参数是什么 / 取值约束」;
- docstring写「整体能做什么 / 何时用 / 副作用 / 返回」;
- 同一条信息只留一处。
官方示例(来自 app.py 的click_game,布尔开关 + 单位特殊的参数加 Field,坐标 x/y 不加):
def click_game( x: float, y: float, press_time: Annotated[float, Field(description="按住时长(秒);click 默认 0.1(游戏识别下限),0=极短按可能无效)")] = 0.1, pc_alt: Annotated[bool, Field(description="点击前是否按住 Alt 解锁光标;大世界等 pc_alt=true 画面必需")] = False, ) -> dict: ...再比如analyze_screen的screenshot参数,Field 说明了三种取值语义:「None=实时截当前画面(需游戏在线);传路径=读该图(无需游戏在线);纯名字=读.debug/images/<名字>.png」。这种三态语义如果不写 Field,智能体几乎必然传错。
3. 返回值:对称结构与错误兜底
与 HTTP 对称(对应 design P11)
同一 backend 方法,MCP 和 HTTP 返同构字段。例如:
check_window→ MCP 返WindowStatusdataclass(定义见 schemas.py)、HTTP/game/window返asdict(WindowStatus);- 运行状态三件套对称暴露:
open_game↔/game/enter、get_run_status↔/game/status、stop_run↔/game/stop,两侧调同一 backend 方法,跨适配器状态共享同一RunSlot(HTTP 触发的运行 MCP 也能查到)。
别在 MCP 把结构压成多行文本——文档明确指出这是早期check_game_window踩过的坑(已修)。多行文本破坏了结构化返回,模型无法按字段精确消费,也无法与 HTTP 侧对齐。
错误兜底:统一 try/except 返带 error 字段的结构,不 raise ToolError
尽管 SDK 原生支持raise ToolError,本项目统一不采用。理由:不把 opaque traceback 透传给客户端,返回 actionable 结构。两种落地方式:
- 成功返回 dataclass 本身带
success/error字段→ 错误也返该 dataclass(success=False, error=str(e))。典型:analyze_screen→AnalyzeScreenResult(定义见 schemas.py),错误分支返回AnalyzeScreenResult(success=False, ocr_texts=[], screens=[], error=str(e))。 - 成功返回 dataclass 不带错误字段→ 错误返
{'error': str(e)}dict,返回类型注解写成T | dict。典型:list_applications→ApplicationListResult | dict、check_game_window→WindowStatus | dict。
源码中每个 tool 都套了统一的工具层兜底,注释写明「工具层统一兜底,避免异常透传到 MCP 框架」,例如 app.py 的check_game_window:
try: return backend.check_window() except Exception as e: # noqa: BLE001 工具层统一兜底,避免异常透传到 MCP 框架 return {'error': str(e)}单值 ack 例外
close_game的约定文案(「已发送关闭游戏信号」)保持str——结构化无增益。因为它只是「信号已发出」的 ack,真正验证要再调check_game_window。
字段语义化命名
统一使用success/error/in_window/started这类语义化字段,避免 cryptic id。从实际返回结构看:click_game返{success, x, y, in_window, pc_alt, error?},open_game的并发拒绝返回{started, error, source, hint}——hint字段直接告诉智能体下一步该做什么(「先 get_run_status 查状态,或 stop_run 停止」),这就是 actionable error 的落地。
4. docstring 三要素(对应 design P9)
每个 tool docstring 至少包含三要素——design P9 的表述是「docstring 是筛选 prompt」,智能体在众多 tool 里选对工具的依据就是它:
- 一句话说能做什么 + 首句标「观察类 / 操作类」:首句标注让智能体在筛选时一眼区分只读与改状态工具,例如
check_game_window首句「检查绝区零游戏窗口状态(只读,不改状态)。观察类。」、click_game首句「点击游戏窗口内坐标(1080p 游戏空间,同 screen_info pc_rect 中心)。操作类。」; - 关键约束 / 隐式上下文:坐标空间、需窗口就绪、单跑道、操作后需 sleep等——把智能体猜不到的显式化。例如
click_game的 ⚠️ 提醒:「底层 click 无内置等待,点 UI 常触发画面切换(菜单/弹窗/进画面),连续操作或capture_game_screen前建议 sleep ~1s 等动画(否则截过渡帧)」;check_game_window还特别提醒「判游戏是否在跑看is_win_valid,勿据 win_title 判断」——win_title 是 controller 缓存的预期标题,游戏未启动时仍可能非 None。这类「反直觉」约束是 docstring 最有价值的部分; - 返回结构:
Returns:段写 dict / dataclass 字段。例如analyze_screen说明「决策优先看screens(精准命中 1 个is_precise=True;否则 top_n 个候选);需要散落文本再看ocr_texts」。
不啰嗦(context 有限),准确说清即可。文档给出的参考基线是新 tool(click_game/key_tap/drag)的密度——「那是踩坑后校准的基线」,后续新 tool 以它们为参照。
5. 命名:资源分组前缀 + 无歧义参数
通用规则(snake_case + 服务前缀 + 动词导向)之上,本项目 tool 按资源分组前缀:
- game 感知 / 直接动作:
check_game_window/click_game/capture_game_screen; - 运行:
run_*(run_one_dragon/run_standalone_app/run_operation); - 查询:
list_*/describe_*/get_run_status; - screen_info CRUD:
upsert_screen_area/delete_screen_area。
参数名无歧义:op_id不写id,use_clipboard不写way。命名空间前缀(design P10)帮智能体在多 server 多 tool 时选对。
6. 借鉴官方 Phase 4 evaluations(本项目缺口,待补)
官方 mcp-builder 把「造 evaluations」作为第 4 阶段:写完 MCP server 后,造10 个只读、复杂、可验证的问题,测 LLM 能否用好它。每题要求:独立 / 只读 / 复杂(多 tool 调用)/ 现实 / 可验证(单一明确答案)/ 稳定。
本项目 MCP tool 目前只有单元测试(mock backend,验证委托与返回结构),缺这套「LLM 好用度」评估——即「智能体光看 tool 描述 / 参数 / 返回,能否选对工具、传对参数、读懂结果」。这正是设计原则 P9 的闭环验证:docstring 是筛选 prompt,但 prompt 写得好不好,只有用真实问题集测过才知道。
后续可针对本项目典型场景(查运行态 / 进游戏 / 分析画面 / screen_info 建模)造问题集,验证描述 / 参数 / 返回是否让 LLM 用得准,反哺本文第 2 / 4 节(Field 描述与 docstring 三要素)。值得注意:仓库内zzz-od-test/test/zzz_od/backend/测试目录属于外部测试仓库(当前仓库不含),文档第 7 节提到的单元测试断言即指该处。
7. 改动同步 checklist:改 / 加 MCP tool 后逐条对照
改 / 加 MCP tool 后逐条对照(原文档完整清单 + 源码佐证):
- docstring 三要素齐 + 首句「观察 / 操作」标注(见第 4 节);
annotations按第 1 节分类标了:观察read_only_hint=True/ 破坏destructive_hint=True,Python 字段使用 snake_case;- 读写分离:单 tool 不混观察 + 操作(通用硬要求);相似操作 tool(
click_game/key_tap/drag)描述互指何时用另一个(disambiguate)。源码可见click_gamedocstring 写「鼠标点击用本 tool;键盘按键用key_tap;鼠标拖拽用drag」,三个 tool 互相交叉引用,形成 disambiguation 闭环; titleannotation(可选):Anthropic Directory 提交时每个 tool 必须有 title;本项目不提交 Directory,按需作 UI 显示名。当前源码中每个 tool 都带了中文 title(如「检查游戏窗口」「捕获游戏截图」),作为 GUI / 调试的可读显示名;- 难懂参数加了
Field description(见第 2 节); - 返回结构化(非裸字符串,单值 ack 除外)+ 错误兜底按第 3 节;
- 同步 tool 可在 MCPServer 的工作线程中并行执行:不依赖固定线程;GPU session 继续经
gpu_executor串行。这是架构约束——MCPServer 2 会在 AnyIO 工作线程中执行同步 tool,同步 backend 方法不能依赖固定调用线程;OCR / YOLO 仍须通过项目的gpu_executor串行调用(见 mcp.md 与 architecture.md); - 同步
mcp.md工具表(签名 / 参数 / 返回 / tool 总数)——文档与实现脱节是最高频坑; - HTTP 对称能力是否也要补(两个适配器消费者都用 → 放 backend 共享,见 design P11):判断依据——一个能力若两个适配器的消费者都用,就放
ZzzBackendContext共享层,MCP 与 HTTP 各自序列化、调同一 backend 方法,别把能力写死在 MCP 适配器; - 测试(
zzz-od-test/test/zzz_od/backend/)断言对齐新返回; ruff check改动文件 + 经 daemon 重启 server 验证 tool 注册。
附:如何在本项目里跑通一套 MCP tool
理解规范后,实际落地链路如下:
- 启动服务:命令行执行
uv run python -m zzz_od.backend.entry.server --host 127.0.0.1 --port 23001(项目根目录有.env时用uv run --env-file .env ...,见 entry.md);也可用 GUI「开发工具 -> MCP 服务」页面管理本机 server 子进程(启动 / 停止 / 重启 / 日志.debug/zzz_od_mcp/main_server.log); - 接入 MCP 客户端:MCP 端点
http://127.0.0.1:23001/mcp(streamable-http),Claude Code 配置claude mcp add --transport http zzz_od http://127.0.0.1:23001/mcp;Codex GUI 填类型Streamable HTTP、URL 同上(本机接口默认无鉴权,Bearer 令牌留空); - 验证注册:改完 tool 后经 daemon 重启 server(清 Python import 缓存)+ 重连,否则跑的是旧代码——这条来自 prompts.py 的
zzz_dev_validate_op开发者指南,是 op 实操验证流程的一部分。
完整工具清单(22 个@mcp.tool的签名 / 参数 / 返回)见 mcp.md;backend 方法与运行槽设计见 architecture.md;服务入口见 entry.md。
- 桌面应用
- RPA
- 计算机视觉
【免费下载链接】ZenlessZoneZero-OneDragon
绝区零 一条龙 | 全自动 | 自动闪避 | 自动每日 | 自动空洞 | 支持手柄
相关推荐
ZenlessZoneZero-OneDragon(绝区零一条龙)AI 编码协作入口与开发规范解析
ZenlessZoneZero OneDragon(绝区零一条龙)AI 编码协作入口与开发规范解析 本文以仓库根目录的 AGENTS.md https://li
桌面应用RPA计算机视觉绝区零一条龙(ZenlessZoneZero-OneDragon)项目开发指南:从环境搭建到 Operation 操作链与 GPU 推理规范
绝区零一条龙(ZenlessZoneZero OneDragon)项目开发指南:从环境搭建到 Operation 操作链与 GPU 推理规范 导读 本文是 Ze
桌面应用RPA计算机视觉DS2API Ollama兼容接口指南:3个接口让Ollama客户端直连DeepSeek模型
DS2API Ollama兼容接口指南:3个接口让Ollama客户端直连DeepSeek模型 DS2API 是一款 DeepSeek 兼容中间件接口,通过 Ol
桌面应用RPA计算机视觉
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考