cdp-mcp 0.2.2 → 0.4.0
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/README.md +28 -303
- package/bin.js +23 -0
- package/contract.d.ts +1 -0
- package/contract.js +2 -0
- package/index.d.ts +1 -0
- package/index.js +2 -0
- package/package.json +31 -73
- package/dist/contract.d.ts +0 -11
- package/dist/contract.js +0 -11
- package/dist/contract.js.map +0 -1
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -402
- package/dist/index.js.map +0 -1
- package/dist/locator.d.ts +0 -108
- package/dist/locator.js +0 -176
- package/dist/locator.js.map +0 -1
- package/dist/server.d.ts +0 -2
- package/dist/server.js +0 -41
- package/dist/server.js.map +0 -1
- package/dist/session/browser.d.ts +0 -29
- package/dist/session/browser.js +0 -409
- package/dist/session/browser.js.map +0 -1
- package/dist/session/buffers.d.ts +0 -48
- package/dist/session/buffers.js +0 -43
- package/dist/session/buffers.js.map +0 -1
- package/dist/session/pause.d.ts +0 -21
- package/dist/session/pause.js +0 -99
- package/dist/session/pause.js.map +0 -1
- package/dist/session/state.d.ts +0 -54
- package/dist/session/state.js +0 -93
- package/dist/session/state.js.map +0 -1
- package/dist/sourcemap/loader.d.ts +0 -4
- package/dist/sourcemap/loader.js +0 -138
- package/dist/sourcemap/loader.js.map +0 -1
- package/dist/sourcemap/normalize.d.ts +0 -2
- package/dist/sourcemap/normalize.js +0 -59
- package/dist/sourcemap/normalize.js.map +0 -1
- package/dist/sourcemap/store.d.ts +0 -57
- package/dist/sourcemap/store.js +0 -196
- package/dist/sourcemap/store.js.map +0 -1
- package/dist/tools/_locator_runtime.d.ts +0 -31
- package/dist/tools/_locator_runtime.js +0 -243
- package/dist/tools/_locator_runtime.js.map +0 -1
- package/dist/tools/_register.d.ts +0 -2
- package/dist/tools/_register.js +0 -30
- package/dist/tools/_register.js.map +0 -1
- package/dist/tools/breakpoints.d.ts +0 -4
- package/dist/tools/breakpoints.js +0 -200
- package/dist/tools/breakpoints.js.map +0 -1
- package/dist/tools/console.d.ts +0 -2
- package/dist/tools/console.js +0 -48
- package/dist/tools/console.js.map +0 -1
- package/dist/tools/dom.d.ts +0 -2
- package/dist/tools/dom.js +0 -309
- package/dist/tools/dom.js.map +0 -1
- package/dist/tools/execution.d.ts +0 -29
- package/dist/tools/execution.js +0 -89
- package/dist/tools/execution.js.map +0 -1
- package/dist/tools/forms.d.ts +0 -8
- package/dist/tools/forms.js +0 -256
- package/dist/tools/forms.js.map +0 -1
- package/dist/tools/inspect.d.ts +0 -2
- package/dist/tools/inspect.js +0 -178
- package/dist/tools/inspect.js.map +0 -1
- package/dist/tools/nav.d.ts +0 -2
- package/dist/tools/nav.js +0 -136
- package/dist/tools/nav.js.map +0 -1
- package/dist/tools/network.d.ts +0 -2
- package/dist/tools/network.js +0 -137
- package/dist/tools/network.js.map +0 -1
- package/dist/tools/session.d.ts +0 -2
- package/dist/tools/session.js +0 -76
- package/dist/tools/session.js.map +0 -1
- package/dist/tools/source.d.ts +0 -2
- package/dist/tools/source.js +0 -63
- package/dist/tools/source.js.map +0 -1
- package/dist/tools/storage.d.ts +0 -2
- package/dist/tools/storage.js +0 -296
- package/dist/tools/storage.js.map +0 -1
- package/dist/util/browser-resolve.d.ts +0 -19
- package/dist/util/browser-resolve.js +0 -263
- package/dist/util/browser-resolve.js.map +0 -1
- package/dist/util/errors.d.ts +0 -7
- package/dist/util/errors.js +0 -12
- package/dist/util/errors.js.map +0 -1
- package/dist/util/format.d.ts +0 -20
- package/dist/util/format.js +0 -65
- package/dist/util/format.js.map +0 -1
- package/dist/util/log.d.ts +0 -6
- package/dist/util/log.js +0 -34
- package/dist/util/log.js.map +0 -1
- package/docs/chromium-sandboxing.md +0 -197
- package/docs/known-chromium-gaps.md +0 -138
- package/docs/launchd-service.md +0 -217
- package/docs/local-l3-e2e-setup.md +0 -199
- package/docs/systemd-service.md +0 -233
package/README.md
CHANGED
|
@@ -1,303 +1,28 @@
|
|
|
1
|
-
# cdp-mcp
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
### Runtime install from npm
|
|
30
|
-
|
|
31
|
-
Requires Node.js 20+ and a local Chrome/Chromium browser.
|
|
32
|
-
|
|
33
|
-
```sh
|
|
34
|
-
npm install -g cdp-mcp
|
|
35
|
-
cdp-mcp # stdio MCP transport
|
|
36
|
-
cdp-mcp --port 9719 # SSE MCP transport on 127.0.0.1:9719
|
|
37
|
-
cdp-mcp --host 0.0.0.0 --port 9719 --allow-remote
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
The npm package ships prebuilt `dist/`, so there is no build step for runtime
|
|
41
|
-
use. If `launch_chrome` cannot find Chrome/Chromium automatically, set
|
|
42
|
-
`CHROME_PATH` to the browser binary.
|
|
43
|
-
|
|
44
|
-
For MCP clients that support SSE, you can run `cdp-mcp` as a persistent local
|
|
45
|
-
service:
|
|
46
|
-
|
|
47
|
-
- [macOS launchd user service](docs/launchd-service.md)
|
|
48
|
-
- [Linux systemd user service](docs/systemd-service.md)
|
|
49
|
-
|
|
50
|
-
Persistent service mode keeps the `cdp-mcp` process and current browser/CDP
|
|
51
|
-
session alive across MCP client restarts or reconnects. It does **not** persist
|
|
52
|
-
state across service-process restarts. SSE mode is single-client today; if a
|
|
53
|
-
new client should start fresh, call `close_session` first.
|
|
54
|
-
|
|
55
|
-
### Build from source
|
|
56
|
-
|
|
57
|
-
```sh
|
|
58
|
-
npm install
|
|
59
|
-
npm run build
|
|
60
|
-
node dist/index.js # stdio MCP transport (default — this is what Claude Code launches)
|
|
61
|
-
node dist/index.js --port 9719 # SSE MCP transport on 127.0.0.1:9719
|
|
62
|
-
node dist/index.js --host 0.0.0.0 --port 9719 --allow-remote
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
SSE mode caveats:
|
|
66
|
-
|
|
67
|
-
- **Single-client only.** Every `/sse` connection gets its own `McpServer`,
|
|
68
|
-
but every tool funnels through one process-global `sessionState` — two
|
|
69
|
-
concurrent clients race on the same browser (shared pause state,
|
|
70
|
-
breakpoints, console/network buffers; `launch_chrome` from client B
|
|
71
|
-
tears down client A's session).
|
|
72
|
-
- **Non-loopback bind requires opt-in.** `--allow-remote` (or
|
|
73
|
-
`CDP_MCP_ALLOW_REMOTE=1`) is required to bind to anything other than
|
|
74
|
-
loopback. MCP tools include `evaluate` (in-page code exec), a
|
|
75
|
-
`screenshot path=` filesystem write, `export_storage_state` (writes full
|
|
76
|
-
cookie values — including HttpOnly auth secrets — to a server-side file) and
|
|
77
|
-
`load_storage_state` (reads an arbitrary server-side file); the gate makes
|
|
78
|
-
remote exposure a deliberate operator decision rather than a default.
|
|
79
|
-
- **Host / Origin headers are validated on loopback binds** to block
|
|
80
|
-
DNS-rebinding against `127.0.0.1` / `localhost` / `[::1]`. On
|
|
81
|
-
non-loopback binds the operator has already accepted exposure via
|
|
82
|
-
`--allow-remote`, and the server can't statically enumerate every
|
|
83
|
-
hostname/IP a LAN/VPN/DNS client might reach it by — those checks
|
|
84
|
-
are skipped. If you need per-`Host` policy on a LAN/WAN deployment,
|
|
85
|
-
front the server with a reverse proxy that enforces it.
|
|
86
|
-
|
|
87
|
-
Smoke test (no browser needed — verifies the protocol surface):
|
|
88
|
-
|
|
89
|
-
```sh
|
|
90
|
-
npm run smoke
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
Unit + L2 contract tests (~640ms, no browser, no LLM):
|
|
94
|
-
|
|
95
|
-
```sh
|
|
96
|
-
npm test
|
|
97
|
-
```
|
|
98
|
-
|
|
99
|
-
The `test/` tree is the L2 contract layer (every tool exercised against a fake
|
|
100
|
-
CDP — see `test/fake-cdp.ts`); the inline `src/**/*.test.ts` files are L1
|
|
101
|
-
pure-data tests; `evals/**/*.test.ts` cover the L4 harness's
|
|
102
|
-
grader/trace/oracle units. See `docs/test-eval-plan.md` for the full pyramid.
|
|
103
|
-
|
|
104
|
-
### L3 — real-browser end-to-end
|
|
105
|
-
|
|
106
|
-
```sh
|
|
107
|
-
npm run test:e2e
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
Drives the 48 MCP tools against a real headless Chromium attached to a
|
|
111
|
-
built copy of `examples/sample-app/`. Eleven specs cover lifecycle, breakpoints,
|
|
112
|
-
stepping, exceptions, console, network, workers, screenshot, DOM
|
|
113
|
-
interaction, form driving, and storage portability. Sequential (one Chrome shared across specs, isolated by a
|
|
114
|
-
shared `afterEach(close_session)`). Run time is a few seconds on a warm
|
|
115
|
-
machine.
|
|
116
|
-
|
|
117
|
-
**Browser selection (`CDP_TEST_BROWSER` env, default `chromium`)**:
|
|
118
|
-
|
|
119
|
-
| Linux x86_64 | Linux ARM64 (primary local) | macOS | Windows |
|
|
120
|
-
|---|---|---|---|
|
|
121
|
-
| `chromium`: Playwright's bundled binary, system chromium, or apt | `chromium`: Playwright's bundled binary or apt (`/snap/bin/chromium` honored with snap-confinement userDataDir workaround) | `chromium`: Homebrew / Playwright bundled | `chromium`: Playwright bundled (set `CDP_TEST_BROWSER_PATH`) |
|
|
122
|
-
| `chrome`: chrome-launcher auto-detect | **not supported** — fail-fast | `chrome`: chrome-launcher auto-detect | `chrome`: chrome-launcher auto-detect |
|
|
123
|
-
|
|
124
|
-
**Local-Windows status**: at the time L3 landed, `chrome-launcher` 1.2.1 fails
|
|
125
|
-
to bind to its own picked port on Windows 11 (ECONNREFUSED inside chrome-
|
|
126
|
-
launcher's startup poll) regardless of headless mode, Chrome stable vs
|
|
127
|
-
Playwright Chromium, or explicit ports. The same code path works on Linux
|
|
128
|
-
where CI runs. If you need to test L3 changes locally on Windows, run them
|
|
129
|
-
under WSL2 (Ubuntu) or push and let CI validate. The unit + L2 tests work
|
|
130
|
-
fine on Windows.
|
|
131
|
-
|
|
132
|
-
Setting an explicit binary path (for example, after running
|
|
133
|
-
`npx playwright install chromium` locally on Linux) lets the resolver skip
|
|
134
|
-
detection and use the bundled binary:
|
|
135
|
-
|
|
136
|
-
```sh
|
|
137
|
-
export CDP_TEST_BROWSER_PATH="$HOME/.cache/ms-playwright/chromium-1223/chrome-linux/chrome"
|
|
138
|
-
npm run test:e2e
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Any spec failing on Chromium-only but passing on Chrome stable should land
|
|
142
|
-
with a `// @chromium-skip — <gap-id>` comment AND a row in
|
|
143
|
-
`docs/known-chromium-gaps.md` — `npm run lint:chromium-skips` (and the
|
|
144
|
-
pretest hook) enforces this.
|
|
145
|
-
|
|
146
|
-
`launch_chrome` defaults to `--no-sandbox` for Ubuntu/Playwright-Chromium
|
|
147
|
-
compatibility. See [`docs/chromium-sandboxing.md`](docs/chromium-sandboxing.md)
|
|
148
|
-
before changing that default or relying on `sandbox: true`, AppArmor, snap
|
|
149
|
-
confinement, or Bubblewrap. For the step-by-step setup that gets local
|
|
150
|
-
`npm run test:e2e` passing with the sandbox **on** (install Playwright Chromium
|
|
151
|
-
+ attach the AppArmor profile), see
|
|
152
|
-
[`docs/local-l3-e2e-setup.md`](docs/local-l3-e2e-setup.md).
|
|
153
|
-
|
|
154
|
-
### L4 — LLM agent evals
|
|
155
|
-
|
|
156
|
-
```sh
|
|
157
|
-
export ANTHROPIC_API_KEY=...
|
|
158
|
-
npm run eval:quick # 1 scenario × 1 trial (~$0.50–2 at default Opus-4.8-medium; ~$0.05 with EVAL_MODEL_OVERRIDE=claude-sonnet-4-6)
|
|
159
|
-
npm run eval # all scenarios × 3 trials (~$4 full pass — first observed on Opus-4.7-medium, the prior default; 4.8 shares its rate card)
|
|
160
|
-
npm run eval -- --scenarios=compute-step --trials=1
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Use `npm run eval` (or `npm run eval:quick`) — NOT `npx tsx evals/cli.ts` directly. The npm script triggers the `preeval` lifecycle hook which rebuilds `dist/index.js` (the MCP subprocess); calling tsx directly bypasses the hook and a fresh clone fails with `Cannot find module '.../dist/index.js'`. If you must invoke tsx directly, run `npm run build` first.
|
|
164
|
-
|
|
165
|
-
Drives the cdp-mcp tool surface through an LLM agent via the
|
|
166
|
-
`VendorAdapter` seam (`evals/harness/vendor.ts`); the Anthropic adapter
|
|
167
|
-
backed by `@anthropic-ai/sdk` is the default; OpenAI, Vertex, DeepSeek,
|
|
168
|
-
and Moonshot/Kimi are also shipped production adapters (plus an LM Studio
|
|
169
|
-
reference adapter for local models), each selected via `EVAL_PROVIDER`.
|
|
170
|
-
Each trial spawns a fresh `dist/index.js` MCP subprocess + a
|
|
171
|
-
static server for the scenario's sample-app variant; the tool-use loop
|
|
172
|
-
drives the page, sets source-level breakpoints, inspects pauses, and
|
|
173
|
-
produces a natural-language final answer. NDJSON traces land under
|
|
174
|
-
`evals/runs/<run-id>/` (gitignored). A programmatic oracle per scenario
|
|
175
|
-
(no LLM judge) emits a dual-axis verdict — **mechanic** (did the agent
|
|
176
|
-
exercise the debugger workflow under test) + **correctness** (did the
|
|
177
|
-
final answer name the bug) — plus efficiency ratio and recovery count.
|
|
178
|
-
|
|
179
|
-
**Default model**: `claude-opus-4-8` with adaptive thinking at
|
|
180
|
-
`effort=medium` (set in `evals/harness/model.ts`). Adaptive-style models
|
|
181
|
-
(Opus 4.7+) default to medium-effort thinking when no env override is
|
|
182
|
-
set; budget-style models (Sonnet 4.6, selectable via
|
|
183
|
-
`EVAL_MODEL_OVERRIDE`) keep extended thinking **off** by default for the
|
|
184
|
-
cheap-baseline path. Override via env:
|
|
185
|
-
|
|
186
|
-
- `EVAL_MODEL_OVERRIDE=claude-sonnet-4-6` — switch to the budget-style
|
|
187
|
-
Sonnet baseline (no thinking by default; ~$5–10/full run).
|
|
188
|
-
- `EVAL_REASONING_LEVEL=none|low|medium|high|xhigh|max` — pick a tier
|
|
189
|
-
(or explicit `none` to disable on adaptive models). On budget-style
|
|
190
|
-
models each tier maps to a default `budget_tokens` in
|
|
191
|
-
`TIER_BUDGET_TOKENS` (high=16K). On adaptive models the tier maps
|
|
192
|
-
directly to Anthropic's `effort` parameter.
|
|
193
|
-
- `EVAL_REASONING_BUDGET=N` — override the budget on budget-style
|
|
194
|
-
models. Used alone the level is tagged `custom`; used alongside
|
|
195
|
-
`EVAL_REASONING_LEVEL` it overrides that tier's default.
|
|
196
|
-
|
|
197
|
-
Thinking-on runs are non-deterministic (Anthropic requires
|
|
198
|
-
`temperature=1` with `thinking`), so use `--trials >= 3` to characterize
|
|
199
|
-
variance. Cost-cap: `$100` per `npm run eval` invocation (override via
|
|
200
|
-
`EVAL_BUDGET_USD` env). Rotation across the Anthropic family + GPT-5.5
|
|
201
|
-
is a follow-up — see the proposal at
|
|
202
|
-
[`docs/eval-model-rotation-proposal.md`](docs/eval-model-rotation-proposal.md).
|
|
203
|
-
|
|
204
|
-
Caching: the system prompt + tool list are tagged `cache_control:
|
|
205
|
-
ephemeral`. The system block (~280 tokens) is below Anthropic's
|
|
206
|
-
~1024-token cache-breakpoint minimum, so only the ~5K-token tools array
|
|
207
|
-
actually caches across trials — that's enough to dominate the input
|
|
208
|
-
cost across trial 2+. Verify post-run via the `cacheTokens` field on
|
|
209
|
-
each `t:"usage"` trace entry (the Anthropic adapter populates
|
|
210
|
-
`cacheTokens.cacheReadInputTokens` and `cacheTokens.cacheCreationInputTokens`
|
|
211
|
-
verbatim from the SDK's `cache_read_input_tokens` / `cache_creation_input_tokens`).
|
|
212
|
-
|
|
213
|
-
Non-Anthropic backends ship behind the same seam, each selected via
|
|
214
|
-
`EVAL_PROVIDER`: OpenAI / GPT-5.5 (#50/#58) — reasoning-off trials route to
|
|
215
|
-
`/v1/chat/completions` (#50), reasoning-on trials to `/v1/responses` (#58),
|
|
216
|
-
the only OpenAI surface that supports tools × reasoning_effort on GPT-5.5;
|
|
217
|
-
Vertex / Gemini (#51); and DeepSeek + Moonshot/Kimi (GH #8), remote
|
|
218
|
-
OpenAI-compatible `/v1` vendors. An LM Studio investigation artifact is
|
|
219
|
-
wired behind the seam for local models (issue #45). See
|
|
220
|
-
[evals/README.md](evals/README.md) for full `EVAL_PROVIDER` / `EVAL_OPENAI_*`
|
|
221
|
-
/ `EVAL_VERTEX_*` / `EVAL_DEEPSEEK_*` / `EVAL_MOONSHOT_*` / `EVAL_LM_STUDIO_*`
|
|
222
|
-
details.
|
|
223
|
-
|
|
224
|
-
Currently registered scenarios (14) — 8 **debugger** scenarios
|
|
225
|
-
(`compute-step`, `adversarial-out-of-order`, `network-bug`, `console-error`,
|
|
226
|
-
`event-binding`, `deep-source-map`, `worker-bug`, `conditional-bp`) plus 6
|
|
227
|
-
**driving + session-portability** scenarios from issue #12 (`form-drive`,
|
|
228
|
-
`clearing-fill`, `idempotent-toggle`, `robust-locator`, `session-resume`,
|
|
229
|
-
`cookie-redaction`). `compute-step` is the canonical `npm run eval:quick`
|
|
230
|
-
target; some scenarios run against the stock `examples/sample-app/`, others
|
|
231
|
-
against per-scenario forks under `evals/sample-app-variants/<name>/` built via
|
|
232
|
-
`npm run sample:build` (`scripts/build-variants.mjs`). See
|
|
233
|
-
[evals/README.md](evals/README.md) for the full scenario table.
|
|
234
|
-
|
|
235
|
-
## Wire into Claude Code
|
|
236
|
-
|
|
237
|
-
```sh
|
|
238
|
-
claude mcp add cdp-mcp node /absolute/path/to/dist/index.js
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
Or via `~/.claude.json`:
|
|
242
|
-
|
|
243
|
-
```json
|
|
244
|
-
{
|
|
245
|
-
"mcpServers": {
|
|
246
|
-
"cdp-mcp": { "command": "node", "args": ["/abs/path/dist/index.js"] }
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
```
|
|
250
|
-
|
|
251
|
-
## End-to-end smoke (with a browser)
|
|
252
|
-
|
|
253
|
-
1. Install the sample app's deps and start it:
|
|
254
|
-
```sh
|
|
255
|
-
cd examples/sample-app
|
|
256
|
-
npm install
|
|
257
|
-
npm run dev # listens on :5173
|
|
258
|
-
```
|
|
259
|
-
2. In a Claude Code session with `cdp-mcp` enabled, ask:
|
|
260
|
-
> Open localhost:5173 in a non-headless browser. Set a breakpoint at src/handlers.ts:7. Click #go. When it pauses, tell me what `step` is — and why the counter increments wrong.
|
|
261
|
-
3. The agent should chain: `launch_chrome` → `set_breakpoint` → `click` → `wait_for_pause` → `get_scope`/`evaluate` → `resume`, and conclude that `computeStep()` returns `2` instead of `1`.
|
|
262
|
-
|
|
263
|
-
## Tool conventions for agents
|
|
264
|
-
|
|
265
|
-
- **File coords are TS, 1-based lines, 0-based columns** unless the tool name ends in `_js` or takes a `script_id`.
|
|
266
|
-
- **Pause-only tools** (`get_call_stack`, `get_scope`, `evaluate` with `frame_index`): return `error: "not_paused"` if called outside a pause.
|
|
267
|
-
- **Buffered tools** (`get_console_logs`, `get_network_requests`): return a `cursor` (max `seq` seen). Pass it back as `since` to paginate.
|
|
268
|
-
- **Errors** come back as `isError: true` with a structured `{ error, message }` JSON payload.
|
|
269
|
-
- **Compact returns**: previews trimmed to ~200 chars, lists capped at sensible defaults — bodies lazy-loaded via dedicated tools.
|
|
270
|
-
|
|
271
|
-
## Programmatic contract (`cdp-mcp/contract`)
|
|
272
|
-
|
|
273
|
-
The structured `LocatorSpec` that `locate`, `wait_for`, and the form-driving tools
|
|
274
|
-
accept is published as a side-effect-free subpath export, so external tooling can
|
|
275
|
-
*produce and validate* specs without duplicating the shape or pulling in the CLI:
|
|
276
|
-
|
|
277
|
-
```ts
|
|
278
|
-
import { locatorSchema, parseLocator, serializeLocator } from "cdp-mcp/contract";
|
|
279
|
-
import type { LocatorSpec } from "cdp-mcp/contract";
|
|
280
|
-
|
|
281
|
-
const spec = parseLocator({ by: "role", role: "button", name: "Submit" });
|
|
282
|
-
locatorSchema.parse(spec); // throws on an invalid shape
|
|
283
|
-
serializeLocator(spec); // stable, normalized JSON
|
|
284
|
-
```
|
|
285
|
-
|
|
286
|
-
Exports: `LocatorSpec` (type), `LocatorBy`, `locatorSchema` / `locatorShape` /
|
|
287
|
-
`locatorBySchema` (Zod), and `normalizeLocator` / `parseLocator` / `serializeLocator`
|
|
288
|
-
/ `LocatorError`. This module imports only `zod`. The subpath is **ESM-only** (the
|
|
289
|
-
`exports` map defines `import`, not `require`) — consume it from an ESM module or a
|
|
290
|
-
bundler.
|
|
291
|
-
|
|
292
|
-
## Prior art
|
|
293
|
-
|
|
294
|
-
If `cdp-mcp` doesn't fit your workflow, look at:
|
|
295
|
-
- [`InDate/cdp-tools-mcp`](https://github.com/InDate/cdp-tools-mcp)
|
|
296
|
-
- [`ScriptedAlchemy/devtools-debugger-mcp`](https://github.com/ScriptedAlchemy/devtools-debugger-mcp) (Node-focused)
|
|
297
|
-
- [`ChromeDevTools/chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) (automation + console, no breakpoints)
|
|
298
|
-
|
|
299
|
-
## Out of scope for v1
|
|
300
|
-
|
|
301
|
-
Firefox / Safari, Node.js debugging, `Storage.*`, `Tracing.*`, `HeapProfiler.*`, concurrent multi-page debugging.
|
|
302
|
-
|
|
303
|
-
See [design notes](docs/design-notes.md) — original plan snapshot + a section on what reviewer iteration discovered.
|
|
1
|
+
# cdp-mcp → lynceus
|
|
2
|
+
|
|
3
|
+
**cdp-mcp has been renamed to [lynceus](https://www.npmjs.com/package/lynceus).**
|
|
4
|
+
|
|
5
|
+
This package is a thin compatibility wrapper: it depends on lynceus and boots the
|
|
6
|
+
lynceus MCP server, so existing `npx cdp-mcp` / `cdp-mcp` setups keep working
|
|
7
|
+
unchanged. It receives no independent fixes — new features and bug fixes land in
|
|
8
|
+
lynceus only, and the wrapper pins the lynceus 0.4.x line: when a newer lynceus
|
|
9
|
+
line ships, the wrapper may lag until republished. Install lynceus directly to
|
|
10
|
+
always get the latest.
|
|
11
|
+
|
|
12
|
+
## Migration (nothing changes except the name)
|
|
13
|
+
|
|
14
|
+
- Install: `npm install -g lynceus` (or `npx lynceus`)
|
|
15
|
+
- MCP config: use `lynceus` as the command, e.g. `claude mcp add lynceus lynceus`
|
|
16
|
+
- Environment variables: nothing to change — the old `CDP_MCP_*` names are still
|
|
17
|
+
honored as aliases of `LYNCEUS_*`
|
|
18
|
+
- Imports: `import { locatorSchema } from "cdp-mcp/contract"` keeps compiling via
|
|
19
|
+
this wrapper; new code should import from `"lynceus/contract"`
|
|
20
|
+
- Repository: <https://github.com/lcjanke2020/lynceus> (GitHub redirects the old
|
|
21
|
+
repo name)
|
|
22
|
+
|
|
23
|
+
## What lynceus is
|
|
24
|
+
|
|
25
|
+
A TypeScript-aware runtime debugger that AI agents drive over MCP: one server that
|
|
26
|
+
debugs both the browser (Chrome DevTools Protocol) and Node.js (V8 Inspector), with
|
|
27
|
+
source-level breakpoints, stepping, frame-aware evaluation, and scope/object
|
|
28
|
+
inspection in TS coordinates. See the [lynceus README](https://github.com/lcjanke2020/lynceus#readme).
|
package/bin.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// cdp-mcp is now lynceus — this shim boots the lynceus server in-process.
|
|
3
|
+
// The lynceus entry only starts the server when import.meta.url matches
|
|
4
|
+
// process.argv[1] (its run-as-main guard, src/index.ts isRunAsMain), so point
|
|
5
|
+
// argv[1] at the realpath-resolved entry and import it via the same URL form
|
|
6
|
+
// the guard reconstructs. require()-based resolution can't be used here:
|
|
7
|
+
// lynceus's exports map is ESM-only (no "require" condition). Sync
|
|
8
|
+
// import.meta.resolve needs Node >= 20.6 — engines pins that floor.
|
|
9
|
+
import { realpathSync } from "node:fs";
|
|
10
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
11
|
+
|
|
12
|
+
// engines only warns at install time; fail loud on Node 20.0–20.5, where
|
|
13
|
+
// sync import.meta.resolve doesn't exist and the audience is stale installs.
|
|
14
|
+
if (typeof import.meta.resolve !== "function") {
|
|
15
|
+
process.stderr.write(
|
|
16
|
+
"cdp-mcp (now lynceus) requires Node >= 20.6 — upgrade Node, or install the successor directly: npm install -g lynceus\n",
|
|
17
|
+
);
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const entry = realpathSync(fileURLToPath(import.meta.resolve("lynceus")));
|
|
22
|
+
process.argv[1] = entry;
|
|
23
|
+
await import(pathToFileURL(entry).href);
|
package/contract.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "lynceus/contract";
|
package/contract.js
ADDED
package/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "lynceus";
|
package/index.js
ADDED
package/package.json
CHANGED
|
@@ -1,90 +1,48 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cdp-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": "Leonard Janke",
|
|
7
|
-
"homepage": "https://github.com/lcjanke2020/cdp-mcp#readme",
|
|
8
|
-
"repository": {
|
|
9
|
-
"type": "git",
|
|
10
|
-
"url": "git+https://github.com/lcjanke2020/cdp-mcp.git"
|
|
11
|
-
},
|
|
12
|
-
"bugs": {
|
|
13
|
-
"url": "https://github.com/lcjanke2020/cdp-mcp/issues"
|
|
14
|
-
},
|
|
15
|
-
"keywords": [
|
|
16
|
-
"mcp",
|
|
17
|
-
"model-context-protocol",
|
|
18
|
-
"chrome-devtools-protocol",
|
|
19
|
-
"cdp",
|
|
20
|
-
"debugger",
|
|
21
|
-
"devtools",
|
|
22
|
-
"ai-agents",
|
|
23
|
-
"typescript",
|
|
24
|
-
"source-maps"
|
|
25
|
-
],
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Renamed: cdp-mcp is now lynceus. Compatibility wrapper that launches the lynceus MCP debugging server.",
|
|
26
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
27
7
|
"bin": {
|
|
28
|
-
"cdp-mcp": "
|
|
8
|
+
"cdp-mcp": "bin.js"
|
|
29
9
|
},
|
|
30
|
-
"main": "dist/index.js",
|
|
31
|
-
"types": "dist/index.d.ts",
|
|
32
10
|
"exports": {
|
|
33
11
|
".": {
|
|
34
|
-
"types": "./
|
|
35
|
-
"import": "./
|
|
12
|
+
"types": "./index.d.ts",
|
|
13
|
+
"import": "./index.js"
|
|
36
14
|
},
|
|
37
15
|
"./contract": {
|
|
38
|
-
"types": "./
|
|
39
|
-
"import": "./
|
|
16
|
+
"types": "./contract.d.ts",
|
|
17
|
+
"import": "./contract.js"
|
|
40
18
|
}
|
|
41
19
|
},
|
|
42
20
|
"files": [
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"docs/known-chromium-gaps.md"
|
|
21
|
+
"bin.js",
|
|
22
|
+
"index.js",
|
|
23
|
+
"index.d.ts",
|
|
24
|
+
"contract.js",
|
|
25
|
+
"contract.d.ts"
|
|
49
26
|
],
|
|
50
|
-
"scripts": {
|
|
51
|
-
"build": "tsc -p tsconfig.json",
|
|
52
|
-
"dev": "tsx src/index.ts",
|
|
53
|
-
"test": "vitest run",
|
|
54
|
-
"test:watch": "vitest",
|
|
55
|
-
"pretest:e2e": "node scripts/check-chromium-skips.mjs && npm run sample:build",
|
|
56
|
-
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
57
|
-
"sample:build": "npm ci --prefix examples/sample-app && npm run --prefix examples/sample-app build && npm run variants:build",
|
|
58
|
-
"variants:build": "node scripts/build-variants.mjs",
|
|
59
|
-
"lint:chromium-skips": "node scripts/check-chromium-skips.mjs",
|
|
60
|
-
"smoke": "node scripts/smoke.mjs",
|
|
61
|
-
"typecheck": "tsc --noEmit && tsc --noEmit -p tsconfig.evals.json",
|
|
62
|
-
"preeval": "npm run build",
|
|
63
|
-
"preeval:quick": "npm run build",
|
|
64
|
-
"eval": "tsx evals/cli.ts",
|
|
65
|
-
"eval:quick": "tsx evals/cli.ts --scenarios=compute-step --trials=1",
|
|
66
|
-
"clean": "rimraf dist",
|
|
67
|
-
"prepack": "npm run build"
|
|
68
|
-
},
|
|
69
27
|
"dependencies": {
|
|
70
|
-
"
|
|
71
|
-
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
72
|
-
"chrome-launcher": "^1.2.1",
|
|
73
|
-
"chrome-remote-interface": "^0.34.0",
|
|
74
|
-
"devtools-protocol": "^0.0.1628107",
|
|
75
|
-
"zod": "^3.23.8"
|
|
76
|
-
},
|
|
77
|
-
"devDependencies": {
|
|
78
|
-
"@anthropic-ai/sdk": "^0.30.1",
|
|
79
|
-
"@google/genai": "^2.4.0",
|
|
80
|
-
"@types/chrome-remote-interface": "^0.33.0",
|
|
81
|
-
"@types/node": "^22.10.5",
|
|
82
|
-
"rimraf": "^6.0.1",
|
|
83
|
-
"tsx": "^4.19.2",
|
|
84
|
-
"typescript": "^5.7.2",
|
|
85
|
-
"vitest": "^4.1.8"
|
|
28
|
+
"lynceus": "^0.4.0"
|
|
86
29
|
},
|
|
87
30
|
"engines": {
|
|
88
|
-
"node": ">=20"
|
|
89
|
-
}
|
|
31
|
+
"node": ">=20.6"
|
|
32
|
+
},
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/lcjanke2020/lynceus.git",
|
|
36
|
+
"directory": "wrapper/cdp-mcp"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/lcjanke2020/lynceus#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/lcjanke2020/lynceus/issues"
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"mcp",
|
|
44
|
+
"debugger",
|
|
45
|
+
"chrome-devtools-protocol",
|
|
46
|
+
"lynceus"
|
|
47
|
+
]
|
|
90
48
|
}
|
package/dist/contract.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public package contract, published under the `cdp-mcp/contract` subpath export.
|
|
3
|
-
*
|
|
4
|
-
* Keep this a thin, side-effect-free barrel: it must only re-export from modules
|
|
5
|
-
* (like `./locator.js`) whose import graph never reaches the CLI/server entry
|
|
6
|
-
* (`./index.js`, `./server.js`, `./session/*`). That guarantee is what lets a
|
|
7
|
-
* downstream consumer `import { locatorSchema } from "cdp-mcp/contract"` without
|
|
8
|
-
* dragging in the executable's transport/shebang side effects.
|
|
9
|
-
*/
|
|
10
|
-
export { LocatorError, locatorBySchema, locatorShape, locatorSchema, normalizeLocator, parseLocator, serializeLocator, } from "./locator.js";
|
|
11
|
-
export type { LocatorBy, LocatorSpec } from "./locator.js";
|
package/dist/contract.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Public package contract, published under the `cdp-mcp/contract` subpath export.
|
|
3
|
-
*
|
|
4
|
-
* Keep this a thin, side-effect-free barrel: it must only re-export from modules
|
|
5
|
-
* (like `./locator.js`) whose import graph never reaches the CLI/server entry
|
|
6
|
-
* (`./index.js`, `./server.js`, `./session/*`). That guarantee is what lets a
|
|
7
|
-
* downstream consumer `import { locatorSchema } from "cdp-mcp/contract"` without
|
|
8
|
-
* dragging in the executable's transport/shebang side effects.
|
|
9
|
-
*/
|
|
10
|
-
export { LocatorError, locatorBySchema, locatorShape, locatorSchema, normalizeLocator, parseLocator, serializeLocator, } from "./locator.js";
|
|
11
|
-
//# sourceMappingURL=contract.js.map
|
package/dist/contract.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EACL,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
|
package/dist/index.d.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { type IncomingMessage, type ServerResponse } from "node:http";
|
|
3
|
-
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
4
|
-
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
-
export interface SseClient {
|
|
6
|
-
server: McpServer;
|
|
7
|
-
transport: SSEServerTransport;
|
|
8
|
-
}
|
|
9
|
-
export declare function handleSseRequest({ req, res, clients, host, port, validateHostOrigin, allowedHosts, allowedOrigins, }: {
|
|
10
|
-
req: IncomingMessage;
|
|
11
|
-
res: ServerResponse;
|
|
12
|
-
clients: Map<string, SseClient>;
|
|
13
|
-
host: string;
|
|
14
|
-
port: number;
|
|
15
|
-
validateHostOrigin: boolean;
|
|
16
|
-
allowedHosts: Set<string>;
|
|
17
|
-
allowedOrigins: Set<string>;
|
|
18
|
-
}): Promise<void>;
|