docs: verify five-tool mcp surface

This commit is contained in:
zhaoyilun
2026-07-09 23:16:02 +08:00
parent 57eb7a5fc7
commit 220f3f68c1
4 changed files with 147 additions and 40 deletions

View File

@@ -14,21 +14,22 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
## Current completed state
- Go MCP foundation exists: `cmd/isphere-mcp`, `internal/mcpserver`, `internal/helperclient`, and `internal/tools` build a stdio MCP server.
- The current MCP surface exposes only four read-only helper tools:
- The current MCP surface exposes five read-oriented tools:
- `win_helper_version`
- `win_helper_self_check`
- `win_helper_scan_windows`
- `win_helper_dump_uia`
- `isphere_receive_messages`
- C# `ISphereWinHelper` exists under `native/ISphereWinHelper` and uses the `isphere.helper.v1` stdin/stdout JSON contract.
- `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper and first-phase Go MCP server.
- `scripts/verify-win-helper.ps1` and `scripts/verify-go-mcp.ps1` provide repeatable local checks for the helper, five-tool MCP surface, and empty-source `isphere_receive_messages` smoke call.
- N12-pre and N12R documents define safe offline evidence intake and internal-sandbox live UIA capture procedures.
- N13/N14/N15 produced selector catalog/report validation infrastructure, but those are supporting validation assets only.
## What cannot be claimed externally
- The project has not yet implemented business MCP tools for contact search, group search, message receiving, message sending, file receiving, or file sending.
- The project has not yet implemented business MCP tools for contact search, group search, message sending, file receiving, or file sending; `isphere_receive_messages` is registered but still lacks a production loader/configuration path.
- The project has not completed production iSphere integration.
- The project has not proven a stable real message source for the full business workflow.
- The project has not proven a stable real message source for the full business workflow beyond decrypted PacketReader log evidence and synthetic/redacted tests.
- The project has not implemented real message sending or real file upload.
- N12-pre offline evidence is not N12 pass.
- N13/N14/N15 selector/report work is pre-business evidence, not finished contact/message/file capability.
@@ -38,8 +39,8 @@ Remote base before local roadmap commits: `b2d839e Merge branch 'codex/n15-repor
- The repository has a Go MCP + C# WinHelper foundation for controlled Windows-side read-only observation.
- The helper protocol boundary is explicit and keeps Windows/UIA work separate from the Go MCP service layer.
- The current code can support future MCP business tools by routing low-level Windows/UIA fallback work through a bounded helper layer.
- The project has repeatable verification scripts for the first-phase helper/MCP foundation.
- The project now has a corrected business contract and plan for core MCP communication tools.
- The project has repeatable verification scripts for the helper/MCP foundation and the current five-tool surface.
- The project now has a corrected business contract and plan for core MCP communication tools, plus a registered first read tool for receiving messages from a future configured source.
## N13/N14/N15 positioning
@@ -47,7 +48,7 @@ N13/N14/N15 are pre-business validation results. They can help identify UI eleme
## Current loop
Current loop: `Stage C / Loop C1 - log decryptor and PacketReader parser`.
Current loop: `Stage C / Loop C4 - operator verification and docs`.
Plan file: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`.
@@ -58,18 +59,17 @@ Loop rule:
3. Verify, commit exact paths, then update the next loop based on actual results.
4. Continue automatically while the next step is clear; ask the user only when blocked or when business direction changes.
Current loop output:
Current loop output so far:
1. `internal/isphere/logcodec.DecryptLine` for DES/CBC/PKCS7 Base64 log lines.
2. `internal/isphere/packetlog.ParseMessageLog` for redacted `PacketReader.ProcessPacket` XMPP `<message>` stanzas.
3. Passing unit tests with synthetic/redacted fixtures only.
4. Updated Loop C2 plan before source abstraction starts.
1. C1: `internal/isphere/logcodec.DecryptLine` and `internal/isphere/packetlog.ParseMessageLog` for redacted PacketReader message logs.
2. C2: `internal/isphere.EncryptedPacketLogSource.ReceiveMessages` source abstraction with synthetic/redacted encrypted fixtures.
3. C3: `isphere_receive_messages` MCP tool registration and server tool list update.
4. C4: updating repeatable operator verification and docs for the five-tool surface.
## Next business mainline
1. Complete Stage C Loop C1: log decryptor + PacketReader parser.
2. Rewrite and execute Loop C2: log-backed `ReceiveMessages` source abstraction.
3. Register `isphere_receive_messages` only after parser/source tests pass.
4. Add contact/group/file read tools after their source decisions are recorded.
5. Add `isphere_send_message` and `isphere_send_file` after source discovery and connector selection.
6. Keep UIA selector/report work as fallback support, not as the primary roadmap.
1. Finish Stage C Loop C4: verify and document the five-tool MCP surface.
2. Implement the next loop: safe configurable source loader or fixture path for `isphere_receive_messages`, without committing raw evidence.
3. Add contact/group/file read tools after their source decisions are recorded.
4. Add `isphere_send_message` and `isphere_send_file` after source discovery and connector selection.
5. Keep UIA selector/report work as fallback support, not as the primary roadmap.

View File

@@ -2,7 +2,7 @@
This runbook is for the first Go MCP phase of `isphere-ai-bridge`. It lets an operator build and verify the Windows helper and the Go MCP server without reading the source code.
Current scope: expose four WinHelper observation operations through Go MCP. Business contact/group/message/file tools are defined in the core MCP contract and implemented in later stages.
Current scope: expose four WinHelper observation operations plus the first log-backed business read tool, `isphere_receive_messages`, through Go MCP. The receive tool is registered with an empty default source until a safe evidence loader is wired.
## 1. Prerequisites
@@ -90,10 +90,11 @@ The verification confirms:
- C# helper can be built.
- Go MCP binary can be built.
- MCP initialize/list/call flow works through the SDK harness.
- Exactly four tools are exposed.
- Exactly five tools are exposed: four WinHelper observation tools plus `isphere_receive_messages`.
- `win_helper_version` returns `ISphereWinHelper`.
- Verification uses synthetic/local helper checks.
- Message/file/search business tools are covered by the core MCP contract, not this runbook phase.
- `isphere_receive_messages` is callable and returns an empty `messages` array from the default empty source.
- Verification uses synthetic/local helper checks and does not load raw N12-pre evidence.
- Contact/group/file/search/send business tools remain later-stage work.
## 6. Configure MCP client command
@@ -132,14 +133,15 @@ E:\coding\codex\isphere-ai-bridge\isphere-mcp.exe
## 7. Allowed tools
Only these four tools are allowed in the first phase:
These five tools are currently allowed:
| Tool | Helper op | Purpose |
| Tool | Source/op | Purpose |
| --- | --- | --- |
| `win_helper_version` | `version` | Read helper version and protocol metadata. |
| `win_helper_self_check` | `self_check` | Read desktop/UIA availability status. |
| `win_helper_scan_windows` | `scan_windows` | Read visible window metadata or likely iSphere candidates. |
| `win_helper_dump_uia` | `dump_uia` | Read a UI Automation tree for a specified window handle. |
| `win_helper_version` | helper `version` | Read helper version and protocol metadata. |
| `win_helper_self_check` | helper `self_check` | Read desktop/UIA availability status. |
| `win_helper_scan_windows` | helper `scan_windows` | Read visible window metadata or likely iSphere candidates. |
| `win_helper_dump_uia` | helper `dump_uia` | Read a UI Automation tree for a specified window handle. |
| `isphere_receive_messages` | log-backed `EncryptedPacketLogSource` | Read normalized messages from the configured PacketReader log source. The default server source is empty until a loader is wired. |
Allowed parameters:
@@ -147,15 +149,19 @@ Allowed parameters:
- `win_helper_self_check`: zero business parameters.
- `win_helper_scan_windows`: `include_all_visible` only.
- `win_helper_dump_uia`: `hwnd`, `max_depth`, `include_text`, `max_children` only.
- `isphere_receive_messages`: `limit` only.
## 8. Current tool surface and next-stage route
The current runbook verifies four WinHelper observation tools:
The current runbook verifies five tools:
- `win_helper_version`
- `win_helper_self_check`
- `win_helper_scan_windows`
- `win_helper_dump_uia`
- `isphere_receive_messages`
`isphere_receive_messages` currently has parser/source/tool registration and an empty default server source. Raw N12-pre evidence remains under ignored `runs/` paths and is not committed. The next implementation slice should wire a safe configurable loader or fixture path before claiming production message ingestion.
Core business tools for contacts, groups, messages, and files are defined in `docs/mcp-core-tools-contract.md`. Send/file capabilities enter the roadmap through that contract after source discovery, connector selection, preview metadata, execution metadata, and audit records are in place.
@@ -207,7 +213,7 @@ iSphere is internal-network only. If the current repository environment is outsi
1. **N12-pre offline evidence** for copied files and static analysis. Follow `docs/offline-evidence-intake-plan.md` and place packages under `runs\offline-evidence-intake\<evidence-id>\`.
2. **N12R internal-sandbox live capture** for real logged-in UIA evidence. Follow `docs/internal-sandbox-live-capture-plan.md` and `docs/internal-sandbox-operator-runbook.md`; place returned packages under `runs\internal-sandbox-live-capture\<capture-id>\`.
N12R is the active live-capture route when login is only possible in an internal-network test sandbox. It still allows only the four first-phase read-only tools:
N12R is the active live-capture route when login is only possible in an internal-network test sandbox. The UIA capture procedure still uses only the four helper observation tools:
```text
win_helper_version
@@ -216,6 +222,8 @@ win_helper_scan_windows
win_helper_dump_uia
```
The MCP server also registers `isphere_receive_messages`, but its default source is empty and it should not be used as N12R UIA evidence collection.
After receiving an N12R package, validate it with `docs/n12r-return-package-validation-checklist.md` before using it as evidence for selector-design review. Prefer the scripted read-only validator:
```powershell

