@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.
- package/CHANGELOG.md +147 -0
- package/LICENSE +21 -0
- package/README.md +373 -0
- package/dist/src/abi-check.d.ts +19 -0
- package/dist/src/abi-check.js +66 -0
- package/dist/src/bridge-driver.d.ts +90 -0
- package/dist/src/bridge-driver.js +290 -0
- package/dist/src/dap-client.d.ts +80 -0
- package/dist/src/dap-client.js +296 -0
- package/dist/src/dap-driver.d.ts +162 -0
- package/dist/src/dap-driver.js +703 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +175 -0
- package/dist/src/state.d.ts +86 -0
- package/dist/src/state.js +15 -0
- package/dist/src/tools/abi-check.d.ts +3 -0
- package/dist/src/tools/abi-check.js +64 -0
- package/dist/src/tools/breakpoints.d.ts +3 -0
- package/dist/src/tools/breakpoints.js +56 -0
- package/dist/src/tools/execution.d.ts +3 -0
- package/dist/src/tools/execution.js +75 -0
- package/dist/src/tools/helpers.d.ts +27 -0
- package/dist/src/tools/helpers.js +134 -0
- package/dist/src/tools/inspection.d.ts +3 -0
- package/dist/src/tools/inspection.js +141 -0
- package/dist/src/tools/lifecycle.d.ts +3 -0
- package/dist/src/tools/lifecycle.js +103 -0
- package/dist/src/tools/preflight.d.ts +3 -0
- package/dist/src/tools/preflight.js +95 -0
- package/dist/src/tools/registry.d.ts +15 -0
- package/dist/src/tools/registry.js +19 -0
- package/dist/src/tools/snapshot.d.ts +3 -0
- package/dist/src/tools/snapshot.js +117 -0
- package/dist/src/tools/source-maps.d.ts +3 -0
- package/dist/src/tools/source-maps.js +232 -0
- package/dist/src/tools/sync.d.ts +3 -0
- package/dist/src/tools/sync.js +80 -0
- package/dist/src/tools/ui-modal.d.ts +3 -0
- package/dist/src/tools/ui-modal.js +182 -0
- package/package.json +73 -0
- package/src/abi-check.ts +97 -0
- package/src/bridge-driver.ts +328 -0
- package/src/dap-client.ts +336 -0
- package/src/dap-driver.ts +810 -0
- package/src/index.ts +155 -0
- package/src/state.ts +115 -0
- package/src/tools/abi-check.ts +66 -0
- package/src/tools/breakpoints.ts +59 -0
- package/src/tools/execution.ts +105 -0
- package/src/tools/helpers.ts +142 -0
- package/src/tools/inspection.ts +173 -0
- package/src/tools/lifecycle.ts +129 -0
- package/src/tools/preflight.ts +95 -0
- package/src/tools/registry.ts +34 -0
- package/src/tools/snapshot.ts +132 -0
- package/src/tools/source-maps.ts +222 -0
- package/src/tools/sync.ts +90 -0
- 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
|
+
[](https://www.npmjs.com/package/@i-scope/mcp-server)
|
|
4
|
+
[](https://www.npmjs.com/package/@i-scope/mcp-server)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](#)
|
|
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
|