ios-decrypt-hub 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ include docs/*.md
@@ -0,0 +1,190 @@
1
+ Metadata-Version: 2.4
2
+ Name: ios-decrypt-hub
3
+ Version: 0.2.0
4
+ Summary: Discover IOSDecryptHub instances and bridge HTTP MCP to stdio
5
+ Author: IOSDecryptHub
6
+ Keywords: ios,mcp,udp,discovery
7
+ Classifier: Development Status :: 3 - Alpha
8
+ Classifier: Environment :: Console
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3 :: Only
11
+ Classifier: Topic :: Software Development :: Debuggers
12
+ Requires-Python: >=3.10
13
+ Description-Content-Type: text/markdown
14
+ Provides-Extra: dev
15
+ Requires-Dist: build>=1.2; extra == "dev"
16
+ Requires-Dist: pytest>=8.0; extra == "dev"
17
+ Requires-Dist: ruff>=0.9; extra == "dev"
18
+
19
+ # idh
20
+
21
+ `idh` 是 IOSDecryptHub 的 PC 端发现与 MCP 网关。它监听设备每 2 秒发送一次的 UDP
22
+ 广播信标(端口 8089),并把设备上的 Streamable HTTP MCP 转换为本地 stdio MCP。
23
+
24
+ > HTTP/MCP 服务没有身份认证,只能在可信局域网中使用,不要暴露到公网。
25
+
26
+ ## 安装
27
+
28
+ 要求 Python 3.10 或更高版本,运行时只使用 Python 标准库。
29
+
30
+ 推荐使用 pipx 独立安装:
31
+
32
+ ```bash
33
+ pipx install ios-decrypt-hub
34
+ ```
35
+
36
+ 也可以直接通过 pip 安装:
37
+
38
+ ```bash
39
+ python3 -m pip install ios-decrypt-hub
40
+ ```
41
+
42
+ 升级到最新版:
43
+
44
+ ```bash
45
+ pipx upgrade ios-decrypt-hub
46
+ ```
47
+
48
+ ## 发现设备
49
+
50
+ ```bash
51
+ idh devices
52
+ idh devices --json
53
+ idh watch
54
+ idh open com.example.app
55
+ ```
56
+
57
+ `idh --devices` 是 `idh devices` 的兼容快捷写法。`devices --json` 返回的
58
+ `target_id` 是当前在线 App 进程的唯一标识,AI Agent 和自动化脚本应优先使用它;
59
+ Bundle ID、App 名称、序号和 MCP URL 仅作为便利选择器。
60
+
61
+ 无法使用 UDP 广播时,可以手动指定地址:
62
+
63
+ ```bash
64
+ idh devices --endpoint http://192.168.1.20:8088 --no-discovery
65
+ ```
66
+
67
+ ## 命令行调用 MCP
68
+
69
+ 一次性调用只读工具:
70
+
71
+ ```bash
72
+ idh call <target_id> get_stats
73
+ idh call <target_id> query_events \
74
+ --arguments '{"category":"digest","limit":3}' --json
75
+ ```
76
+
77
+ 修改远端状态的工具必须显式确认:
78
+
79
+ ```bash
80
+ idh call <target_id> set_pause \
81
+ --arguments '{"paused":true}' --allow-mutation
82
+ ```
83
+
84
+ ## MCP 聚合网关
85
+
86
+ 聚合网关适合动态发现和管理多个 App,只需在 MCP 客户端配置一次:
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "idh": {
92
+ "command": "idh",
93
+ "args": ["mcp"]
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ 网关提供固定工具集,避免设备上下线后 MCP 客户端缓存动态 `tools/list`:
100
+
101
+ - `idh_list_devices`
102
+ - `idh_list_tools`
103
+ - `idh_get_tool_schema`
104
+ - `idh_call_tool`
105
+ - `idh_get_panel_url`
106
+
107
+ ### AI Agent 调用协议
108
+
109
+ `idh` 不解析自然语言,也不替 AI 决定“应该怎样分析”。自然语言理解、目标判断和分析规划
110
+ 属于 AI Agent;`idh` 只提供在线事实、设备端真实工具描述、参数 schema 和确定性路由。
111
+
112
+ 当用户说“帮我分析 xxxx App”时,Agent 应按以下协议工作:
113
+
114
+ 1. 调用 `idh_list_devices` 获取当前在线 App,不使用历史 target 或缓存序号。
115
+ 2. 由 Agent 将用户说的 `xxxx` 与返回的 `app`、`bundle` 字段对照。
116
+ 3. 只有一个明确候选时,保存并使用该候选本轮返回的 `target_id`。
117
+ 4. 多个候选都合理时,向用户展示 App、Bundle ID 和设备并要求选择;不得自行猜测。
118
+ 5. 没有候选时,提示用户启动目标 App 并确认 IOSDecryptHub 已注入。
119
+ 6. 调用 `idh_list_tools` 阅读设备端真实工具描述,不臆造不存在的分析能力。
120
+ 7. 调用 `idh_get_tool_schema` 获取准备调用工具的完整 schema。
121
+ 8. 调用 `idh_call_tool`,传入 `target`、`tool_name` 和 `tool_arguments`。
122
+ 9. 查询、读取、反汇编等只读操作可根据用户目标自主执行;具有副作用的工具只有在用户
123
+ 明确要求后才传 `allow_mutation=true`。
124
+
125
+ 示例流程:
126
+
127
+ ```text
128
+ 用户:帮我分析 Example App 最近的加密行为
129
+ Agent → idh_list_devices({})
130
+ Agent:根据 app/bundle 字段确定唯一候选,取得 target_id
131
+ Agent → idh_list_tools({"target":"<target_id>","query":"crypto"})
132
+ Agent → idh_get_tool_schema({"target":"<target_id>","tool_name":"query_events"})
133
+ Agent → idh_call_tool({
134
+ "target":"<target_id>",
135
+ "tool_name":"query_events",
136
+ "tool_arguments":{"category":"all","limit":100}
137
+ })
138
+ ```
139
+
140
+ 上述工具链提供事实和执行能力,具体选择 `query_events` 还是其他工具应由 Agent 根据用户目标
141
+ 和设备端返回的 description/schema 判断,而不是由 `idh` 内置关键词或自然语言规则决定。
142
+
143
+ 希望 Agent 自主选择在线目标时,应配置聚合网关 `idh mcp`。透明代理的 target 在进程启动时
144
+ 已经固定,更适合用户或上层系统预先确定目标的场景。
145
+
146
+ ## 单 App 透明代理
147
+
148
+ 固定分析一个 App 时,透明代理会把远端工具及完整 schema 原样暴露给 AI Agent,调用体验最好:
149
+
150
+ ```json
151
+ {
152
+ "mcpServers": {
153
+ "idh-demo": {
154
+ "command": "idh",
155
+ "args": ["mcp", "--target", "com.example.app"]
156
+ }
157
+ }
158
+ }
159
+ ```
160
+
161
+ 多台设备运行相同 Bundle ID 时,应改用 `idh devices --json` 返回的 `target_id`,
162
+ 或者显式指定唯一 MCP URL。透明代理启动时会等待目标出现,而不是在发现任意设备后立即失败。
163
+
164
+ 本地 Simulator 联调:
165
+
166
+ ```bash
167
+ idh mcp --target 1 --endpoint http://127.0.0.1:8088 --no-discovery
168
+ ```
169
+
170
+ 所有日志写入 stderr,stdout 严格保留给逐行 JSON-RPC stdio 消息。
171
+
172
+ ## 发现生命周期
173
+
174
+ - 信标每 2 秒发送一次。
175
+ - 6 秒未收到信标时,实例标记为 `stale`,不再参与 target 解析。
176
+ - 10 秒未收到信标时,实例从注册表移除。
177
+ - 同一设备上的同一 Bundle ID 启动新进程时,新实例会立即替换旧实例。
178
+ - UDP 广播仅适用于同一二层局域网;跨 VLAN 时使用 `--endpoint` 或配置 UDP 转发。
179
+
180
+ ## 开发
181
+
182
+ ```bash
183
+ uv sync --extra dev
184
+ uv run python -m pytest tests/ -q
185
+ uv run ruff check src/ tests/
186
+ uv run python -m build
187
+ ```
188
+
189
+ 详细实施和验收步骤见
190
+ [MCP_GATEWAY_AGENT_OPTIMIZATION_PLAN.md](docs/MCP_GATEWAY_AGENT_OPTIMIZATION_PLAN.md)。
@@ -0,0 +1,172 @@
1
+ # idh
2
+
3
+ `idh` 是 IOSDecryptHub 的 PC 端发现与 MCP 网关。它监听设备每 2 秒发送一次的 UDP
4
+ 广播信标(端口 8089),并把设备上的 Streamable HTTP MCP 转换为本地 stdio MCP。
5
+
6
+ > HTTP/MCP 服务没有身份认证,只能在可信局域网中使用,不要暴露到公网。
7
+
8
+ ## 安装
9
+
10
+ 要求 Python 3.10 或更高版本,运行时只使用 Python 标准库。
11
+
12
+ 推荐使用 pipx 独立安装:
13
+
14
+ ```bash
15
+ pipx install ios-decrypt-hub
16
+ ```
17
+
18
+ 也可以直接通过 pip 安装:
19
+
20
+ ```bash
21
+ python3 -m pip install ios-decrypt-hub
22
+ ```
23
+
24
+ 升级到最新版:
25
+
26
+ ```bash
27
+ pipx upgrade ios-decrypt-hub
28
+ ```
29
+
30
+ ## 发现设备
31
+
32
+ ```bash
33
+ idh devices
34
+ idh devices --json
35
+ idh watch
36
+ idh open com.example.app
37
+ ```
38
+
39
+ `idh --devices` 是 `idh devices` 的兼容快捷写法。`devices --json` 返回的
40
+ `target_id` 是当前在线 App 进程的唯一标识,AI Agent 和自动化脚本应优先使用它;
41
+ Bundle ID、App 名称、序号和 MCP URL 仅作为便利选择器。
42
+
43
+ 无法使用 UDP 广播时,可以手动指定地址:
44
+
45
+ ```bash
46
+ idh devices --endpoint http://192.168.1.20:8088 --no-discovery
47
+ ```
48
+
49
+ ## 命令行调用 MCP
50
+
51
+ 一次性调用只读工具:
52
+
53
+ ```bash
54
+ idh call <target_id> get_stats
55
+ idh call <target_id> query_events \
56
+ --arguments '{"category":"digest","limit":3}' --json
57
+ ```
58
+
59
+ 修改远端状态的工具必须显式确认:
60
+
61
+ ```bash
62
+ idh call <target_id> set_pause \
63
+ --arguments '{"paused":true}' --allow-mutation
64
+ ```
65
+
66
+ ## MCP 聚合网关
67
+
68
+ 聚合网关适合动态发现和管理多个 App,只需在 MCP 客户端配置一次:
69
+
70
+ ```json
71
+ {
72
+ "mcpServers": {
73
+ "idh": {
74
+ "command": "idh",
75
+ "args": ["mcp"]
76
+ }
77
+ }
78
+ }
79
+ ```
80
+
81
+ 网关提供固定工具集,避免设备上下线后 MCP 客户端缓存动态 `tools/list`:
82
+
83
+ - `idh_list_devices`
84
+ - `idh_list_tools`
85
+ - `idh_get_tool_schema`
86
+ - `idh_call_tool`
87
+ - `idh_get_panel_url`
88
+
89
+ ### AI Agent 调用协议
90
+
91
+ `idh` 不解析自然语言,也不替 AI 决定“应该怎样分析”。自然语言理解、目标判断和分析规划
92
+ 属于 AI Agent;`idh` 只提供在线事实、设备端真实工具描述、参数 schema 和确定性路由。
93
+
94
+ 当用户说“帮我分析 xxxx App”时,Agent 应按以下协议工作:
95
+
96
+ 1. 调用 `idh_list_devices` 获取当前在线 App,不使用历史 target 或缓存序号。
97
+ 2. 由 Agent 将用户说的 `xxxx` 与返回的 `app`、`bundle` 字段对照。
98
+ 3. 只有一个明确候选时,保存并使用该候选本轮返回的 `target_id`。
99
+ 4. 多个候选都合理时,向用户展示 App、Bundle ID 和设备并要求选择;不得自行猜测。
100
+ 5. 没有候选时,提示用户启动目标 App 并确认 IOSDecryptHub 已注入。
101
+ 6. 调用 `idh_list_tools` 阅读设备端真实工具描述,不臆造不存在的分析能力。
102
+ 7. 调用 `idh_get_tool_schema` 获取准备调用工具的完整 schema。
103
+ 8. 调用 `idh_call_tool`,传入 `target`、`tool_name` 和 `tool_arguments`。
104
+ 9. 查询、读取、反汇编等只读操作可根据用户目标自主执行;具有副作用的工具只有在用户
105
+ 明确要求后才传 `allow_mutation=true`。
106
+
107
+ 示例流程:
108
+
109
+ ```text
110
+ 用户:帮我分析 Example App 最近的加密行为
111
+ Agent → idh_list_devices({})
112
+ Agent:根据 app/bundle 字段确定唯一候选,取得 target_id
113
+ Agent → idh_list_tools({"target":"<target_id>","query":"crypto"})
114
+ Agent → idh_get_tool_schema({"target":"<target_id>","tool_name":"query_events"})
115
+ Agent → idh_call_tool({
116
+ "target":"<target_id>",
117
+ "tool_name":"query_events",
118
+ "tool_arguments":{"category":"all","limit":100}
119
+ })
120
+ ```
121
+
122
+ 上述工具链提供事实和执行能力,具体选择 `query_events` 还是其他工具应由 Agent 根据用户目标
123
+ 和设备端返回的 description/schema 判断,而不是由 `idh` 内置关键词或自然语言规则决定。
124
+
125
+ 希望 Agent 自主选择在线目标时,应配置聚合网关 `idh mcp`。透明代理的 target 在进程启动时
126
+ 已经固定,更适合用户或上层系统预先确定目标的场景。
127
+
128
+ ## 单 App 透明代理
129
+
130
+ 固定分析一个 App 时,透明代理会把远端工具及完整 schema 原样暴露给 AI Agent,调用体验最好:
131
+
132
+ ```json
133
+ {
134
+ "mcpServers": {
135
+ "idh-demo": {
136
+ "command": "idh",
137
+ "args": ["mcp", "--target", "com.example.app"]
138
+ }
139
+ }
140
+ }
141
+ ```
142
+
143
+ 多台设备运行相同 Bundle ID 时,应改用 `idh devices --json` 返回的 `target_id`,
144
+ 或者显式指定唯一 MCP URL。透明代理启动时会等待目标出现,而不是在发现任意设备后立即失败。
145
+
146
+ 本地 Simulator 联调:
147
+
148
+ ```bash
149
+ idh mcp --target 1 --endpoint http://127.0.0.1:8088 --no-discovery
150
+ ```
151
+
152
+ 所有日志写入 stderr,stdout 严格保留给逐行 JSON-RPC stdio 消息。
153
+
154
+ ## 发现生命周期
155
+
156
+ - 信标每 2 秒发送一次。
157
+ - 6 秒未收到信标时,实例标记为 `stale`,不再参与 target 解析。
158
+ - 10 秒未收到信标时,实例从注册表移除。
159
+ - 同一设备上的同一 Bundle ID 启动新进程时,新实例会立即替换旧实例。
160
+ - UDP 广播仅适用于同一二层局域网;跨 VLAN 时使用 `--endpoint` 或配置 UDP 转发。
161
+
162
+ ## 开发
163
+
164
+ ```bash
165
+ uv sync --extra dev
166
+ uv run python -m pytest tests/ -q
167
+ uv run ruff check src/ tests/
168
+ uv run python -m build
169
+ ```
170
+
171
+ 详细实施和验收步骤见
172
+ [MCP_GATEWAY_AGENT_OPTIMIZATION_PLAN.md](docs/MCP_GATEWAY_AGENT_OPTIMIZATION_PLAN.md)。
@@ -0,0 +1,308 @@
1
+ # idh MCP 网关 Agent 适配优化与验证计划
2
+
3
+ ## 1. 目标
4
+
5
+ 让 AI Agent 在单设备和多设备环境中都能可靠完成以下流程:
6
+
7
+ 1. 发现当前在线的 IOSDecryptHub App。
8
+ 2. 无歧义地选择目标进程。
9
+ 3. 以较低 token 成本了解远端工具。
10
+ 4. 按完整 JSON Schema 组装参数并调用工具。
11
+ 5. 对修改状态的调用进行显式确认。
12
+ 6. 在 App 重启、设备下线和 IP 更新后恢复工作。
13
+
14
+ 本计划不改变设备端 HTTP/MCP 端口和路径:HTTP/MCP 继续使用 8088,MCP 继续使用
15
+ `POST /api/mcp`,发现继续使用 UDP 8089。服务没有认证,只能在可信局域网中使用。
16
+
17
+ ### 1.1 Agent 与网关的职责边界
18
+
19
+ AI Agent 负责:
20
+
21
+ - 理解用户自然语言中的 App 名称和分析目标。
22
+ - 根据 `idh_list_devices` 返回的事实选择唯一候选,或在歧义时向用户澄清。
23
+ - 根据设备端工具 description 和 inputSchema 制定分析步骤。
24
+ - 在用户授权范围内决定是否执行具有副作用的操作。
25
+
26
+ `idh` 负责:
27
+
28
+ - 返回当前在线 App、稳定的本轮 `target_id` 和连接状态。
29
+ - 转发设备端真实工具描述和 schema。
30
+ - 按明确的 `target_id` 和工具参数做确定性路由。
31
+ - 对歧义 target、离线设备、无效 schema 和副作用调用返回结构化错误。
32
+
33
+ 明确不做:
34
+
35
+ - 不解析“帮我分析 xxxx App”等自然语言。
36
+ - 不内置 App 名称评分、关键词匹配或所谓置信度算法。
37
+ - 不根据用户目标自动编排反汇编、事件查询或动态 hook。
38
+ - 不伪造设备端不存在的分析能力。
39
+
40
+ 这些非目标用于避免把不可靠的语义判断放入基础设施层。Agent 的可用性应通过 MCP
41
+ `instructions`、工具 description、严格 schema 和结构化结果提升,而不是新增一个看似智能、
42
+ 实际不可验证的 `analyze_app` 类函数。
43
+
44
+ ## 2. 基线问题与设计决定
45
+
46
+ | 问题 | 风险 | 设计决定 |
47
+ |---|---|---|
48
+ | `target` 同时接受序号、名称、Bundle ID、URL 和部分匹配 | 多设备时容易匹配失败 | `target_id` 作为 Agent 的唯一规范标识,其他选择器只保留兼容 |
49
+ | App 重启后生成新实例 UUID,旧实例不删除 | 同一 Bundle ID 出现假歧义 | 新进程立即替换同 IP、同 Bundle ID 的旧进程,并增加 TTL |
50
+ | 网关发现任意设备后立即结束启动等待 | 指定的设备稍晚发信标时初始化失败 | 透明代理等待指定 target 出现 |
51
+ | 聚合网关直接发送 `tools/list`/`tools/call` | 不符合严格 MCP 初始化顺序 | 每个远端会话先执行 initialize 和 initialized 通知 |
52
+ | `idh_call_tool.arguments` 没有具体远端 schema | Agent 容易猜错参数且工具列表消耗较多 token | 工具摘要与单工具 schema 分离 |
53
+ | 读写工具统一隐藏在一个网关工具后 | MCP 客户端无法判断副作用 | 已知修改型工具要求 `allow_mutation=true` |
54
+ | 人类命令行只能手工构造 JSON-RPC | 调试成本高 | 增加 `idh call` 一次性调用命令 |
55
+
56
+ ## 3. 分阶段实施步骤
57
+
58
+ ### 阶段 A:建立规范 target 契约
59
+
60
+ 实施:
61
+
62
+ - `AppEndpoint.as_dict()` 同时返回兼容字段 `id` 和规范字段 `target_id`。
63
+ - 网关工具 schema 明确要求优先使用 `idh_list_devices` 返回的 `target_id`。
64
+ - Bundle ID、App 名称、序号、服务名和 URL 继续兼容。
65
+ - 匹配失败返回结构化错误码和候选列表,不静默选择。
66
+
67
+ 验证:
68
+
69
+ ```bash
70
+ idh devices --json
71
+ uv run python -m pytest tests/test_models.py -q
72
+ ```
73
+
74
+ 验收标准:
75
+
76
+ - 每个 App 都包含非空 `target_id`。
77
+ - 两台设备运行相同 Bundle ID 时返回 `ambiguous_target` 和两个候选项。
78
+ - 使用候选项中的 `target_id` 可以准确解析到一个 App。
79
+
80
+ ### 阶段 B:修复发现生命周期
81
+
82
+ 实施:
83
+
84
+ - 保存每个 UDP 实例的最后信标时间。
85
+ - 6 秒未收到信标时标记 `beacon_status=stale`,并停止参与 target 解析。
86
+ - 10 秒未收到信标时从注册表删除。
87
+ - 同一发送 IP、同一 Bundle ID 的新 UUID 立即替换旧 UUID。
88
+ - 手动 `--endpoint` 不受 UDP TTL 影响。
89
+ - 对无效端口、无效实例 ID 和非信标 UDP 数据静默忽略。
90
+
91
+ 验证:
92
+
93
+ ```bash
94
+ uv run python -m pytest tests/test_discovery.py -q
95
+ idh watch --json
96
+ ```
97
+
98
+ 手工验证时启动目标 App,确认出现 `add`;终止 App 后等待 10 秒,确认出现 `remove`。
99
+
100
+ 验收标准:
101
+
102
+ - App 重启后同一设备和 Bundle ID 只保留新 `target_id`。
103
+ - stale 实例不会造成 Bundle ID 匹配歧义。
104
+ - 下线实例最迟 10 秒从 `watch` 和 `devices` 消失。
105
+
106
+ ### 阶段 C:按 target 等待透明代理启动
107
+
108
+ 实施:
109
+
110
+ - `DiscoveryRegistry.wait()` 支持 predicate。
111
+ - `idh mcp --target X` 等待 X 可解析,而不是发现任意 App 后立即继续。
112
+ - 超时后仍返回结构化 target 错误,便于 MCP 客户端显示原因。
113
+
114
+ 验证:
115
+
116
+ ```bash
117
+ uv run python -m pytest \
118
+ tests/test_discovery.py::test_registry_waits_for_requested_target_not_first_device -q
119
+ idh mcp --target com.example.app --startup-timeout 6
120
+ ```
121
+
122
+ 验收标准:先启动一个不匹配 App,再在 6 秒内启动目标 App,透明代理初始化成功。
123
+
124
+ ### 阶段 D:补齐远端 MCP 握手
125
+
126
+ 实施:
127
+
128
+ - 聚合网关首次访问每个远端实例时依次发送:
129
+ `initialize`、`notifications/initialized`、实际请求。
130
+ - 保存设备返回的 `Mcp-Session-Id`。
131
+ - MCP URL 改变时清除旧 session 和初始化状态。
132
+ - 不自动重放 `tools/call`。
133
+
134
+ 验证:
135
+
136
+ ```bash
137
+ uv run python -m pytest tests/test_gateway.py::test_gateway_lists_and_calls_remote_tools -q
138
+ ```
139
+
140
+ 验收标准:测试服务收到的方法顺序必须是
141
+ `initialize -> notifications/initialized -> tools/list/tools/call`,同一会话只初始化一次。
142
+
143
+ ### 阶段 E:降低 Agent schema 歧义
144
+
145
+ 实施:
146
+
147
+ - 固定网关工具集增加 `idh_get_tool_schema`。
148
+ - `idh_list_tools` 默认返回名称、描述和 annotations 摘要。
149
+ - `detail=full` 保留一次返回全部 schema 的能力。
150
+ - `query` 支持按名称或描述过滤。
151
+ - `idh_call_tool` 规范参数改为 `tool_name` 和 `tool_arguments`。
152
+ - 旧参数 `name` 和 `arguments` 保留兼容并标记 deprecated。
153
+ - 所有网关输入 schema 增加 `additionalProperties=false`。
154
+
155
+ Agent 验证流程:
156
+
157
+ ```text
158
+ idh_list_devices({})
159
+ idh_list_tools({"target":"<target_id>","query":"event"})
160
+ idh_get_tool_schema({"target":"<target_id>","tool_name":"query_events"})
161
+ idh_call_tool({
162
+ "target":"<target_id>",
163
+ "tool_name":"query_events",
164
+ "tool_arguments":{"category":"digest","limit":3}
165
+ })
166
+ ```
167
+
168
+ 验收标准:Agent 不需要读取全部工具 schema,即可准确调用一个复杂工具。
169
+
170
+ ### 阶段 E.1:验证 Agent 使用说明
171
+
172
+ 实施:
173
+
174
+ - MCP initialize 的 `instructions` 明确目标发现、候选澄清、schema 获取和权限边界。
175
+ - 每个固定网关工具的 description 说明输入来源、事实边界和下一步。
176
+ - `idh_list_devices` 不替 Agent 选择 App;`idh_call_tool` 不理解自然语言。
177
+
178
+ 验证:
179
+
180
+ ```bash
181
+ uv run python -m pytest tests/test_gateway.py -q
182
+ ```
183
+
184
+ 验收标准:
185
+
186
+ - instructions 明确要求从 `idh_list_devices` 开始。
187
+ - instructions 明确规定多个候选时向用户澄清。
188
+ - tools/list 中不存在 `analyze_app`、`prepare_analysis` 等语义编排工具。
189
+ - 工具 description 明确以设备端返回的 description/schema 为事实来源。
190
+
191
+ ### 阶段 F:保护修改型调用
192
+
193
+ 实施:
194
+
195
+ - 网关维护明确的修改型工具集合。
196
+ - 未传 `allow_mutation=true` 时返回 `mutation_confirmation_required`。
197
+ - 只读工具不需要确认。
198
+ - 透明代理保持原样透传;其工具 schema 和 annotations 由设备端负责。
199
+
200
+ 验证:
201
+
202
+ ```bash
203
+ uv run python -m pytest \
204
+ tests/test_gateway.py::test_gateway_requires_confirmation_for_mutating_tool -q
205
+ ```
206
+
207
+ 验收标准:`clear_events` 在未确认时不产生任何远端 HTTP 请求,确认后只执行一次。
208
+
209
+ ### 阶段 G:增加一次性 CLI 调用
210
+
211
+ 实施:
212
+
213
+ ```bash
214
+ idh call <target_id> get_stats
215
+ idh call <target_id> query_events \
216
+ --arguments '{"category":"digest","limit":3}' --json
217
+ idh call <target_id> set_pause \
218
+ --arguments '{"paused":true}' --allow-mutation
219
+ ```
220
+
221
+ 验证:
222
+
223
+ ```bash
224
+ uv run python -m pytest tests/test_gateway.py::test_cli_call_invokes_remote_tool -q
225
+ ```
226
+
227
+ 验收标准:成功调用退出码为 0,远端错误或确认缺失退出码为 1,无效 JSON 退出码为 2。
228
+
229
+ ## 4. 完整自动化验证
230
+
231
+ 在 `idh/` 目录执行:
232
+
233
+ ```bash
234
+ uv run python -m pytest tests/ -q
235
+ uv run ruff check src/ tests/
236
+ uv run python -m build
237
+ ```
238
+
239
+ 验收标准:
240
+
241
+ - 所有测试通过。
242
+ - Ruff 无错误。
243
+ - sdist 和 wheel 构建成功。
244
+ - 运行时依赖仍为空。
245
+
246
+ ## 5. Simulator 端到端验证
247
+
248
+ 在 `IOSDecryptHub/` 目录执行:
249
+
250
+ ```bash
251
+ make sim
252
+ scripts/sim_install.sh
253
+ ```
254
+
255
+ 在 `idh/` 目录执行:
256
+
257
+ ```bash
258
+ idh devices --timeout 4 --json
259
+ idh call com.taisuii.cryptotesthost get_capabilities --timeout 4 --json
260
+ idh call com.taisuii.cryptotesthost get_stats --timeout 4 --json
261
+ idh call com.taisuii.cryptotesthost query_events \
262
+ --arguments '{"category":"digest","limit":3}' --timeout 4 --json
263
+ ```
264
+
265
+ 然后验证聚合 stdio 网关和透明代理:
266
+
267
+ ```bash
268
+ idh mcp --startup-timeout 4
269
+ idh mcp --target com.taisuii.cryptotesthost --startup-timeout 4
270
+ ```
271
+
272
+ 验收标准:
273
+
274
+ - UDP 自动发现成功,状态为 online。
275
+ - `target_id` 非空且同一进程内稳定。
276
+ - 三个一次性调用均返回 `isError=false`。
277
+ - 聚合网关按 `target_id` 调用成功。
278
+ - 透明代理直接暴露设备端工具。
279
+ - `/api/stats` 中 `hookFails=0`、`httpFailed=false`。
280
+
281
+ ## 6. 兼容性与发布检查
282
+
283
+ - 保留 `id`、`name`、`arguments` 旧字段,旧客户端可继续工作。
284
+ - `target_id` 是进程实例 ID,App 重启后会变化;Agent 每个新任务都应重新调用
285
+ `idh_list_devices`,不能跨重启缓存。
286
+ - Bundle ID 只有在唯一匹配时才能作为 target。
287
+ - `idh mcp --target` 透明代理行为保持不变。
288
+ - 不新增运行时依赖,不改 8088、8089 和 `/api/mcp`。
289
+ - README 必须保留“无认证,仅限可信网络”的警告。
290
+
291
+ ## 7. 完成定义
292
+
293
+ - [x] 阶段 A-G 的单元测试全部通过。
294
+ - [x] 完整 pytest、Ruff 和构建通过。
295
+ - [x] Simulator 自动发现、聚合调用和透明代理调用通过。
296
+ - [x] App 重启和下线 TTL 手工验证通过。
297
+ - [x] README 与实际 UDP 协议一致。
298
+ - [x] `git diff` 中没有捕获日志、设备数据、密钥或构建产物。
299
+
300
+ ## 8. 本次执行记录(2026-07-28)
301
+
302
+ - 自动化:26 个 pytest 测试通过,Ruff 通过。
303
+ - 构建:`ios_decrypt_hub-0.2.0.tar.gz` 和 wheel 构建成功。
304
+ - Simulator:自动发现 `Crypto Test`,`get_stats`、`query_events`、透明代理调用成功。
305
+ - Agent schema:固定 5 个网关工具,摘要查询和单工具 schema 查询成功。
306
+ - 安全检查:未确认的 `clear_events` 返回 `mutation_confirmation_required`,没有发往设备。
307
+ - 生命周期:终止 App 后收到 remove;重新启动后收到新 target_id 的 add。
308
+ - 本机命令:pipx 可执行文件已更新为 `idh 0.2.0`。