View File

@@ -725,7 +725,7 @@ Implemented and verified in this loop:
- Default `isphere_receive_messages` source: `isphere.EncryptedPacketLogSource{}` with no configured lines, so the operator smoke call should return `messages: []` until a real evidence loader is wired.
- Verification script should still call `win_helper_version`, and should additionally call `isphere_receive_messages` with a small `limit` and assert the returned `messages` field is an array.
- [ ] **Step 1: Capture current verification red state**
- [x] **Step 1: Capture current verification red state**
Run before editing the script:
@@ -735,15 +735,15 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-go-mcp.ps1
Expected: FAIL because the existing harness still expects exactly four tools and treats `receive` as a forbidden term.
- [ ] **Step 2: Update `scripts/verify-go-mcp.ps1`**
- [x] **Step 2: Update `scripts/verify-go-mcp.ps1`**
Change expected tools to five, remove `receive` from the forbidden write/scope terms, and add an SDK call to `isphere_receive_messages` with `{ "limit": 5 }`. Assert `messages` exists and is an array; for the default empty source, assert the smoke result has zero messages.
- [ ] **Step 3: Update operator docs**
- [x] **Step 3: Update operator docs**
Update `docs/go-mcp-runbook.md` and `docs/current-status-card.md` so they describe the current five-tool surface, the empty default read source, and the fact that raw N12-pre evidence still stays under ignored `runs/` paths.
- [ ] **Step 4: Run full verification**
- [x] **Step 4: Run full verification**
Run:
@@ -756,12 +756,86 @@ powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-go-mcp.ps1
Expected: all exit 0. Remove any generated root `isphere-mcp.exe` after build.
- [ ] **Step 5: Commit Loop C4 and rewrite next loop**
- [x] **Step 5: Commit Loop C4 and rewrite next loop**
Commit exact C4 paths only. Rewrite the next loop around the remaining gap: a safe configurable source loader or fixture path for `isphere_receive_messages`, without committing raw evidence.
---
## Loop C4 Result
Implemented and verified in this loop:
- `scripts/verify-go-mcp.ps1` now expects five tools and treats `isphere_receive_messages` as an allowed read capability rather than a forbidden action term.
- The SDK harness still verifies `win_helper_version`, and now also calls `isphere_receive_messages` with `{ "limit": 5 }`.
- Default server wiring returns `messages: []` for `isphere_receive_messages`, proving the tool is callable without loading raw evidence.
- `docs/go-mcp-runbook.md` and `docs/current-status-card.md` now describe the five-tool surface and the empty default source behavior.
- Verification completed for C4 with `git diff --check`, `go test ./...`, `go build ./cmd/isphere-mcp`, and `powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-go-mcp.ps1`; the generated root `isphere-mcp.exe` build artifact was removed.
---
## Loop C5: Safe configurable PacketReader log source loader
**Goal:** Add a safe configuration path so `isphere_receive_messages` can read encrypted PacketReader log lines from a local operator-supplied file without committing raw evidence and while preserving the empty default source.
**Planned files:**
- Create: `internal/isphere/file_source.go`
- Create: `internal/isphere/file_source_test.go`
- Modify: `internal/mcpserver/server.go`
- Modify: `internal/mcpserver/server_test.go`
- Modify: `cmd/isphere-mcp/main.go`
- Modify: `scripts/verify-go-mcp.ps1`
- Modify: `docs/go-mcp-runbook.md`
- Modify: `docs/current-status-card.md`
- Modify: `docs/superpowers/plans/2026-07-09-stage-c-log-backed-receive-messages-loop.md`
**Planned interface:**
- Environment variable: `ISPHERE_PACKET_LOG_FILE`.
- Default behavior: env var unset means `isphere_receive_messages` remains an empty-source read tool returning `messages: []`.
- Configured behavior: env var set to a local text file means the server reads non-empty encrypted Base64 lines from that file into `isphere.EncryptedPacketLogSource{Lines: lines}`.
- Evidence rule: the configured file should live under ignored `runs/` or another operator-local path; the loader must not require or commit raw evidence.
- [ ] **Step 1: Write failing file loader test**
Create `internal/isphere/file_source_test.go` first and run:
```powershell
go test ./internal/isphere -run TestLoadEncryptedPacketLogSourceFromFileReadsNonEmptyLines -v
```
Expected initial failure: loader function/type does not exist.
- [ ] **Step 2: Implement file loader**
Implement a small loader that reads a UTF-8 text file, trims whitespace, skips blank lines, and returns `EncryptedPacketLogSource{Lines: lines}`. It should return clear path/context errors for missing or unreadable files.
- [ ] **Step 3: Write failing env-wired server test**
Update `internal/mcpserver/server_test.go` with a temp encrypted fixture file and a test that sets `ISPHERE_PACKET_LOG_FILE`, constructs the env-wired server, calls `isphere_receive_messages`, and expects one redacted message. Run the specific test before implementation.
- [ ] **Step 4: Implement env-wired server construction**
Add `NewServerFromEnv()` or equivalent env-aware construction. Keep `NewServer()` as the empty default for existing tests. Update `cmd/isphere-mcp/main.go` to use the env-aware server.
- [ ] **Step 5: Update operator verification/docs**
Extend `scripts/verify-go-mcp.ps1` so default verification still asserts zero messages when no env var is set. Document optional `ISPHERE_PACKET_LOG_FILE` usage in `docs/go-mcp-runbook.md` and update the status card.
- [ ] **Step 6: Run full verification and commit**
Run:
```powershell
git diff --check
go test ./...
go build ./cmd/isphere-mcp
powershell -NoProfile -ExecutionPolicy Bypass -File scripts/verify-go-mcp.ps1
```
Expected: all exit 0. Remove any generated root `isphere-mcp.exe` after build. Commit exact C5 paths only and rewrite the next loop from actual results.
---
## Self-Review
- Spec coverage: the plan follows the user's cyclic requirement: plan first, implement one loop at a time, update the next loop after each result, and ask only on blockers.

