把
ZzzBackendContext(见 architecture.md)以 MCP 暴露给 MCP 客户端(AI 编码工具等)。MCP 是两个并行适配器之一,另一个是 HTTP(见 http.md);两者共享同一 backend。
22 个 @mcp.tool,多数委托一个 backend 方法;自定义 op 工具另走 operation_registry + run_slot._start:
| MCP tool | 委托 | 返回 |
|---|---|---|
check_game_window |
backend.check_window() |
WindowStatus(结构化 JSON;backend 抛错时返 {'error': ...}) |
capture_game_screen |
backend.capture() |
截图绝对路径(落盘 .debug/zzz_od_mcp/screenshot/) |
analyze_screen(screenshot=None, save_image=False) |
backend.analyze() |
AnalyzeScreenResult(结构化 JSON;实时 + save_image=True 多回传 screenshot_path;success 时带 vision_hint 能力边界提示) |
upsert_screen_area(screen_name, area_name, pc_rect, ...) |
backend.upsert_screen_area() |
{success, action(inserted/updated), area_count, error}(写 yml + reload) |
delete_screen_area(screen_name, area_name) |
backend.delete_screen_area() |
{success, action(deleted), area_count, error}(写 yml + reload) |
open_game(enter=True, block=True) |
backend.start_run('mcp', op_factory)(enter=False→OpenGame,enter=True→OpenAndEnterGame) |
block=True:结果文本;block=False:已启动 JSON;并发拒绝时返错误 JSON |
click_game(x, y, press_time=0.1, pc_alt=False) |
backend.click_game() |
{success, x, y, in_window, pc_alt}(坐标不在窗口内 → in_window=False;pc_alt=True 大世界等锁光标画面点击前需按 Alt 解锁) |
input_text(text, use_clipboard=None) |
backend.input_text() |
{success, method, masked_text}(use_clipboard=None 跟 game_config.type_input_way) |
key_tap(key, press_time=0) |
backend.key_tap() |
{success, key, press_time}(框架键名 w/a/s/d/f/esc/space;press_time>0 长按) |
drag(x1, y1, x2, y2, duration=1) |
backend.drag() |
{success, x1, y1, x2, y2, duration}((x1,y1)→(x2,y2) 1080p 游戏坐标拖拽,覆盖刮刮卡 / 收集来回拖等) |
list_applications |
backend.list_applications() |
当前实例可运行应用(每个 app 含 app_id/app_name/description[app 类 class docstring])、独立应用列表和当前选中项(只读,不刷新配置) |
get_predefined_teams |
backend.list_predefined_teams() |
当前实例预备编队(idx/name/auto_battle/agent_id_list/agent_name_list/weakness_list,过滤占位;agent_name_list 角色中文名;weakness_list 中文=防卫战配置优先,没配取角色伤害属性;idx 喂给 run_operation(op_id='zzz_od.operation.choose_predefined_team.ChoosePredefinedTeam', args={'target_team_idx_list': [idx]}) 选配队) |
run_one_dragon(block=False) |
backend.run_one_dragon('mcp') |
默认立刻返回启动状态;block=True 等待一条龙结束 |
run_standalone_app(app_id=None, block=False) |
backend.run_standalone_app('mcp', app_id) |
app_id=None 时使用 GUI「应用运行」当前选中项 |
list_operations |
operation_registry.scan_operations(ctx) |
可运行自定义 op 列表(op_id + 参数 schema,纯反射不实例化) |
describe_operation(op_id) |
operation_registry.describe_operation(ctx, op_id) |
单个 op 参数 schema + description(class/__init__ docstring 摘要,去 :param 噪声);每个参数标 json_serializable + 整体 debuggable |
run_operation(op_id, args=None, block=False) |
operation_registry 校验 + 反序列化 + run_slot._start(op 路径) |
默认立刻返回;block=True 等结束;非 Operation / 缺参 / 不支持的数据类 / 并发拒绝返错误 JSON。@dataclass+from_dict 参数(如 ChargePlanItem)可从 dict 传入 |
get_run_status |
backend.query_status() |
RunStatusResult(运行中返当前节点/重试;终态返结果/失败定位) |
stop_run |
backend.stop() |
{"stopped": bool, ...}(仅表信号已发出,过渡期 get_run_status 仍显示 running) |
close_game |
backend.close_game() |
文本(str,已发送关闭信号;controller 吞异常,用 check_game_window 验证) |
list_mcp_usage_guides |
mcp/prompts.py |
可用操作指南目录,相当于帮助索引 |
get_mcp_usage_guide(name, app_id=None) |
mcp/prompts.py |
指定操作指南正文,相当于任务级 --help |
要点:
app.py放 MCP server 创建、基础 game tool 和总注册入口;service_app.py放应用运行 tool 与自定义 op tool 工厂。- backend 实例通过闭包注入 tool,不使用全局单例,也不让 MCPServer lifespan 管 backend 生命周期。
capture_game_screen落盘返回路径;analyze_screen返回结构化 dataclass,由 MCPServer 序列化。- MCPServer 2 会在 AnyIO 工作线程中执行同步 tool;同步 backend 方法不能依赖固定调用线程,OCR / YOLO 仍须通过项目的
gpu_executor串行调用。异步 tool 继续在事件循环中执行。 analyze_screen(save_image=True)(实时模式)把已截的内存图顺手存盘 + 回传screenshot_path,供调用方喂 vision double-check;默认false不落盘,离线模式忽略。analyze_screen成功时返回vision_hint:提醒本结果仅含 OCR + 模板匹配的部分识别,不等同完整视觉理解,需要全面判断画面时配合视觉工具 / 多模态再看(能力边界提示,design-principles.md P14;防智能体把部分识别当画面全貌)。失败时为null。- 所有运行(
open_game/ 一条龙 / 独立应用 / 自定义 op)经同一个RunSlot派发:op 路径(open_game/run_operation)槽自管start_running/execute/stop_running,app 路径(run_one_dragon/run_standalone_app)委托run_application(复用 GUI/CLI 共享入口)。block=True用asyncio.wrap_future(future)阻塞 await 取结果,block=False立刻返回已启动状态,后续用get_run_status查进度。 run_operation是通用 operation 运行入口(不框死为调试):op_id格式<dotted module path>.<ClassName>(可从list_operations获取);args传构造参数,以cls(ctx, **args)烤进闭包——JSON 标量/列表/字典直接传;@dataclass+from_dict参数(如ChargePlanItem)传 dict,实例化前用coerce_dataclass_params自动反序列化;其余复杂数据类拒绝(提示走 application);先用describe_operation看参数 schema(coercible=True的可传 dict)。- 配置刷新:app 路径在
run_application前(槽线程内、_start已赢锁后)刷新当前进程的 YAML 配置缓存,对齐 GUI 已保存设置;list_applications与list_operations是只读路径,不刷新。 list_applications的ApplicationInfo.description与describe_operation的description取自 app/op 类 docstring,服务看不到源码的远程 MCP 受众(源码可访问受众读源码即可)—— 见 design-principles.md「两种受众」+ P1 源码盲受众例外。app description = class docstring 整段(D4:做什么 + 有消耗必标);op description =_doc_summary(去:param噪声)。get_run_status/stop_run是统一入口:无论最近一次运行来自 op 路径还是 app 路径,都通过同一组工具查询和停止。- 单进程内已有运行时会返回并发拒绝,避免同一个 backend 内重复操作游戏资源。
- MCP tool 不返回运行日志正文;客户端需要用
get_run_status轮询是否完成,GUI 服务页负责展示日志。 close_game/click_game/key_tap/drag/input_text是独立同步操作,不走运行槽;click_game/drag使用 1080p 游戏空间坐标。底层 click / key_tap / drag 无内置等待,连续操作或capture前建议 sleep 等动画(见各 tool 描述的⚠️ 提醒)。list_mcp_usage_guides/get_mcp_usage_guide把 prompt 模板以普通 tool 暴露,方便不会主动消费 MCP prompts 的客户端发现。- 理念:MCP 只做感知 / 操作,编码 / 调试交给 AI(design-principles.md)。
MCPServer(name, instructions=...) 传 server 级 instructions,握手时返回;客户端通常注入 system prompt(协议 Optional/MAY,Claude Code 会注入;非协议强制)。放两边共通的操作哲学(保持精炼):工具分类(观察/操作)、操作三件套(analyze_screen → 操作 → 等 ~1s 后验)、实机约束(pc_alt)、出错查 log、安全边界。
引导内容分三条通道,分工互补(可见性均为客户端行为,非协议强制——spec 用 Optional/MAY):
| 通道 | 智能体可见性 | 内容 |
|---|---|---|
instructions |
客户端通常注入 system prompt(协议 Optional/MAY;Claude Code 会) | 共通操作哲学(上节) |
prompts(@mcp.prompt()) |
由客户端决定;Claude Code 是 slash 命令,智能体平时不自动看到 | 按场景剧本(见下) |
help tool(list_mcp_usage_guides / get_mcp_usage_guide) |
通常可见(客户端一般暴露 tools) | 同 prompts 模板,给智能体 --help 入口 |
prompts 协议设计给人手动选,智能体平时不自动看到 → 同份模板再做成 tool 镜像补;但 tool 要智能体「想到去调」,故核心操作哲学放 instructions(通常注入,最贴近常驻)。guide item 带 mode(user/dev):user 项(跑龙/独立应用)也有对应 prompt,dev 项(zzz_dev_validate_op:op 实操验证 / 战斗 op 边界)只走 tool。模式差异不进 instructions(server 级全局、不支持运行时切;且两套会膨胀违背精炼)。
| MCP prompt | 用途 |
|---|---|
zzz_check_status |
引导 AI 查询运行状态、窗口状态与当前画面分析结果。 |
zzz_run_one_dragon |
引导 AI 按当前配置启动一条龙,并轮询 get_run_status。 |
zzz_run_standalone_app(app_id=None) |
引导 AI 列出应用、选择独立应用并启动运行。 |
要点:
- prompt 只描述调用顺序,不直接执行工具;实际执行仍由 MCP 客户端选择 tool。
zzz_run_standalone_app支持传入app_id,为空时提示使用 GUI「应用运行」当前选中项。- 运行类 prompt 默认使用
block=False启动,再轮询get_run_status,便于客户端在长耗时任务中持续反馈状态。 - 部分 MCP 客户端不会主动展示 prompts;这时可让 agent 先调用
list_mcp_usage_guides,再调用get_mcp_usage_guide读取同一份模板。
- 传输:streamable-http。
- MCP 端点:
/mcp。 - 默认本机端口:
23001。 - MCP URL:
http://127.0.0.1:23001/mcp。 - 健康检查:
http://127.0.0.1:23001/health。
主 server 是标准 streamable-http,任何 MCP 客户端都可挂载。 先通过 GUI「开发工具 -> MCP 服务」或命令行启动本机 server,再在 Codex/Claude 里新增 MCP 服务器。
claude mcp add --transport http zzz_od http://127.0.0.1:23001/mcp| 字段 | 填写 |
|---|---|
| 名称 | zzz_od |
| 类型 | Streamable HTTP |
| Bearer 令牌环境变量 | 留空 |
| URL | http://127.0.0.1:23001/mcp |
| 标头 | 留空;如果界面要求 JSON,填 {} |
| 启动命令 | 留空 |
| 参数 | 留空 |
要点:
- 当前服务只实现 streamable HTTP,不是 STDIO server;Codex 中不要选 STDIO。
- 本机接口默认无鉴权,因此不需要 Bearer token 或额外 headers。
- Codex/Claude 只负责连接已启动的 HTTP MCP server;启动 / 停止 / 重启由 GUI「MCP 服务」页或命令行负责。
- 命令行启动可用
uv run python -m zzz_od.backend.entry.server --host 127.0.0.1 --port 23001;如果项目根目录存在.env,也可使用uv run --env-file .env python -m zzz_od.backend.entry.server --host 127.0.0.1 --port 23001。
- 更多 game 感知 / 交互 tool:原
identify_current_screen→analyze_screen、click_at_position→click_game、press_key→key_tap、drag_to→drag均已实现;后续按需补scroll等。 - 更完整的 AI 操作范式,例如失败恢复、实例切换与多步巡检。
- architecture.md - backend 方法定义
- http.md - 并行的 HTTP 适配器
- design-principles.md - MCP tool 设计规范
- entry.md - 服务入口