docs: verify five-tool mcp surface
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user