View File

@@ -6,7 +6,8 @@ $expectedTools = @(
"win_helper_version",
"win_helper_self_check",
"win_helper_scan_windows",
"win_helper_dump_uia"
"win_helper_dump_uia",
"isphere_receive_messages"
)
$tempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("isphere-go-mcp-verify-" + [guid]::NewGuid().ToString("N"))
@@ -74,9 +75,10 @@ var expectedTools = []string{
"win_helper_self_check",
"win_helper_scan_windows",
"win_helper_dump_uia",
"isphere_receive_messages",
}
var forbiddenTerms = []string{"send", "search", "file", "login", "conversation", "upload", "download", "receive", "autologin"}
var forbiddenTerms = []string{"send", "search", "file", "login", "conversation", "upload", "download", "autologin"}
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
@@ -122,7 +124,7 @@ func main() {
sort.Strings(toolNames)
want := append([]string(nil), expectedTools...)
sort.Strings(want)
if len(toolNames) != 4 || !reflect.DeepEqual(toolNames, want) {
if len(toolNames) != 5 || !reflect.DeepEqual(toolNames, want) {
fail("tools/list", fmt.Errorf("tool names = %#v, want %#v", toolNames, want))
}
@@ -153,6 +155,26 @@ func main() {
fail("tools/call win_helper_version", fmt.Errorf("helper_name = %q, want ISphereWinHelper", helperName))
}
receiveResult, err := session.CallTool(ctx, &mcp.CallToolParams{Name: "isphere_receive_messages", Arguments: map[string]any{"limit": 5}})
if err != nil {
fail("tools/call isphere_receive_messages", err)
}
if receiveResult.IsError {
fail("tools/call isphere_receive_messages", fmt.Errorf("tool returned isError=true: %#v", receiveResult.Content))
}
var receivePayload map[string]any
receiveEncoded, _ := json.Marshal(receiveResult.StructuredContent)
if err := json.Unmarshal(receiveEncoded, &receivePayload); err != nil {
fail("tools/call isphere_receive_messages", fmt.Errorf("decode structuredContent %s: %w", receiveEncoded, err))
}
messagesValue, ok := receivePayload["messages"].([]any)
if !ok {
fail("tools/call isphere_receive_messages", fmt.Errorf("messages missing or not array: %s", receiveEncoded))
}
if len(messagesValue) != 0 {
fail("tools/call isphere_receive_messages", fmt.Errorf("default empty source returned %d messages, want 0", len(messagesValue)))
}
result := map[string]any{
"ok": true,
"transport": "sdk_in_memory",
@@ -160,6 +182,7 @@ func main() {
"tool_count": len(toolNames),
"tools": toolNames,
"helper_name": helperName,
"receive_message_count": len(messagesValue),
"real_isphere_login_required": false,
"python_runtime_required": false,
"action_tools_present": false,
@@ -195,7 +218,8 @@ func fail(step string, err error) {
Assert-True ($script:harnessJson.ok -eq $true) "SDK harness did not return ok=true"
Assert-True ($script:harnessJson.helper_name -eq "ISphereWinHelper") "SDK harness helper_name mismatch: $($script:harnessJson.helper_name)"
Assert-True ($script:harnessJson.tool_count -eq 4) "SDK harness tool_count mismatch: $($script:harnessJson.tool_count)"
Assert-True ($script:harnessJson.tool_count -eq 5) "SDK harness tool_count mismatch: $($script:harnessJson.tool_count)"
Assert-True ($script:harnessJson.receive_message_count -eq 0) "SDK harness receive_message_count mismatch: $($script:harnessJson.receive_message_count)"
[ordered]@{
ok = $true
@@ -204,6 +228,7 @@ func fail(step string, err error) {
helper_name = $script:harnessJson.helper_name
tool_count = $script:harnessJson.tool_count
tools = $script:harnessJson.tools
receive_message_count = $script:harnessJson.receive_message_count
python_runtime_required = $false
real_isphere_login_required = $false
action_tools_present = $false
@@ -216,4 +241,4 @@ finally {
if (Test-Path -LiteralPath $harnessDir) {
Remove-Item -LiteralPath $harnessDir -Recurse -Force
}
}
}