cdp-mcp 0.1.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.
Files changed (49) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +240 -0
  3. package/dist/index.js +345 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/server.js +27 -0
  6. package/dist/server.js.map +1 -0
  7. package/dist/session/browser.js +394 -0
  8. package/dist/session/browser.js.map +1 -0
  9. package/dist/session/buffers.js +43 -0
  10. package/dist/session/buffers.js.map +1 -0
  11. package/dist/session/pause.js +99 -0
  12. package/dist/session/pause.js.map +1 -0
  13. package/dist/session/state.js +93 -0
  14. package/dist/session/state.js.map +1 -0
  15. package/dist/sourcemap/loader.js +138 -0
  16. package/dist/sourcemap/loader.js.map +1 -0
  17. package/dist/sourcemap/normalize.js +59 -0
  18. package/dist/sourcemap/normalize.js.map +1 -0
  19. package/dist/sourcemap/store.js +185 -0
  20. package/dist/sourcemap/store.js.map +1 -0
  21. package/dist/tools/_register.js +30 -0
  22. package/dist/tools/_register.js.map +1 -0
  23. package/dist/tools/breakpoints.js +164 -0
  24. package/dist/tools/breakpoints.js.map +1 -0
  25. package/dist/tools/console.js +48 -0
  26. package/dist/tools/console.js.map +1 -0
  27. package/dist/tools/dom.js +527 -0
  28. package/dist/tools/dom.js.map +1 -0
  29. package/dist/tools/execution.js +89 -0
  30. package/dist/tools/execution.js.map +1 -0
  31. package/dist/tools/inspect.js +178 -0
  32. package/dist/tools/inspect.js.map +1 -0
  33. package/dist/tools/nav.js +136 -0
  34. package/dist/tools/nav.js.map +1 -0
  35. package/dist/tools/network.js +137 -0
  36. package/dist/tools/network.js.map +1 -0
  37. package/dist/tools/session.js +76 -0
  38. package/dist/tools/session.js.map +1 -0
  39. package/dist/tools/source.js +63 -0
  40. package/dist/tools/source.js.map +1 -0
  41. package/dist/util/browser-resolve.js +263 -0
  42. package/dist/util/browser-resolve.js.map +1 -0
  43. package/dist/util/errors.js +12 -0
  44. package/dist/util/errors.js.map +1 -0
  45. package/dist/util/format.js +65 -0
  46. package/dist/util/format.js.map +1 -0
  47. package/dist/util/log.js +34 -0
  48. package/dist/util/log.js.map +1 -0
  49. package/package.json +74 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Leonard Janke
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,240 @@
1
+ # cdp-mcp
2
+
3
+ A Model Context Protocol (MCP) server that exposes the Chrome DevTools Protocol (CDP) to AI agents as a **TypeScript-aware frontend debugger**.
4
+
5
+ Designed for agents running in CLIs (Claude Code, GitHub Copilot CLI) that have local source + source-map access. Coordinates flow in TS terms; the server translates to JS for CDP under the hood.
6
+
7
+ **Status:** alpha (v0.1.0). **License:** [MIT](./LICENSE).
8
+
9
+ ## What it gives an agent
10
+
11
+ Across 39 tools:
12
+
13
+ - **Breakpoints in TS source** — `set_breakpoint(file="src/foo.ts", line=42, condition?, log_message?)`. The server matches source maps and binds in every script that maps back to that file.
14
+ - **Stepping** — `step_over`, `step_into`, `step_out`, `resume`, `pause`, plus the authoritative sync point `wait_for_pause`.
15
+ - **Live inspection at a paused frame** — `get_call_stack`, `get_scope`, `evaluate` (frame-aware), `get_object_properties`. All call-stack frames are TS-mapped.
16
+ - **Buffered console + network** — pull-based, paginated by monotonic `seq`. Bodies are lazy-loaded via `get_request_body` / `get_response_body`.
17
+ - **Light DOM interaction** — `query_selector`, `click`, `type_text`, `press_key`, `screenshot` so the agent can drive a flow to a breakpoint.
18
+ - **Structured DOM querying** — Playwright-inspired `locate` (LocatorSpec: CSS, text, role, test-id, label, placeholder, name), `wait_for` (poll until DOM state), `get_form_state` (read named form fields).
19
+ - **Source-map diagnostics** — `list_scripts`, `resolve_source_position`, `get_script_source`.
20
+
21
+ Auto-attaches to iframes and workers via `Target.setAutoAttach({ flatten: true })`.
22
+
23
+ ## Install / build
24
+
25
+ ```sh
26
+ npm install
27
+ npm run build
28
+ node dist/index.js # stdio MCP transport (default — this is what Claude Code launches)
29
+ node dist/index.js --port 9719 # SSE MCP transport on 127.0.0.1:9719
30
+ node dist/index.js --host 0.0.0.0 --port 9719 --allow-remote
31
+ ```
32
+
33
+ SSE mode caveats:
34
+
35
+ - **Single-client only.** Every `/sse` connection gets its own `McpServer`,
36
+ but every tool funnels through one process-global `sessionState` — two
37
+ concurrent clients race on the same browser (shared pause state,
38
+ breakpoints, console/network buffers; `launch_chrome` from client B
39
+ tears down client A's session).
40
+ - **Non-loopback bind requires opt-in.** `--allow-remote` (or
41
+ `CDP_MCP_ALLOW_REMOTE=1`) is required to bind to anything other than
42
+ loopback. MCP tools include `evaluate` (in-page code exec) and a
43
+ `screenshot path=` filesystem write; the gate makes remote exposure
44
+ a deliberate operator decision rather than a default.
45
+ - **Host / Origin headers are validated on loopback binds** to block
46
+ DNS-rebinding against `127.0.0.1` / `localhost` / `[::1]`. On
47
+ non-loopback binds the operator has already accepted exposure via
48
+ `--allow-remote`, and the server can't statically enumerate every
49
+ hostname/IP a LAN/VPN/DNS client might reach it by — those checks
50
+ are skipped. If you need per-`Host` policy on a LAN/WAN deployment,
51
+ front the server with a reverse proxy that enforces it.
52
+
53
+ Smoke test (no browser needed — verifies the protocol surface):
54
+
55
+ ```sh
56
+ npm run smoke
57
+ ```
58
+
59
+ Unit + L2 contract tests (~640ms, no browser, no LLM):
60
+
61
+ ```sh
62
+ npm test
63
+ ```
64
+
65
+ Currently 299 tests across 22 files. The `test/` tree is the L2 contract
66
+ layer (every tool exercised against a fake CDP — see `test/fake-cdp.ts`);
67
+ the inline `src/**/*.test.ts` files are L1 pure-data tests; `evals/**/
68
+ *.test.ts` cover the L4 harness's grader/trace/oracle units (21 tests).
69
+ See `docs/test-eval-plan.md` for the full pyramid.
70
+
71
+ ### L3 — real-browser end-to-end
72
+
73
+ ```sh
74
+ npm run test:e2e
75
+ ```
76
+
77
+ Drives the 39 MCP tools against a real headless Chromium attached to a
78
+ built copy of `examples/sample-app/`. Nine specs cover lifecycle, breakpoints,
79
+ stepping, exceptions, console, network, workers, screenshot, and DOM
80
+ interaction. Sequential (one Chrome shared across specs, isolated by a
81
+ shared `afterEach(close_session)`). Run time is a few seconds on a warm
82
+ machine.
83
+
84
+ **Browser selection (`CDP_TEST_BROWSER` env, default `chromium`)**:
85
+
86
+ | Linux x86_64 | Linux ARM64 (primary local) | macOS | Windows |
87
+ |---|---|---|---|
88
+ | `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`) |
89
+ | `chrome`: chrome-launcher auto-detect | **not supported** — fail-fast | `chrome`: chrome-launcher auto-detect | `chrome`: chrome-launcher auto-detect |
90
+
91
+ **Local-Windows status**: at the time L3 landed, `chrome-launcher` 1.2.1 fails
92
+ to bind to its own picked port on Windows 11 (ECONNREFUSED inside chrome-
93
+ launcher's startup poll) regardless of headless mode, Chrome stable vs
94
+ Playwright Chromium, or explicit ports. The same code path works on Linux
95
+ where CI runs. If you need to test L3 changes locally on Windows, run them
96
+ under WSL2 (Ubuntu) or push and let CI validate. The unit + L2 tests work
97
+ fine on Windows.
98
+
99
+ Setting an explicit binary path (for example, after running
100
+ `npx playwright install chromium` locally on Linux) lets the resolver skip
101
+ detection and use the bundled binary:
102
+
103
+ ```sh
104
+ export CDP_TEST_BROWSER_PATH="$HOME/.cache/ms-playwright/chromium-1223/chrome-linux/chrome"
105
+ npm run test:e2e
106
+ ```
107
+
108
+ Any spec failing on Chromium-only but passing on Chrome stable should land
109
+ with a `// @chromium-skip — <gap-id>` comment AND a row in
110
+ `docs/known-chromium-gaps.md` — `npm run lint:chromium-skips` (and the
111
+ pretest hook) enforces this.
112
+
113
+ `launch_chrome` defaults to `--no-sandbox` for Ubuntu/Playwright-Chromium
114
+ compatibility. See [`docs/chromium-sandboxing.md`](docs/chromium-sandboxing.md)
115
+ before changing that default or relying on `sandbox: true`, AppArmor, snap
116
+ confinement, or Bubblewrap.
117
+
118
+ ### L4 — LLM agent evals
119
+
120
+ ```sh
121
+ export ANTHROPIC_API_KEY=...
122
+ npm run eval:quick # 1 scenario × 1 trial (~$0.50–2 at default Opus-4.7-medium; ~$0.05 with EVAL_MODEL_OVERRIDE=claude-sonnet-4-6)
123
+ npm run eval # all scenarios × 3 trials (first observed ~$4 at default Opus-4.7-medium on a reference host — one data point, not the steady-state band)
124
+ npm run eval -- --scenarios=compute-step --trials=1
125
+ ```
126
+
127
+ 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.
128
+
129
+ Drives the cdp-mcp tool surface through an LLM agent via the
130
+ `VendorAdapter` seam (`evals/harness/vendor.ts`); the Anthropic adapter
131
+ backed by `@anthropic-ai/sdk` is the default and only production path
132
+ today. Each trial spawns a fresh `dist/index.js` MCP subprocess + a
133
+ static server for the scenario's sample-app variant; the tool-use loop
134
+ drives the page, sets source-level breakpoints, inspects pauses, and
135
+ produces a natural-language final answer. NDJSON traces land under
136
+ `evals/runs/<run-id>/` (gitignored). A programmatic oracle per scenario
137
+ (no LLM judge) emits a dual-axis verdict — **mechanic** (did the agent
138
+ exercise the debugger workflow under test) + **correctness** (did the
139
+ final answer name the bug) — plus efficiency ratio and recovery count.
140
+
141
+ **Default model**: `claude-opus-4-7` with adaptive thinking at
142
+ `effort=medium` (set in `evals/harness/model.ts`). Adaptive-style models
143
+ (Opus 4.7+) default to medium-effort thinking when no env override is
144
+ set; budget-style models (Sonnet 4.6, selectable via
145
+ `EVAL_MODEL_OVERRIDE`) keep extended thinking **off** by default for the
146
+ cheap-baseline path. Override via env:
147
+
148
+ - `EVAL_MODEL_OVERRIDE=claude-sonnet-4-6` — switch to the budget-style
149
+ Sonnet baseline (no thinking by default; ~$5–10/full run).
150
+ - `EVAL_REASONING_LEVEL=none|low|medium|high|xhigh|max` — pick a tier
151
+ (or explicit `none` to disable on adaptive models). On budget-style
152
+ models each tier maps to a default `budget_tokens` in
153
+ `TIER_BUDGET_TOKENS` (high=16K). On adaptive models the tier maps
154
+ directly to Anthropic's `effort` parameter.
155
+ - `EVAL_REASONING_BUDGET=N` — override the budget on budget-style
156
+ models. Used alone the level is tagged `custom`; used alongside
157
+ `EVAL_REASONING_LEVEL` it overrides that tier's default.
158
+
159
+ Thinking-on runs are non-deterministic (Anthropic requires
160
+ `temperature=1` with `thinking`), so use `--trials >= 3` to characterize
161
+ variance. Cost-cap: `$100` per `npm run eval` invocation (override via
162
+ `EVAL_BUDGET_USD` env). Rotation across the Anthropic family + GPT-5.5
163
+ is a follow-up — see the proposal at
164
+ [`docs/eval-model-rotation-proposal.md`](docs/eval-model-rotation-proposal.md).
165
+
166
+ Caching: the system prompt + tool list are tagged `cache_control:
167
+ ephemeral`. The system block (~280 tokens) is below Anthropic's
168
+ ~1024-token cache-breakpoint minimum, so only the ~5K-token tools array
169
+ actually caches across trials — that's enough to dominate the input
170
+ cost across trial 2+. Verify post-run via the `cacheTokens` field on
171
+ each `t:"usage"` trace entry (the Anthropic adapter populates
172
+ `cacheTokens.cacheReadInputTokens` and `cacheTokens.cacheCreationInputTokens`
173
+ verbatim from the SDK's `cache_read_input_tokens` / `cache_creation_input_tokens`).
174
+
175
+ Non-Anthropic backends: the OpenAI vendor adapter ships with #50/#58
176
+ (target: GPT-5.5) — `EVAL_PROVIDER=openai` plus `OPENAI_API_KEY`
177
+ + `EVAL_OPENAI_MODEL` activates it. Reasoning-off trials route to
178
+ `/v1/chat/completions` (#50); reasoning-on trials route to
179
+ `/v1/responses` (#58), the only OpenAI surface that supports tools
180
+ × reasoning_effort on GPT-5.5. An LM Studio investigation artifact
181
+ is wired behind the same seam for issue #45. See
182
+ [evals/README.md](evals/README.md) for full `EVAL_PROVIDER` /
183
+ `EVAL_OPENAI_*` / `EVAL_LM_STUDIO_*` details. Vertex (#51) is the last
184
+ backend adapter still pending.
185
+
186
+ Currently registered scenarios (8): `compute-step` and
187
+ `adversarial-out-of-order` ship against the canonical `examples/sample-app/`;
188
+ `network-bug`, `console-error`, `event-binding`, `deep-source-map`,
189
+ `worker-bug`, and `conditional-bp` have committed per-scenario forks
190
+ under `evals/sample-app-variants/<name>/` and build via
191
+ `npm run sample:build` (`scripts/build-variants.mjs`).
192
+
193
+ ## Wire into Claude Code
194
+
195
+ ```sh
196
+ claude mcp add cdp-mcp node /absolute/path/to/dist/index.js
197
+ ```
198
+
199
+ Or via `~/.claude.json`:
200
+
201
+ ```json
202
+ {
203
+ "mcpServers": {
204
+ "cdp-mcp": { "command": "node", "args": ["/abs/path/dist/index.js"] }
205
+ }
206
+ }
207
+ ```
208
+
209
+ ## End-to-end smoke (with a browser)
210
+
211
+ 1. Install the sample app's deps and start it:
212
+ ```sh
213
+ cd examples/sample-app
214
+ npm install
215
+ npm run dev # listens on :5173
216
+ ```
217
+ 2. In a Claude Code session with `cdp-mcp` enabled, ask:
218
+ > 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.
219
+ 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`.
220
+
221
+ ## Tool conventions for agents
222
+
223
+ - **File coords are TS, 1-based lines, 0-based columns** unless the tool name ends in `_js` or takes a `script_id`.
224
+ - **Pause-only tools** (`get_call_stack`, `get_scope`, `evaluate` with `frame_index`): return `error: "not_paused"` if called outside a pause.
225
+ - **Buffered tools** (`get_console_logs`, `get_network_requests`): return a `cursor` (max `seq` seen). Pass it back as `since` to paginate.
226
+ - **Errors** come back as `isError: true` with a structured `{ error, message }` JSON payload.
227
+ - **Compact returns**: previews trimmed to ~200 chars, lists capped at sensible defaults — bodies lazy-loaded via dedicated tools.
228
+
229
+ ## Prior art
230
+
231
+ If `cdp-mcp` doesn't fit your workflow, look at:
232
+ - [`InDate/cdp-tools-mcp`](https://github.com/InDate/cdp-tools-mcp)
233
+ - [`ScriptedAlchemy/devtools-debugger-mcp`](https://github.com/ScriptedAlchemy/devtools-debugger-mcp) (Node-focused)
234
+ - [`ChromeDevTools/chrome-devtools-mcp`](https://github.com/ChromeDevTools/chrome-devtools-mcp) (automation + console, no breakpoints)
235
+
236
+ ## Out of scope for v1
237
+
238
+ Firefox / Safari, Node.js debugging, `Storage.*`, `Tracing.*`, `HeapProfiler.*`, concurrent multi-page debugging.
239
+
240
+ See [design notes](docs/design-notes.md) — original plan snapshot + a section on what reviewer iteration discovered.
package/dist/index.js ADDED
@@ -0,0 +1,345 @@
1
+ #!/usr/bin/env node
2
+ import { createServer } from "node:http";
3
+ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import { buildServer } from "./server.js";
6
+ import { getSession, sessionState } from "./session/state.js";
7
+ import { log } from "./util/log.js";
8
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "::1"]);
9
+ function isLoopbackHost(host) {
10
+ return LOOPBACK_HOSTS.has(host);
11
+ }
12
+ function parseArgs(args) {
13
+ let port;
14
+ let host = "127.0.0.1";
15
+ let allowRemote = process.env.CDP_MCP_ALLOW_REMOTE === "1";
16
+ for (let index = 0; index < args.length; index += 1) {
17
+ const arg = args[index];
18
+ if (!arg) {
19
+ continue;
20
+ }
21
+ if (arg === "--help" || arg === "-h") {
22
+ process.stderr.write([
23
+ "Usage:",
24
+ " cdp-mcp # stdio MCP transport",
25
+ " cdp-mcp --port 9719 # SSE MCP transport on 127.0.0.1:9719",
26
+ " cdp-mcp --host 0.0.0.0 --port 9719 --allow-remote",
27
+ "",
28
+ "SSE mode caveats:",
29
+ " - Single-client only: concurrent /sse connections race on a",
30
+ " shared browser session (sessionState is process-global).",
31
+ " - Non-loopback bind requires --allow-remote (or",
32
+ " CDP_MCP_ALLOW_REMOTE=1). MCP tools include in-page eval and",
33
+ " server-filesystem writes; exposing them remotely without",
34
+ " further auth is a deliberate operator decision.",
35
+ " - Host / Origin headers are validated against the loopback",
36
+ " aliases (127.0.0.1, localhost, [::1]) to block",
37
+ " DNS-rebinding. On non-loopback binds the operator has",
38
+ " accepted exposure via --allow-remote, and we cannot",
39
+ " enumerate every reachable hostname/IP, so the checks",
40
+ " are skipped — front the server with a reverse proxy if",
41
+ " you need per-Host policy.",
42
+ "",
43
+ ].join("\n"));
44
+ process.exit(0);
45
+ }
46
+ if (arg === "--port") {
47
+ const value = args[index + 1];
48
+ if (!value)
49
+ throw new Error("--port requires a value");
50
+ port = parsePort(value);
51
+ index += 1;
52
+ continue;
53
+ }
54
+ if (arg.startsWith("--port=")) {
55
+ port = parsePort(arg.slice("--port=".length));
56
+ continue;
57
+ }
58
+ if (arg === "--host") {
59
+ const value = args[index + 1];
60
+ if (!value)
61
+ throw new Error("--host requires a value");
62
+ host = value;
63
+ index += 1;
64
+ continue;
65
+ }
66
+ if (arg.startsWith("--host=")) {
67
+ host = arg.slice("--host=".length);
68
+ continue;
69
+ }
70
+ if (arg === "--allow-remote") {
71
+ allowRemote = true;
72
+ continue;
73
+ }
74
+ throw new Error(`Unknown argument: ${arg}`);
75
+ }
76
+ if (port === undefined) {
77
+ return { transport: "stdio" };
78
+ }
79
+ if (!isLoopbackHost(host) && !allowRemote) {
80
+ throw new Error(`Refusing to bind SSE transport on non-loopback host '${host}' without --allow-remote (or CDP_MCP_ALLOW_REMOTE=1). MCP tools include in-page eval and server-filesystem writes; remote exposure is opt-in.`);
81
+ }
82
+ return {
83
+ transport: "sse",
84
+ host,
85
+ port,
86
+ allowRemote,
87
+ };
88
+ }
89
+ function parsePort(raw) {
90
+ const port = Number(raw);
91
+ if (!Number.isInteger(port) || port < 1 || port > 65535) {
92
+ throw new Error(`Invalid --port value: ${raw}`);
93
+ }
94
+ return port;
95
+ }
96
+ async function main() {
97
+ const mode = parseArgs(process.argv.slice(2));
98
+ if (mode.transport === "sse") {
99
+ await runSseServer(mode);
100
+ return;
101
+ }
102
+ await runStdioServer();
103
+ }
104
+ async function runStdioServer() {
105
+ const server = buildServer();
106
+ const transport = new StdioServerTransport();
107
+ await server.connect(transport);
108
+ log.info("cdp-mcp server started", { pid: process.pid });
109
+ const shutdown = async (signal) => {
110
+ log.info(`shutdown signal: ${signal}`);
111
+ try {
112
+ const session = getSession();
113
+ if (session)
114
+ await sessionState.close();
115
+ }
116
+ catch (e) {
117
+ log.warn("error during shutdown", { error: String(e) });
118
+ }
119
+ try {
120
+ await server.close();
121
+ }
122
+ catch (e) {
123
+ log.warn("error closing server", { error: String(e) });
124
+ }
125
+ process.exit(0);
126
+ };
127
+ process.on("SIGINT", () => void shutdown("SIGINT"));
128
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
129
+ installProcessErrorHandlers();
130
+ }
131
+ async function runSseServer(mode) {
132
+ const clients = new Map();
133
+ // Host/Origin validation is a DNS-rebinding defense — it bites only
134
+ // on loopback binds, where an attacker page can be tricked into
135
+ // reaching 127.0.0.1 via a rebound DNS name. On non-loopback binds
136
+ // the operator has explicitly accepted exposure via --allow-remote,
137
+ // and we cannot statically enumerate every hostname/IP the host
138
+ // might be reached by (LAN IP, hostname, mDNS, VPN, …) — so we skip
139
+ // both checks and treat --allow-remote as the gate.
140
+ const validateHostOrigin = isLoopbackHost(mode.host);
141
+ const allowedHosts = validateHostOrigin ? buildAllowedHosts(mode.host, mode.port) : new Set();
142
+ const allowedOrigins = validateHostOrigin ? buildAllowedOrigins(mode.host, mode.port) : new Set();
143
+ const httpServer = createServer((req, res) => {
144
+ void handleSseRequest({
145
+ req,
146
+ res,
147
+ clients,
148
+ host: mode.host,
149
+ port: mode.port,
150
+ validateHostOrigin,
151
+ allowedHosts,
152
+ allowedOrigins,
153
+ });
154
+ });
155
+ await listen(httpServer, mode);
156
+ log.info("cdp-mcp SSE server started", {
157
+ pid: process.pid,
158
+ url: `http://${mode.host}:${mode.port}/sse`,
159
+ allowRemote: mode.allowRemote,
160
+ });
161
+ if (!isLoopbackHost(mode.host)) {
162
+ log.warn("SSE bound to non-loopback host — exposing in-page eval + filesystem-write tools without auth (operator opted in via --allow-remote)", { host: mode.host, port: mode.port });
163
+ }
164
+ // Close SSE transports BEFORE the HTTP server: Node's server.close()
165
+ // waits for in-flight requests to drain, and /sse connections are
166
+ // long-lived by design — closing the HTTP server first would hang
167
+ // SIGINT / SIGTERM indefinitely.
168
+ const shutdown = async (signal) => {
169
+ log.info(`shutdown signal: ${signal}`);
170
+ await closeSseClients(clients);
171
+ await closeHttpServer(httpServer);
172
+ try {
173
+ const session = getSession();
174
+ if (session)
175
+ await sessionState.close();
176
+ }
177
+ catch (e) {
178
+ log.warn("error during shutdown", { error: String(e) });
179
+ }
180
+ process.exit(0);
181
+ };
182
+ process.on("SIGINT", () => void shutdown("SIGINT"));
183
+ process.on("SIGTERM", () => void shutdown("SIGTERM"));
184
+ installProcessErrorHandlers();
185
+ }
186
+ function installProcessErrorHandlers() {
187
+ process.on("uncaughtException", (err) => {
188
+ log.error("uncaughtException", { error: String(err), stack: err.stack });
189
+ });
190
+ process.on("unhandledRejection", (reason) => {
191
+ log.error("unhandledRejection", { reason: String(reason) });
192
+ });
193
+ }
194
+ async function handleSseRequest({ req, res, clients, host, port, validateHostOrigin, allowedHosts, allowedOrigins, }) {
195
+ try {
196
+ // DNS-rebinding defense for loopback binds: validate Host (and
197
+ // Origin if present) before the SDK touches the request. The MCP
198
+ // SDK's SSEServerTransport does not gate either header by default.
199
+ // Skipped on non-loopback binds — see runSseServer for rationale.
200
+ if (validateHostOrigin) {
201
+ const headerHost = req.headers.host;
202
+ if (!headerHost || !allowedHosts.has(headerHost)) {
203
+ log.warn("rejecting SSE request with disallowed Host header", {
204
+ host: headerHost,
205
+ bindHost: host,
206
+ });
207
+ respondText(res, 403, "forbidden\n");
208
+ return;
209
+ }
210
+ // Origin is only sent by browsers (and is `null` for sandboxed
211
+ // iframes / file://). Checking it when present is the
212
+ // cross-origin defense layer; the Host check above is what
213
+ // catches non-browser callers and Origin-omitting browsers.
214
+ const originHeader = req.headers.origin;
215
+ if (originHeader && !allowedOrigins.has(originHeader)) {
216
+ log.warn("rejecting SSE request with disallowed Origin header", { origin: originHeader });
217
+ respondText(res, 403, "forbidden\n");
218
+ return;
219
+ }
220
+ }
221
+ const url = new URL(req.url ?? "/", `http://${req.headers.host ?? `${host}:${port}`}`);
222
+ if (req.method === "GET" && url.pathname === "/sse") {
223
+ await startSseConnection({ res, clients });
224
+ return;
225
+ }
226
+ if (req.method === "POST" && url.pathname === "/messages") {
227
+ await handleSseMessage({ req, res, clients, sessionId: url.searchParams.get("sessionId") });
228
+ return;
229
+ }
230
+ respondText(res, 404, "not found\n");
231
+ }
232
+ catch (e) {
233
+ log.error("SSE request failed", { error: String(e) });
234
+ if (!res.headersSent) {
235
+ respondText(res, 500, "internal server error\n");
236
+ }
237
+ else {
238
+ res.end();
239
+ }
240
+ }
241
+ }
242
+ // Called only on loopback binds (see runSseServer). The set covers the
243
+ // three loopback aliases a browser or CLI might use to reach a 127.0.0.1
244
+ // / localhost / ::1 server; anything else implies DNS-rebinding.
245
+ function buildAllowedHosts(bindHost, port) {
246
+ const hosts = new Set([
247
+ `${bindHost}:${port}`,
248
+ `127.0.0.1:${port}`,
249
+ `localhost:${port}`,
250
+ `[::1]:${port}`,
251
+ ]);
252
+ return hosts;
253
+ }
254
+ function buildAllowedOrigins(bindHost, port) {
255
+ const origins = new Set();
256
+ for (const hostPort of buildAllowedHosts(bindHost, port)) {
257
+ origins.add(`http://${hostPort}`);
258
+ origins.add(`https://${hostPort}`);
259
+ }
260
+ return origins;
261
+ }
262
+ async function startSseConnection({ res, clients, }) {
263
+ const transport = new SSEServerTransport("/messages", res);
264
+ const server = buildServer();
265
+ transport.onclose = () => {
266
+ const client = clients.get(transport.sessionId);
267
+ clients.delete(transport.sessionId);
268
+ void client?.server.close().catch((e) => {
269
+ log.warn("error closing MCP server for SSE client", { sessionId: transport.sessionId, error: String(e) });
270
+ });
271
+ };
272
+ transport.onerror = (e) => {
273
+ log.warn("SSE transport error", { sessionId: transport.sessionId, error: String(e) });
274
+ };
275
+ clients.set(transport.sessionId, { server, transport });
276
+ await server.connect(transport);
277
+ log.info("SSE client connected", { sessionId: transport.sessionId });
278
+ }
279
+ async function handleSseMessage({ req, res, clients, sessionId, }) {
280
+ if (!sessionId) {
281
+ respondText(res, 400, "missing sessionId\n");
282
+ return;
283
+ }
284
+ const client = clients.get(sessionId);
285
+ if (!client) {
286
+ respondText(res, 404, "unknown sessionId\n");
287
+ return;
288
+ }
289
+ await client.transport.handlePostMessage(req, res);
290
+ }
291
+ async function listen(server, mode) {
292
+ await new Promise((resolve, reject) => {
293
+ const onError = (e) => {
294
+ server.off("listening", onListening);
295
+ reject(e);
296
+ };
297
+ const onListening = () => {
298
+ server.off("error", onError);
299
+ resolve();
300
+ };
301
+ server.once("error", onError);
302
+ server.once("listening", onListening);
303
+ server.listen(mode.port, mode.host);
304
+ });
305
+ }
306
+ async function closeHttpServer(server) {
307
+ await new Promise((resolve, reject) => {
308
+ server.close((e) => {
309
+ if (e) {
310
+ reject(e);
311
+ return;
312
+ }
313
+ resolve();
314
+ });
315
+ }).catch((e) => {
316
+ log.warn("error closing HTTP server", { error: String(e) });
317
+ });
318
+ }
319
+ async function closeSseClients(clients) {
320
+ const entries = [...clients.entries()];
321
+ clients.clear();
322
+ await Promise.all(entries.map(async ([sessionId, client]) => {
323
+ try {
324
+ await client.transport.close();
325
+ }
326
+ catch (e) {
327
+ log.warn("error closing SSE transport", { sessionId, error: String(e) });
328
+ }
329
+ try {
330
+ await client.server.close();
331
+ }
332
+ catch (e) {
333
+ log.warn("error closing MCP server", { sessionId, error: String(e) });
334
+ }
335
+ }));
336
+ }
337
+ function respondText(res, statusCode, body) {
338
+ res.writeHead(statusCode, { "Content-Type": "text/plain; charset=utf-8" });
339
+ res.end(body);
340
+ }
341
+ main().catch((err) => {
342
+ log.error("fatal", { error: String(err), stack: err?.stack });
343
+ process.exit(1);
344
+ });
345
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/server.js ADDED
@@ -0,0 +1,27 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { registerSessionTools } from "./tools/session.js";
3
+ import { registerNavTools } from "./tools/nav.js";
4
+ import { registerSourceTools } from "./tools/source.js";
5
+ import { registerBreakpointTools } from "./tools/breakpoints.js";
6
+ import { registerExecutionTools } from "./tools/execution.js";
7
+ import { registerInspectTools } from "./tools/inspect.js";
8
+ import { registerConsoleTools } from "./tools/console.js";
9
+ import { registerNetworkTools } from "./tools/network.js";
10
+ import { registerDomTools } from "./tools/dom.js";
11
+ export function buildServer() {
12
+ const server = new McpServer({
13
+ name: "cdp-mcp",
14
+ version: "0.1.0",
15
+ });
16
+ registerSessionTools(server);
17
+ registerNavTools(server);
18
+ registerSourceTools(server);
19
+ registerBreakpointTools(server);
20
+ registerExecutionTools(server);
21
+ registerInspectTools(server);
22
+ registerConsoleTools(server);
23
+ registerNetworkTools(server);
24
+ registerDomTools(server);
25
+ return server;
26
+ }
27
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAElD,MAAM,UAAU,WAAW;IACzB,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACzB,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAC5B,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChC,sBAAsB,CAAC,MAAM,CAAC,CAAC;IAC/B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,oBAAoB,CAAC,MAAM,CAAC,CAAC;IAC7B,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAEzB,OAAO,MAAM,CAAC;AAChB,CAAC"}