diff --git a/docs/go-csharp-helper-boundary.md b/docs/go-csharp-helper-boundary.md new file mode 100644 index 0000000..e60c70e --- /dev/null +++ b/docs/go-csharp-helper-boundary.md @@ -0,0 +1,419 @@ +# Go MCP 与 C# Windows Helper 边界设计 + +## 1. 目标 + +最终程序分成两层: + +```text +MCP Client + -> Go MCP Server + -> C# Windows Helper + -> 已登录的 iSphere / IMPlatformClient 窗口 +``` + +当前阶段只提前固定 Go 与 C# 之间的边界,不实现 Go MCP 主程序,也不实现真实搜索、发送、文件操作。 + +第一阶段的实际目标是:用 C# helper 只读探测已登录客户端窗口,并把窗口和 UI Automation 控件树以稳定 JSON 返回给未来 Go MCP 服务。 + +## 2. 不做什么 + +当前阶段不做以下内容: + +- 不写 Go MCP 实现代码。 +- 不做 C# 常驻后台进程。 +- 不做 Windows Service。 +- 不做 named pipe、gRPC、HTTP 本地服务。 +- 不做插件框架。 +- 不做 selector 自动学习系统。 +- 不执行搜索联系人、发消息、发文件、收文件。 +- 不自动登录。 +- 不读取密码、token、cookie、私钥。 +- 不注入进程、不 hook、不读目标进程内存、不提权。 +- 不加壳、不混淆、不伪装系统进程。 + +## 3. 分工原则 + +### 3.1 Go MCP Server + +Go 是对外服务层,负责: + +- MCP 工具注册。 +- 参数校验。 +- 调用 C# helper。 +- 控制超时。 +- 解析 helper JSON 输出。 +- 审批校验。 +- 审计记录。 +- 把 helper 结果整理成 MCP 返回值。 + +Go 不直接操作窗口,不直接使用 UIA,不点击按钮,不保存 iSphere 控件细节。 + +### 3.2 C# Windows Helper + +C# 是 Windows 执行层,负责: + +- 枚举桌面窗口。 +- 找疑似 iSphere / IMPlatformClient 窗口。 +- 读取指定窗口的 UI Automation 控件树。 +- 后续在 selector 稳定后执行少量受控窗口动作。 + +C# 不做 MCP,不做审批策略中心,不做业务状态中心,不联网,不常驻。 + +## 4. 进程模型 + +第一阶段采用一次性 CLI 模型: + +```text +Go 启动 C# helper +Go 通过 stdin 写入一个 JSON 请求 +C# 执行一个 op +C# 通过 stdout 返回一个 JSON 响应 +C# 退出 +``` + +原因: + +- 简单。 +- 易测试。 +- 不常驻后台,减少安防误报和运维复杂度。 +- 不把联系人、消息、文件路径暴露在命令行参数里。 +- 后续如果确实需要提速,再评估长连接,不提前设计。 + +标准约束: + +- stdout 只能输出 JSON 响应。 +- stderr 可输出诊断信息。 +- exit code 非 0 表示 helper 进程级失败。 +- 业务失败用 JSON 中的 `ok:false` 表达。 + +## 5. Helper JSON Contract v1 + +协议名固定为: + +```text +isphere.helper.v1 +``` + +### 5.1 请求格式 + +```json +{ + "protocol": "isphere.helper.v1", + "request_id": "uuid-string", + "op": "scan_windows", + "timeout_ms": 5000, + "args": {} +} +``` + +字段说明: + +| 字段 | 必填 | 说明 | +| --- | --- | --- | +| `protocol` | 是 | 固定 `isphere.helper.v1` | +| `request_id` | 是 | Go 生成,用于关联请求和响应 | +| `op` | 是 | 操作名 | +| `timeout_ms` | 否 | Go 和 C# 都应尊重的超时 | +| `args` | 是 | op 参数 | + +### 5.2 成功响应 + +```json +{ + "protocol": "isphere.helper.v1", + "request_id": "uuid-string", + "op": "scan_windows", + "ok": true, + "data": {}, + "error": null, + "warnings": [] +} +``` + +### 5.3 失败响应 + +```json +{ + "protocol": "isphere.helper.v1", + "request_id": "uuid-string", + "op": "scan_windows", + "ok": false, + "data": null, + "error": { + "code": "WINDOW_NOT_FOUND", + "message": "no matching iSphere window found" + }, + "warnings": [] +} +``` + +第一版错误码只保留: + +```text +INVALID_REQUEST +UNSUPPORTED_OP +HELPER_FAILED +TIMEOUT +WINDOW_NOT_FOUND +AMBIGUOUS_WINDOW +UIA_DUMP_FAILED +``` + +后续真实动作阶段再增加: + +```text +SELECTOR_NOT_FOUND +APP_NOT_LOGGED_IN +APP_BUSY +APPROVAL_REQUIRED +VERIFY_FAILED +``` + +## 6. 第一阶段 op + +第一阶段只支持四个 op。 + +### 6.1 `version` + +用途:确认 helper 可运行,返回协议版本、程序版本、运行时信息。 + +请求: + +```json +{ + "protocol": "isphere.helper.v1", + "request_id": "...", + "op": "version", + "args": {} +} +``` + +响应 data 示例: + +```json +{ + "helper_name": "ISphereWinHelper", + "helper_version": "0.1.0", + "protocol": "isphere.helper.v1", + "runtime": ".NET Framework" +} +``` + +### 6.2 `self_check` + +用途:检查 helper 是否能访问当前桌面、UI Automation 是否可用。 + +响应 data 示例: + +```json +{ + "desktop_access": true, + "uia_available": true +} +``` + +### 6.3 `scan_windows` + +用途:枚举当前桌面窗口,返回疑似 iSphere / IMPlatformClient 候选。 + +args 示例: + +```json +{ + "include_all_visible": false +} +``` + +响应 data 示例: + +```json +{ + "windows": [ + { + "hwnd": "0x001A0B2C", + "pid": 1234, + "process_name": "IMPlatformClient", + "title": "iSphere", + "class_name": "WindowsForms10.Window.8.app.0.xxxxx", + "visible": true, + "bounds": { + "x": 100, + "y": 80, + "width": 1200, + "height": 800 + }, + "score": 90 + } + ] +} +``` + +### 6.4 `dump_uia` + +用途:对指定窗口导出 UI Automation 控件树。 + +args 示例: + +```json +{ + "hwnd": "0x001A0B2C", + "max_depth": 8, + "include_text": true +} +``` + +响应 data 示例: + +```json +{ + "hwnd": "0x001A0B2C", + "root": { + "name": "iSphere", + "control_type": "Window", + "automation_id": "", + "class_name": "WindowsForms10.Window.8.app.0.xxxxx", + "children": [] + } +} +``` + +第一阶段 Go 可以把该响应保存到: + +```text +runs/real-loggedin-lab/uia-dumps/ +``` + +C# helper 默认不主动写文件,除非未来明确加入 `out_path` 参数。 + +## 7. 后续 op 扩展顺序 + +必须等真实登录窗口的 UIA dump 被确认后,再扩展真实动作。 + +建议顺序: + +```text +search_contacts +open_conversation +read_latest_messages +write_draft +send_after_approval +send_file_after_approval +receive_file_after_approval +``` + +其中: + +- `search_contacts`、`open_conversation`、`read_latest_messages` 可先做只读或低风险动作。 +- `write_draft` 只能写入草稿,不点击发送。 +- `send_after_approval` 必须带 `approval_id`。 +- 文件发送、文件接收也必须带 `approval_id`。 + +## 8. 审批和审计边界 + +审批主逻辑放在 Go。 + +Go 负责: + +- 生成审批记录。 +- 校验 `approval_id`。 +- 记录操作者、目标联系人、消息摘要、文件路径摘要、时间、结果。 + +C# 负责二次保护: + +- 对真实发送和文件类 op,如果没有 `approval_id`,直接返回 `APPROVAL_REQUIRED`。 +- 执行前确认当前窗口和目标会话仍然匹配。 +- 执行后返回可核验结果。 + +第一阶段没有真实发送类 op,因此不实现审批逻辑,只在协议里预留字段。 + +## 9. 安防低误报约束 + +helper 必须保持普通企业辅助工具形态: + +- 普通命令行程序。 +- 不需要管理员权限。 +- 不注入目标进程。 +- 不 hook 全局键盘鼠标。 +- 不读目标进程内存。 +- 不修改目标程序文件。 +- 不自启动。 +- 不隐藏进程。 +- 不联网。 +- 不加壳、不混淆。 +- 不伪装系统进程名。 +- 默认不写日志文件。 +- 只在 Go 指定输出路径时保存证据文件。 + +正式部署时依靠: + +- 明确程序名。 +- 固定安装路径。 +- 代码签名。 +- 企业白名单。 +- 可审计日志。 + +不依靠规避、隐藏或绕过安防。 + +## 10. 建议目录结构 + +当前只需要规划,不需要一次性全部创建。 + +Go 侧未来结构: + +```text +go/ + cmd/ + isphere-mcp/ + main.go + internal/ + mcpserver/ + server.go + tools/ + real_lab.go + helperclient/ + client.go + contract.go + audit/ + audit.go + approval/ + approval.go +``` + +C# 侧第一阶段结构: + +```text +native/ + ISphereWinHelper/ + Program.cs + HelperProtocol.cs + WindowScanner.cs + UiaDumper.cs +``` + +第一阶段不要再拆更多目录。 + +## 11. 验收标准 + +第一阶段完成后,只验收: + +1. C# helper 能编译。 +2. `version` 返回合法 JSON。 +3. `self_check` 返回 UIA 可用状态。 +4. `scan_windows` 能列出当前可见窗口。 +5. 打开记事本后,`dump_uia` 能导出记事本控件树。 +6. 用户手动登录 iSphere 后,`scan_windows` 能找到候选窗口。 +7. 对 iSphere 候选窗口执行 `dump_uia` 能返回控件树。 +8. 全流程不点击、不输入、不发送、不修改目标客户端。 + +## 12. 下一步 + +建议下一步只做 C# helper 第一阶段: + +```text +version +self_check +scan_windows +dump_uia +``` + +Go MCP 代码暂不写。等 C# helper 能稳定拿到真实 iSphere 窗口结构后,再实现 Go 的 `helperclient` 和 MCP tools。