@i-scope/mcp-server 0.4.2

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +147 -0
  2. package/LICENSE +21 -0
  3. package/README.md +373 -0
  4. package/dist/src/abi-check.d.ts +19 -0
  5. package/dist/src/abi-check.js +66 -0
  6. package/dist/src/bridge-driver.d.ts +90 -0
  7. package/dist/src/bridge-driver.js +290 -0
  8. package/dist/src/dap-client.d.ts +80 -0
  9. package/dist/src/dap-client.js +296 -0
  10. package/dist/src/dap-driver.d.ts +162 -0
  11. package/dist/src/dap-driver.js +703 -0
  12. package/dist/src/index.d.ts +3 -0
  13. package/dist/src/index.js +175 -0
  14. package/dist/src/state.d.ts +86 -0
  15. package/dist/src/state.js +15 -0
  16. package/dist/src/tools/abi-check.d.ts +3 -0
  17. package/dist/src/tools/abi-check.js +64 -0
  18. package/dist/src/tools/breakpoints.d.ts +3 -0
  19. package/dist/src/tools/breakpoints.js +56 -0
  20. package/dist/src/tools/execution.d.ts +3 -0
  21. package/dist/src/tools/execution.js +75 -0
  22. package/dist/src/tools/helpers.d.ts +27 -0
  23. package/dist/src/tools/helpers.js +134 -0
  24. package/dist/src/tools/inspection.d.ts +3 -0
  25. package/dist/src/tools/inspection.js +141 -0
  26. package/dist/src/tools/lifecycle.d.ts +3 -0
  27. package/dist/src/tools/lifecycle.js +103 -0
  28. package/dist/src/tools/preflight.d.ts +3 -0
  29. package/dist/src/tools/preflight.js +95 -0
  30. package/dist/src/tools/registry.d.ts +15 -0
  31. package/dist/src/tools/registry.js +19 -0
  32. package/dist/src/tools/snapshot.d.ts +3 -0
  33. package/dist/src/tools/snapshot.js +117 -0
  34. package/dist/src/tools/source-maps.d.ts +3 -0
  35. package/dist/src/tools/source-maps.js +232 -0
  36. package/dist/src/tools/sync.d.ts +3 -0
  37. package/dist/src/tools/sync.js +80 -0
  38. package/dist/src/tools/ui-modal.d.ts +3 -0
  39. package/dist/src/tools/ui-modal.js +182 -0
  40. package/package.json +73 -0
  41. package/src/abi-check.ts +97 -0
  42. package/src/bridge-driver.ts +328 -0
  43. package/src/dap-client.ts +336 -0
  44. package/src/dap-driver.ts +810 -0
  45. package/src/index.ts +155 -0
  46. package/src/state.ts +115 -0
  47. package/src/tools/abi-check.ts +66 -0
  48. package/src/tools/breakpoints.ts +59 -0
  49. package/src/tools/execution.ts +105 -0
  50. package/src/tools/helpers.ts +142 -0
  51. package/src/tools/inspection.ts +173 -0
  52. package/src/tools/lifecycle.ts +129 -0
  53. package/src/tools/preflight.ts +95 -0
  54. package/src/tools/registry.ts +34 -0
  55. package/src/tools/snapshot.ts +132 -0
  56. package/src/tools/source-maps.ts +222 -0
  57. package/src/tools/sync.ts +90 -0
  58. package/src/tools/ui-modal.ts +201 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,147 @@
1
+ # Changelog — @i-scope/mcp-server
2
+
3
+ All notable changes to this package will be documented here. The format
4
+ is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
5
+ this project adheres to [Semantic Versioning](https://semver.org/).
6
+
7
+ ## [0.4.2] — 2026-05-20
8
+
9
+ ### Added
10
+
11
+ - **`system_abi_check` MCP tool** — wraps `protocol/version` on
12
+ `iScopeBridge.exe` (no COM, no Oscilloscope). Returns client vs server
13
+ wire ABI semver, compatibility kind (`ok` / `warn` / `fatal`), optional
14
+ `policy` argument (`strict` | `warn` | `ignore`), and user hints when
15
+ the bundled helper is stale relative to `@i-scope/iscope-bridge-client`.
16
+
17
+ ### Changed
18
+
19
+ - Root `npm run test:prepublish` gate (headless matrix) runs before
20
+ `publish-all` in live mode; see `scripts/test-prepublish-matrix.cjs`.
21
+
22
+ ## [0.4.0] — 2026-05-19
23
+
24
+ ### Added — `system_preflight_check` MCP tool
25
+
26
+ A new MCP tool that surfaces a structured pre-flight diagnostic for
27
+ the iScope debug stack. It wraps the `preflight/check` JSON-RPC
28
+ method of `iScopeBridge.exe` (introduced in
29
+ `@i-scope/iscope-bridge-client` v0.3.0) and probes the local
30
+ registry for the two prerequisites Oscilloscope needs to expose
31
+ JScript debugging:
32
+
33
+ - The Windows Script Debugger (Machine Debug Manager, `pdm.dll`,
34
+ CLSID `{0BFCC060-8C1D-11D0-ACCD-00AA0060275C}`). When this CLSID
35
+ is missing, Oscilloscope shows the "Unable to create debuger
36
+ object!" dialog at first `ExecuteFile` and silently declines to
37
+ run scripts in debug mode. The verdict
38
+ `'script-debugger-not-registered'` carries actionable user hints
39
+ ("install Build Tools / Remote Tools for Visual Studio") and a
40
+ download URL for the AI / UI to surface as a clickable link.
41
+ - The Oscilloscope `ScopeAppDbgCtrl` CLSID
42
+ (`{176ED004-4A4D-439F-BDEC-5A78CC5BFC7B}`) — a side-check that
43
+ lets an AI agent distinguish "Script Debugger missing" from
44
+ "Oscilloscope not installed" failure modes.
45
+
46
+ The tool is read-only, idempotent, and does NOT require
47
+ Oscilloscope to be running. AI agents should call it proactively
48
+ when the user reports "F5 just sits there", "breakpoints are
49
+ ignored", or whenever `debug_launch` fails with a generic
50
+ "engine returned but emitted no sink events" symptom.
51
+
52
+ ### Changed — DAP adapter pre-launch hook
53
+
54
+ `@i-scope/dap-adapter` now calls `bridge.preflightCheck()` between
55
+ `bridge.start()` and `bridge.initialize()` during `launchRequest`
56
+ processing. The structured pre-flight failure surfaces through the
57
+ existing `showErrorWithDownloadLink` host dependency, replacing the
58
+ ad-hoc registry probe that used to live inside the 4-second
59
+ engine-start watchdog. The old watchdog still calls
60
+ `isScriptDebuggerInstalled()` as a fallback diagnostic for clients
61
+ that bypass the pre-launch hook, but no longer drives the
62
+ download-link modal — the pre-flight already did.
63
+
64
+ ### Bumped dependency
65
+
66
+ - `@i-scope/iscope-bridge-client` `^0.3.0` (was `^0.2.0`). v0.3.0
67
+ introduced the typed `preflightCheck()` wrapper that the new
68
+ tool calls into and the adapter pre-launch hook depends on.
69
+
70
+ ## [0.3.0] — 2026-05-19
71
+
72
+ ### Added — UI modal control tools (interactive AI agent)
73
+
74
+ Four new MCP tools that surface Oscilloscope's child dialogs as a
75
+ programmatically driveable tree. They unblock AI agents (and CI
76
+ pipelines) when a script is stuck on a `Host.Configure()` form, when
77
+ Oscilloscope itself shows a diagnostic prompt, or whenever a
78
+ `debug_continue` / `debug_step_*` silently times out because of a
79
+ modal in the way.
80
+
81
+ - `ui_modal_list` — enumerate every visible top-level dialog owned by
82
+ Oscilloscope, with full child-controls inventory (HWND, controlId,
83
+ className, text, isVisible / isEnabled, isChecked for checkboxes /
84
+ radios) and a `signature` classification (`configure` / `diagnostic`
85
+ / `unknown`) so the AI knows which dialogs are safe to drive
86
+ automatically. Read-only / idempotent / safe regardless of debug
87
+ session state.
88
+ - `ui_modal_click` — programmatic button click via
89
+ `SendMessage(WM_COMMAND, MAKEWPARAM(controlId, BN_CLICKED))`.
90
+ Standard ids: `1`=IDOK, `2`=IDCANCEL, `6`=IDYES, `7`=IDNO; custom
91
+ buttons in Configure forms use whatever id `ui_modal_list` reports.
92
+ - `ui_modal_fill` — fill an `Edit` (`WM_SETTEXT`) or `ComboBox`
93
+ (`CB_FINDSTRINGEXACT` + `CB_SETCURSEL` when the value matches an
94
+ existing item, `WM_SETTEXT` fallback otherwise). Returns
95
+ `previousText` for verification / diffing.
96
+ - `ui_modal_dismiss` — explicit modal close. `mode='close'` →
97
+ `PostMessage(WM_CLOSE)` (= X button); `mode='cancel'` /
98
+ `mode='ok'` → `SendMessage(WM_COMMAND, IDCANCEL/IDOK)`.
99
+
100
+ ### Safety contract enforced in C++ (`iScopeBridge.exe`)
101
+
102
+ - `GetWindowThreadProcessId(targetHwnd) == oscPid` — every UI handler
103
+ refuses to touch a window owned by a different process. Returns
104
+ JSON-RPC error `-32602` (invalid params) on mismatch.
105
+ - Target HWND must NOT be the Oscilloscope main window — only owned
106
+ dialogs are mutated.
107
+ - All synchronous `SendMessage`s use `SendMessageTimeout(SMTO_ABORTIFHUNG,
108
+ 500 ms)` — a hung target STA cannot stall the helper thread.
109
+
110
+ ### Bumped dependency
111
+
112
+ - `@i-scope/iscope-bridge-client` `^0.2.0` (was `^0.1.0`). v0.2.0
113
+ introduced the typed `uiModal*()` wrappers that the new tools call
114
+ into.
115
+
116
+ ## [0.2.0] — 2026-05-19
117
+
118
+ ### Changed (breaking by deployment, NOT by tool API)
119
+
120
+ - DAP server is now spawned through
121
+ `require.resolve('@i-scope/dap-adapter/dist/src/server.js')` — the
122
+ adapter lives in its own published package
123
+ ([`@i-scope/dap-adapter`](https://www.npmjs.com/package/@i-scope/dap-adapter))
124
+ and is pulled in as a regular `dependencies` entry. `npm install
125
+ @i-scope/mcp-server` is now sufficient for an end-user install; no
126
+ monorepo clone, no extension build, no `ISCOPE_EXTENSION_PATH` env.
127
+ - The internal launcher `scripts/iscope-mcp-debug-server.cjs` and the
128
+ `vscode-stub.cjs` mock are gone. The adapter has no `require('vscode')`
129
+ in its runtime path anymore, so direct `node server.js` works.
130
+ - `DapDriverOptions.extensionPath` became optional — kept as a
131
+ `bundledRoot` override for embedded use-cases.
132
+
133
+ ### Tool surface
134
+
135
+ - No changes to the 16 debug tools. Same input/output schemas, same
136
+ state machine.
137
+
138
+ ## [0.1.0] — 2026-05-15
139
+
140
+ ### Added
141
+
142
+ - Initial public release. 16 MCP tools for AI-driven .ajs debugging:
143
+ `debug_launch` / `debug_disconnect` / `debug_current_state`,
144
+ `debug_set_breakpoints`, `debug_continue` / `debug_step_*`,
145
+ `debug_wait_for_paused` / `debug_read_output`,
146
+ `debug_stack_trace` / `debug_scopes` / `debug_variables` /
147
+ `debug_evaluate`, `debug_snapshot`, `debug_resolve_source`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 iScope
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,373 @@
1
+ # @i-scope/mcp-server
2
+
3
+ [![npm version](https://img.shields.io/npm/v/%40i-scope%2Fmcp-server.svg?label=npm)](https://www.npmjs.com/package/@i-scope/mcp-server)
4
+ [![npm downloads](https://img.shields.io/npm/dm/%40i-scope%2Fmcp-server.svg)](https://www.npmjs.com/package/@i-scope/mcp-server)
5
+ [![License: MIT](https://img.shields.io/npm/l/%40i-scope%2Fmcp-server.svg)](./LICENSE)
6
+ [![Node](https://img.shields.io/node/v/%40i-scope%2Fmcp-server.svg)](#)
7
+
8
+ > **Part of the [`@i-scope/debugger`](https://www.npmjs.com/package/@i-scope/debugger) SDK** — one of seven leaf packages aggregated by the `@i-scope/debugger` meta-umbrella.
9
+ > Most users should install the meta (`npm install @i-scope/debugger`),
10
+ > which transitively pulls this package in together with the rest of the
11
+ > Debugger SDK (DAP adapter, native helper, source-map / VLST / COM
12
+ > leaves). Install `@i-scope/mcp-server` **directly** only when you want
13
+ > the MCP server surface without the rest of the SDK on your top-level
14
+ > `package.json` (e.g. an MCP-only Cursor / Claude Code config via
15
+ > `npx -y @i-scope/mcp-server`).
16
+
17
+ Model Context Protocol (MCP) server that lets AI agents drive a
18
+ `Oscilloscope.exe` debug session for `.ajs` scripts — set breakpoints,
19
+ step, read variables and call stack, evaluate watch expressions — all
20
+ through standard MCP tools layered on top of the iScope DAP adapter.
21
+
22
+ > **Status:** v0.4.0 — **21 MCP tools** shipped across three phases:
23
+ > Phase 1 (16 debug tools), Phase 2 (4 UI modal control tools —
24
+ > `ui_modal_list / _click / _fill / _dismiss`), Phase 3 (1 system
25
+ > diagnostics tool — `system_preflight_check`). Phase 4+ planned:
26
+ > `control_*` (open file, run script, …) and `data_*` (read channels,
27
+ > measure signals). See [`info/Plan.md`](../../info/Plan.md) in the
28
+ > parent repo.
29
+
30
+ ## Quick start
31
+
32
+ 1. **Prerequisites** (Windows):
33
+
34
+ - `Oscilloscope.exe` v5 installed (default install path is supported
35
+ out-of-the-box; for portable installs see the
36
+ `oscilloscopePath` launch argument).
37
+
38
+ 2. **Install** the MCP server. Two flavours:
39
+
40
+ **End-user (npm-only)** — no repo clone, no local build:
41
+
42
+ ```pwsh
43
+ npm install -g @i-scope/mcp-server
44
+ # ...or use npx in mcp.json (see step 3).
45
+ ```
46
+
47
+ This pulls in `@i-scope/dap-adapter`, `@i-scope/iscope-bridge-client`,
48
+ and the native helper `@i-scope/iscope-bridge` (which bundles
49
+ `iScopeBridge.exe`) as transitive dependencies. No `ISCOPE_*`
50
+ environment variable required.
51
+
52
+ **Monorepo developer** — full local build:
53
+
54
+ ```pwsh
55
+ npm install
56
+ npm run build:packages
57
+ npm --workspace=@i-scope/iscope-bridge run build:msbuild
58
+ ```
59
+
60
+ 3. **Configure your MCP client** (Cursor example, `.cursor/mcp.json`):
61
+
62
+ ```json
63
+ {
64
+ "mcpServers": {
65
+ "iscope-debug": {
66
+ "command": "npx",
67
+ "args": ["-y", "@i-scope/mcp-server"]
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ For local development from the monorepo:
74
+
75
+ ```json
76
+ {
77
+ "mcpServers": {
78
+ "iscope-debug": {
79
+ "command": "node",
80
+ "args": ["${workspaceFolder}/packages/mcp-server/dist/src/index.js"]
81
+ }
82
+ }
83
+ }
84
+ ```
85
+
86
+ `ISCOPE_EXTENSION_PATH` is optional now — set it only when you want
87
+ to override the helper-binary lookup with a custom bundled root.
88
+
89
+ 3. **Reload Cursor** and ask your AI agent:
90
+
91
+ > "Run `dist/Analyzer.ajs` and pause on `src/index.ts:42`, show me
92
+ > the value of `signal` at that point."
93
+
94
+ The agent will use `debug_launch` + `debug_set_breakpoints` +
95
+ `debug_continue` + `debug_variables` to inspect your script.
96
+
97
+ ## Architecture
98
+
99
+ ```
100
+ AI Agent (Cursor / Claude Code)
101
+ ↕ MCP JSON-RPC over stdio
102
+ @i-scope/mcp-server (this package)
103
+ ↕ DAP over stdio (custom DapClient → spawned server.js)
104
+ @i-scope/dap-adapter (AjsDebugSession + stdio server entry)
105
+ ↕ JSON-RPC over stdio
106
+ @i-scope/iscope-bridge-client → @i-scope/iscope-bridge (iScopeBridge.exe)
107
+ ↕ COM (DISPID Invoke)
108
+ Oscilloscope.exe (JScript engine + ScopeAppDbgCtrl)
109
+ ```
110
+
111
+ Each MCP tool delegates to the existing DAP adapter — no debug logic is
112
+ duplicated. The session state machine
113
+ (`idle → launching → running ⇄ paused → terminated`) lives in
114
+ [`src/dap-driver.ts`](src/dap-driver.ts). Tool groups live under
115
+ [`src/tools/`](src/tools).
116
+
117
+ ## Tool reference
118
+
119
+ v0.4.2 ships **22 tools** (16 debug + 4 UI modal + 2 system diagnostics).
120
+ Every tool is invokable via the standard MCP `tools/call` request;
121
+ consult the tool descriptions inside the running server (`tools/list`)
122
+ for the canonical schemas.
123
+
124
+ ### Lifecycle
125
+
126
+ | Tool | Purpose |
127
+ |-----------------------|-------------------------------------------------------------------------|
128
+ | `debug_launch` | Spawn the DAP adapter, start `program` under Oscilloscope. |
129
+ | `debug_disconnect` | Tear down the session; close Oscilloscope (if we launched it). |
130
+ | `debug_current_state` | Lock-free snapshot of session state + last-known stop info. |
131
+
132
+ ### Breakpoints
133
+
134
+ | Tool | Purpose |
135
+ |-------------------------|----------------------------------------------------------|
136
+ | `debug_set_breakpoints` | Replace the breakpoint set for one source file. Pass `lines:[]` to clear. |
137
+
138
+ ### Execution control
139
+
140
+ | Tool | Purpose |
141
+ |---------------------|-------------------------------------------------------------------------|
142
+ | `debug_continue` | Resume; returns the next paused/terminated transition. |
143
+ | `debug_step_over` | Step over (same frame). |
144
+ | `debug_step_into` | Step into the called function. |
145
+ | `debug_step_out` | Step out of the current frame. |
146
+
147
+ ### Sync
148
+
149
+ | Tool | Purpose |
150
+ |-------------------------|----------------------------------------------------------------------|
151
+ | `debug_wait_for_paused` | Block until the next pause / termination (or timeout). |
152
+ | `debug_read_output` | Cursor-paginated read of buffered `Host.ReportOut` + adapter logs. |
153
+
154
+ ### Inspection
155
+
156
+ | Tool | Purpose |
157
+ |---------------------|-------------------------------------------------------------------------|
158
+ | `debug_stack_trace` | Get the current call stack with source-map provenance per frame. |
159
+ | `debug_scopes` | List scopes (Locals, …) for a given frame. |
160
+ | `debug_variables` | Enumerate variables under a scope or compound `variablesReference`. |
161
+ | `debug_evaluate` | Evaluate a JScript expression (watch / hover / repl). |
162
+
163
+ ### Composite
164
+
165
+ | Tool | Purpose |
166
+ |------------------|--------------------------------------------------------------------------|
167
+ | `debug_snapshot` | Stack + scopes + locals in one round-trip, atomically under one mutex. |
168
+
169
+ ### Source maps (no debug session required)
170
+
171
+ | Tool | Purpose |
172
+ |------------------------|--------------------------------------------------------------------|
173
+ | `debug_resolve_source` | Translate `.ts ↔ .ajs` positions for any on-disk pair. |
174
+
175
+ ### UI modal control (interactive AI agent)
176
+
177
+ Surface Oscilloscope's child dialogs as a programmatically driveable
178
+ tree. Use these tools when a `debug_continue` / `debug_step_*`
179
+ unexpectedly times out — the script is most likely blocked on a
180
+ `Host.Configure()` form, or Oscilloscope itself is reporting a
181
+ diagnostic prompt that needs dismissal.
182
+
183
+ | Tool | Purpose |
184
+ |--------------------|----------------------------------------------------------------------------------------------------------|
185
+ | `ui_modal_list` | Enumerate every visible top-level dialog owned by Oscilloscope, with child controls and a `signature` classification (`configure` / `diagnostic` / `unknown`). |
186
+ | `ui_modal_click` | Programmatic button click (`WM_COMMAND` + `BN_CLICKED`). Standard ids: `1`=IDOK, `2`=IDCANCEL, `6`=IDYES, `7`=IDNO. |
187
+ | `ui_modal_fill` | Set the text of a child `Edit` (`WM_SETTEXT`) or `ComboBox` (`CB_FINDSTRINGEXACT` + `CB_SETCURSEL`, `WM_SETTEXT` fallback). Returns `previousText` for diffing. |
188
+ | `ui_modal_dismiss` | Explicit close — `mode='close'` → `PostMessage(WM_CLOSE)` (the X button); `mode='cancel'` / `'ok'` → `SendMessage(WM_COMMAND, IDCANCEL/IDOK)`. |
189
+
190
+ Safety contract enforced in C++ for every UI tool:
191
+
192
+ - `GetWindowThreadProcessId(hwnd) == oscPid` — we never touch a window
193
+ owned by a different process.
194
+ - Target HWND must not be the Oscilloscope main window — we only act
195
+ on its owned dialogs.
196
+ - All synchronous calls use `SendMessageTimeout(SMTO_ABORTIFHUNG,
197
+ 500 ms)` — a hung target STA cannot stall the helper.
198
+
199
+ #### AI usage pattern — Configure() form
200
+
201
+ ```ts
202
+ // 1. debug_continue times out — script is likely blocked on a modal.
203
+ const list = await callTool('ui_modal_list', {});
204
+ const m = list.modals.find(m => m.signature === 'configure');
205
+ if (m) {
206
+ // 2. Find the input + the OK button.
207
+ const edit = m.controls.find(c => c.className === 'Edit');
208
+ const ok = m.controls.find(c => c.controlId === 1 /* IDOK */);
209
+ // 3. Fill and submit.
210
+ await callTool('ui_modal_fill', { hwnd: m.hwnd, controlId: edit.controlId, text: '42' });
211
+ await callTool('ui_modal_click', { hwnd: m.hwnd, controlId: ok.controlId });
212
+ // 4. Resume — engine should now proceed past the blocked Configure() call.
213
+ }
214
+ ```
215
+
216
+ #### AI usage pattern — diagnostic dismissal
217
+
218
+ ```ts
219
+ const list = await callTool('ui_modal_list', {});
220
+ const diag = list.modals.find(m => m.signature === 'diagnostic');
221
+ if (diag) {
222
+ // Read diag.title, take action, then dismiss with Enter/Esc.
223
+ await callTool('ui_modal_dismiss', { hwnd: diag.hwnd, mode: 'ok' });
224
+ }
225
+ ```
226
+
227
+ These tools work **without an active debug session** (Oscilloscope only
228
+ needs to be running) and are SAFE to mix with an active DAP session —
229
+ COM lets multiple clients attach to Oscilloscope. The complementary
230
+ Q4b auto-rescue mechanism (`packages/iscope-bridge/src/Q4bProbe.cpp`)
231
+ remains as a safety net during `disconnect`, but `ui_modal_*` is the
232
+ preferred primary path for interactive control.
233
+
234
+ ### System diagnostics
235
+
236
+ Verify host machine prerequisites before (or after a failure during)
237
+ any debug session. Read-only / idempotent — safe to call without
238
+ Oscilloscope running.
239
+
240
+ | Tool | Purpose |
241
+ |--------------------------|---------------------------------------------------------------------------------------------------------|
242
+ | `system_preflight_check` | Verify that Windows Script Debugger (Machine Debug Manager, `pdm.dll`) is installed and that Oscilloscope's COM classes are registered. Returns a structured verdict (`ok` / `script-debugger-not-registered` / `script-debugger-file-missing`), per-check details, and human-readable hints + a download URL. Read-only / idempotent; safe to call before any debug session and without Oscilloscope running. AI agents should call this proactively when a launch fails or a user reports "BP ignored". |
243
+ | `system_abi_check` | Probe `iScopeBridge.exe` wire ABI via `protocol/version` (no COM). Compares helper `abi` semver to `@i-scope/iscope-bridge-client`. Optional `policy` (`strict` default). Call when mixing npm versions or after swapping a custom helper binary — before `debug_launch` if you see `ProtocolVersionMismatchError`. |
244
+
245
+ Wire contract: preflight response shape is exported from
246
+ `@i-scope/com-protocol-types` as `PreflightCheckResponse`.
247
+
248
+ #### AI usage pattern — preflight before launch
249
+
250
+ ```ts
251
+ const r = await callTool('system_preflight_check', {});
252
+ if (!r.ok) {
253
+ // Surface r.userHints + r.downloadUrl to the user.
254
+ // Distinguish: r.verdict === 'script-debugger-not-registered' → install MDM
255
+ // r.verdict === 'script-debugger-file-missing' → repair install
256
+ // r.oscilloscope.comRegistered === false → Oscilloscope itself is not installed
257
+ }
258
+ ```
259
+
260
+ ### Frame source-map provenance
261
+
262
+ Every frame in `debug_stack_trace` / `debug_snapshot` carries a
263
+ `sourceOrigin` field:
264
+
265
+ - `mapped` — `source` is `.ts` because the adapter resolved the
266
+ bundler's source map.
267
+ - `unmapped-fallback` — launch was `.ts` but the `.ajs.map` had a gap
268
+ for this line; `source` is the raw `.ajs` so you don't act on stale
269
+ TS coordinates.
270
+ - `generated` — launch was directly against `.ajs` / `.apn` / `.aps`.
271
+
272
+ ## Tool-namespace reservation (Phase 4+)
273
+
274
+ Each MCP tool name is prefixed by a short namespace identifying which
275
+ Oscilloscope **COM-domain** it targets. The table below reserves the
276
+ allocation **ahead of time** so future expansion of Oscilloscope's COM
277
+ surface (a third remote-control object, additional file/app operations
278
+ on `ScopeAppControl`, signal-data access on the existing debug object)
279
+ does not collide with the `debug_*` / `ui_modal_*` / `system_*` tools
280
+ already shipped.
281
+
282
+ | Prefix | COM-domain in Oscilloscope.exe | Status | Purpose |
283
+ |-----------------|------------------------------------------------|---------------------|-----------------------------------------------------------------------------------------------|
284
+ | `debug_*` | `ScopeAppDbgCtrl` (debug COM object) | **shipped** (16) | Launch, breakpoints, step, stack, variables, evaluate, snapshot. Phase 1. |
285
+ | `ui_modal_*` | Win32 GUI (modal-dialog rescue, not COM) | **shipped** (4) | List / click / fill / dismiss native modal dialogs blocking the engine. Phase 2. |
286
+ | `system_*` | host machine (registry / file-system probe) | **shipped** (1) | Preflight diagnostics — MDM / `pdm.dll` / Oscilloscope COM registration. Phase 3. |
287
+ | `system_abi_check` | `iScopeBridge.exe` JSON-RPC (`protocol/version`) | **shipped** v0.4.2 | Wire ABI semver probe before `initialize` (no Oscilloscope required). See `info/Naming-Taxonomy.md` §11. |
288
+ | `app_*` | `ScopeAppControl` (existing file/app COM) | **reserved** (none) | `OpenFile`, future `SaveAs`, file-tab manipulation, app-level UI control. Phase 4a. |
289
+ | `device_*` | `ScopeAppRemoteControl` (planned 3rd COM) | **reserved** (none) | Remote control of the oscilloscope **instrument** (channel config, triggers, capture, …). |
290
+ | `remote_*` | `ScopeAppRemoteControl` (planned 3rd COM) | **reserved** (none) | Remote control of the **application** itself (start/stop measurement, switch mode, …). |
291
+ | `data_*` | signal-data access (multi-COM, read-only) | **reserved** (none) | Read channel samples, measure (peak / RMS / FFT), edge detection on a loaded `.mwf`. |
292
+ | `analyzer_*` | `.aps` analyzer-panel runtime | **reserved** (none) | Drive analyzer-panel state from MCP (load `.aps`, list panels, dump results). Q8 follow-on. |
293
+
294
+ ### Why this matters
295
+
296
+ Without the reservation, a Phase 4 implementer who sees Oscilloscope
297
+ gain a third COM object called "Remote Control" would naturally pick
298
+ `control_*` as the prefix — colliding with `ScopeAppControl` (the
299
+ existing file-operations COM). The split `app_*` vs `device_*` vs
300
+ `remote_*` keeps the COM-domain → prefix mapping injective: an AI
301
+ agent can always tell from the tool name which Oscilloscope subsystem
302
+ will be touched.
303
+
304
+ ### Cross-reference
305
+
306
+ The npm-package side of this question (why Phase 4+ does **not**
307
+ require new `@i-scope/*` packages, only minor/major version bumps of
308
+ the existing seven leaves) is covered in
309
+ [`info/Naming-Taxonomy.md`](https://gitlab.com/i-scope/Debugger/-/blob/main/info/Naming-Taxonomy.md)
310
+ §9 "MCP tool-namespace allocation" and §6.7 "ABI extension ≠ new npm
311
+ package".
312
+
313
+ ## Integration with @i-scope SDK
314
+
315
+ If you use `@i-scope/cli-tools` (`iscope create-analyzer`) to scaffold
316
+ analyzers, this MCP server transparently understands the resulting
317
+ TypeScript → `.ajs` source maps. Pass `.ts` paths to `program` and
318
+ `source` — frames and breakpoints come back in `.ts` space
319
+ automatically. The same source maps the platform's
320
+ `@i-scope/webpack-config` produces are consumed unchanged here; see
321
+ the platform's `docs/guides/debugging.md` for the producer side.
322
+
323
+ ## Testing
324
+
325
+ Three integration tests (drive the server through the official
326
+ `@modelcontextprotocol/sdk` client over stdio) plus one unit-test
327
+ suite for the pure driver internals:
328
+
329
+ ```pwsh
330
+ # Unit tests — no Oscilloscope, no DAP child. Covers Mutex, output-
331
+ # buffer pagination, classifyFrame with reverse source-map lookup.
332
+ npm --workspace=@i-scope/mcp-server run test:unit
333
+
334
+ # Integration: pure source-map translation. No Oscilloscope.
335
+ npm --workspace=iscope-debugger run test:mcp-sourcemaps
336
+
337
+ # Integration: full launch → read output → disconnect cycle.
338
+ # Requires Oscilloscope.exe + a .mwf.
339
+ npm --workspace=iscope-debugger run test:mcp
340
+
341
+ # Integration: snapshot equivalence — asserts debug_snapshot returns
342
+ # the same payload as the headless inspect.cjs harness on the VLST
343
+ # fixture. Requires Oscilloscope + .mwf.
344
+ npm --workspace=iscope-debugger run test:mcp-snapshot
345
+ ```
346
+
347
+ Integration test scripts live in
348
+ `extension/cursor-vscode/src/tests/{18,19,20}-mcp-*.ts`; unit tests in
349
+ `packages/mcp-server/src/__tests__/dap-driver.test.ts`.
350
+
351
+ ## Related packages
352
+
353
+ This package is one of seven leaves of the
354
+ [`@i-scope/debugger`](https://www.npmjs.com/package/@i-scope/debugger) SDK
355
+ meta-umbrella. The full family:
356
+
357
+ | Package | Role |
358
+ |---------|------|
359
+ | [`@i-scope/debugger`](https://www.npmjs.com/package/@i-scope/debugger) | **meta** — one-install entry point for the whole SDK |
360
+ | **`@i-scope/mcp-server`** *(you are here)* | MCP server for AI agents (21 tools: 16 debug + 4 UI modal + 1 system) |
361
+ | [`@i-scope/dap-adapter`](https://www.npmjs.com/package/@i-scope/dap-adapter) | DAP server (`AjsDebugSession`) — embeddable + stdio |
362
+ | [`@i-scope/iscope-bridge-client`](https://www.npmjs.com/package/@i-scope/iscope-bridge-client) | Node JSON-RPC client to the native helper |
363
+ | [`@i-scope/iscope-bridge`](https://www.npmjs.com/package/@i-scope/iscope-bridge) | Win32 native helper binary (`iScopeBridge.exe`) |
364
+ | [`@i-scope/source-map-bridge`](https://www.npmjs.com/package/@i-scope/source-map-bridge) | TS ↔ AJS source-map manager |
365
+ | [`@i-scope/vlst-parser`](https://www.npmjs.com/package/@i-scope/vlst-parser) | Parser for VLST locals/Watch blobs |
366
+ | [`@i-scope/com-protocol-types`](https://www.npmjs.com/package/@i-scope/com-protocol-types) | TS-mirror of COM DISPID / event constants |
367
+
368
+ See [`info/Naming-Taxonomy.md`](https://gitlab.com/i-scope/Debugger/-/blob/main/info/Naming-Taxonomy.md)
369
+ for the rationale behind the package allocation.
370
+
371
+ ## License
372
+
373
+ MIT. See [LICENSE](./LICENSE).
@@ -0,0 +1,19 @@
1
+ import { type ProtocolVersionResponse, type AbiPolicy, type AbiCompatKind, type AbiWarningPayload } from '@i-scope/iscope-bridge-client';
2
+ export interface AbiCheckResult {
3
+ ok: boolean;
4
+ clientAbi: string;
5
+ serverAbi: string;
6
+ server: string;
7
+ buildTime?: string;
8
+ compatKind: AbiCompatKind;
9
+ compatReason: string;
10
+ policy: AbiPolicy;
11
+ warnings: AbiWarningPayload[];
12
+ userHints: string[];
13
+ }
14
+ /**
15
+ * Evaluate wire ABI compatibility from a `protocol/version` response.
16
+ * Does not spawn the helper — callers supply the RPC result.
17
+ */
18
+ export declare function evaluateAbiCheck(version: ProtocolVersionResponse, policy?: AbiPolicy, clientAbi?: string): AbiCheckResult;
19
+ //# sourceMappingURL=abi-check.d.ts.map
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ // ABI probe logic shared by BridgeDriver and unit tests.
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.evaluateAbiCheck = evaluateAbiCheck;
5
+ const iscope_bridge_client_1 = require("@i-scope/iscope-bridge-client");
6
+ /**
7
+ * Evaluate wire ABI compatibility from a `protocol/version` response.
8
+ * Does not spawn the helper — callers supply the RPC result.
9
+ */
10
+ function evaluateAbiCheck(version, policy = 'strict', clientAbi = iscope_bridge_client_1.ISCOPE_BRIDGE_ABI_VERSION) {
11
+ const serverAbi = version.abi;
12
+ const compat = (0, iscope_bridge_client_1.checkAbiCompat)(clientAbi, serverAbi);
13
+ const warnings = [];
14
+ try {
15
+ (0, iscope_bridge_client_1.applyAbiPolicy)(serverAbi, policy, (w) => warnings.push(w), clientAbi);
16
+ }
17
+ catch (e) {
18
+ if (e instanceof iscope_bridge_client_1.ProtocolVersionMismatchError) {
19
+ return {
20
+ ok: false,
21
+ clientAbi,
22
+ serverAbi,
23
+ server: version.server,
24
+ buildTime: version.buildTime,
25
+ compatKind: 'fatal',
26
+ compatReason: e.message,
27
+ policy,
28
+ warnings,
29
+ userHints: buildUserHints(clientAbi, serverAbi, 'fatal', e.message),
30
+ };
31
+ }
32
+ throw e;
33
+ }
34
+ const ok = policy === 'ignore'
35
+ || policy === 'warn'
36
+ || compat.kind !== 'fatal';
37
+ return {
38
+ ok,
39
+ clientAbi,
40
+ serverAbi,
41
+ server: version.server,
42
+ buildTime: version.buildTime,
43
+ compatKind: compat.kind,
44
+ compatReason: compat.reason,
45
+ policy,
46
+ warnings,
47
+ userHints: buildUserHints(clientAbi, serverAbi, compat.kind, compat.reason),
48
+ };
49
+ }
50
+ function buildUserHints(clientAbi, serverAbi, kind, reason) {
51
+ if (kind === 'ok') {
52
+ return [`Wire ABI ${serverAbi} matches client expectation ${clientAbi}.`];
53
+ }
54
+ if (kind === 'warn') {
55
+ return [
56
+ reason || `Server ABI ${serverAbi} is older than client ${clientAbi}.`,
57
+ 'Session may still work; upgrade iScopeBridge.exe when convenient.',
58
+ ];
59
+ }
60
+ return [
61
+ reason || `ABI incompatible: client expects ${clientAbi}, helper reports ${serverAbi}.`,
62
+ 'Rebuild and redeploy iScopeBridge.exe from the same monorepo tag as @i-scope/iscope-bridge-client.',
63
+ 'If you mix npm packages, pin matching versions from the same release.',
64
+ ];
65
+ }
66
+ //# sourceMappingURL=abi-check.js.map