@ait-co/devtools 0.1.44 → 0.1.46
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.en.md +16 -7
- package/README.md +34 -7
- package/dist/mcp/cli.d.ts +8 -1
- package/dist/mcp/cli.d.ts.map +1 -1
- package/dist/mcp/cli.js +709 -143
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +312 -15
- package/dist/mcp/server.js.map +1 -1
- package/dist/panel/index.js +2 -2
- package/package.json +1 -1
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/ait-source.ts","../../src/mcp/server.ts"],"mappings":";;;;;;;AAsBA;;;;;AAGA;;;;;;;;;;;;;KAHY,kBAAA;AAqBZ;AAAA,UAlBiB,UAAA;;EAEf,MAAA;EAiBiB;EAfjB,IAAA;EAwBsB;EAtBtB,SAAA;EAsByB;EApBzB,MAAA;EAuBe;EArBf,MAAA;;EAEA,KAAA;EAuBU;EArBV,QAAA,EAAU,kBAAA;AAAA;;UAIK,iBAAA;EACf,KAAA,EAAO,UAAA;AAAA;;;;;;;KASG,YAAA,GAAe,MAAA;;UAGV,yBAAA;EAW2C;EAT1D,WAAA;EAYuB;EAVvB,UAAA;AAAA;;UAIe,YAAA;EACf,uBAAA,EAAyB,iBAAA;EACzB,kBAAA,EAAoB,YAAA;EACpB,+BAAA,EAAiC,yBAAA;AAAA;AAAA,KAGvB,aAAA,SAAsB,YAAA;;;;;UAMjB,SAAA;EACf,GAAA,WAAc,aAAA,EAAe,MAAA,EAAQ,CAAA,GAAI,OAAA,CAAQ,YAAA,CAAa,CAAA;AAAA;;;
|
|
1
|
+
{"version":3,"file":"server.d.ts","names":[],"sources":["../../src/mcp/ait-source.ts","../../src/mcp/server.ts"],"mappings":";;;;;;;AAsBA;;;;;AAGA;;;;;;;;;;;;;KAHY,kBAAA;AAqBZ;AAAA,UAlBiB,UAAA;;EAEf,MAAA;EAiBiB;EAfjB,IAAA;EAwBsB;EAtBtB,SAAA;EAsByB;EApBzB,MAAA;EAuBe;EArBf,MAAA;;EAEA,KAAA;EAuBU;EArBV,QAAA,EAAU,kBAAA;AAAA;;UAIK,iBAAA;EACf,KAAA,EAAO,UAAA;AAAA;;;;;;;KASG,YAAA,GAAe,MAAA;;UAGV,yBAAA;EAW2C;EAT1D,WAAA;EAYuB;EAVvB,UAAA;AAAA;;UAIe,YAAA;EACf,uBAAA,EAAyB,iBAAA;EACzB,kBAAA,EAAoB,YAAA;EACpB,+BAAA,EAAiC,yBAAA;AAAA;AAAA,KAGvB,aAAA,SAAsB,YAAA;;;;;UAMjB,SAAA;EACf,GAAA,WAAc,aAAA,EAAe,MAAA,EAAQ,CAAA,GAAI,OAAA,CAAQ,YAAA,CAAa,CAAA;AAAA;;;UCkN/C,mBAAA;EDnNS;ECqNxB,SAAA,GAAY,SAAA;AAAA;;iBA8IE,eAAA,CAAgB,IAAA,GAAM,mBAAA,GAA2B,MAAA;;iBAuF3C,YAAA,CAAA,GAAgB,OAAA"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -214,7 +214,7 @@ new Set([
|
|
|
214
214
|
},
|
|
215
215
|
{
|
|
216
216
|
name: "list_pages",
|
|
217
|
-
description: "Returns the single active page (at most one) the relay sees attached. When a second page attaches, the previous one is evicted (last-attach wins — single-attach model). The result includes `singleAttachModel: true` so the agent knows the array is always 0 or 1 entries. Also returns whether the cloudflared tunnel is up and the public wss relay URL. The `tunnel` field includes `droppedAt` (ISO timestamp or null/undefined): when non-null the tunnel has permanently dropped after 3 failed reissue attempts — restart the debug server with `npx @ait-co/devtools devtools-mcp`. Each page entry includes a `lastSeenAt` ISO timestamp (last inbound CDP message from that target — useful to detect stale entries when the phone app backgrounded). The result also includes `crashDetectedAt` (ISO timestamp or null): when non-null, a page crash was detected via Inspector.targetCrashed / Target.targetDestroyed since the last attach, the pages list will be empty, and `crashWarning` shows a Korean hint to re-attach. Call this first to confirm a page is attached before reading console/network.",
|
|
217
|
+
description: "Returns the single active page (at most one) the relay sees attached. When a second page attaches, the previous one is evicted (last-attach wins — single-attach model). The result includes `singleAttachModel: true` so the agent knows the array is always 0 or 1 entries. Also returns whether the cloudflared tunnel is up and the public wss relay URL. The `tunnel` field includes `droppedAt` (ISO timestamp or null/undefined): when non-null the tunnel has permanently dropped after 3 failed reissue attempts — restart the debug server with `npx @ait-co/devtools devtools-mcp`. Each page entry includes a `lastSeenAt` ISO timestamp (last inbound CDP message from that target — useful to detect stale entries when the phone app backgrounded). The result also includes `crashDetectedAt` (ISO timestamp or null): when non-null, a page crash was detected via Inspector.targetCrashed / Target.targetDestroyed since the last attach, the pages list will be empty, and `crashWarning` shows a Korean hint to re-attach. Call this first to confirm a page is attached before reading console/network. When a page attaches or detaches the server emits notifications/tools/list_changed — call tools/list again to get the full updated tool surface.",
|
|
218
218
|
inputSchema: {
|
|
219
219
|
type: "object",
|
|
220
220
|
properties: {},
|
|
@@ -224,7 +224,7 @@ new Set([
|
|
|
224
224
|
},
|
|
225
225
|
{
|
|
226
226
|
name: "build_attach_url",
|
|
227
|
-
description: "The tool result already shows the QR to the user directly (Claude Code renders MCP tool output to the user's screen; they press Ctrl+O to expand if it's collapsed). Do NOT re-print or re-render the QR in your reply — that just wastes output tokens. Simply tell the user to scan the QR shown in this tool's output with their phone camera. Turns an `ait deploy --scheme-only` URL (intoss-private://…?_deploymentId=<uuid>) into a self-attaching deep link by splicing in debug=1 and the live relay URL for this session. Returns the deep link JSON and a unicode QR of that deep link. Scan the QR with the phone camera to open the mini-app and attach it to this debug session (QR is the single entry path — no USB cable or platform CLI needed). Requires the tunnel to be up — call list_pages first. Set wait_for_attach=true to block until the phone scans and a page attaches (polls listTargets up to
|
|
227
|
+
description: "The tool result already shows the QR to the user directly (Claude Code renders MCP tool output to the user's screen; they press Ctrl+O to expand if it's collapsed). Do NOT re-print or re-render the QR in your reply — that just wastes output tokens. Simply tell the user to scan the QR shown in this tool's output with their phone camera. Turns an `ait deploy --scheme-only` URL (intoss-private://…?_deploymentId=<uuid>) into a self-attaching deep link by splicing in debug=1 and the live relay URL for this session. Returns the deep link JSON and a unicode QR of that deep link. Scan the QR with the phone camera to open the mini-app and attach it to this debug session (QR is the single entry path — no USB cable or platform CLI needed). Requires the tunnel to be up — call list_pages first. If the tunnel is not up, restart the MCP server: `npx @ait-co/devtools devtools-mcp`. Set wait_for_attach=true to block until the phone scans and a page attaches (polls listTargets up to 30 s by default), then returns the attached page info too. On timeout, call build_attach_url again to resume polling. When open_in_browser=true (default), saves the QR as a PNG and opens it in the OS default browser — only works when the MCP server runs on a local GUI machine (not headless/remote containers). Requires MCP_ENV=relay-dev or relay-live (set automatically in debug-mode default).\n\nTOTP auth: when AIT_DEBUG_TOTP_SECRET is set on the MCP server, the returned attachUrl automatically includes the current one-time code (at=<code>) — the URL is single-use for that 30-second step. The response includes a `totp` field with `expiresAt` (ISO timestamp). If the phone scan happens after expiresAt, the relay will reject the code — just call build_attach_url again to get a fresh one-time URL. Without AIT_DEBUG_TOTP_SECRET, the attachUrl has no expiry.",
|
|
228
228
|
inputSchema: {
|
|
229
229
|
type: "object",
|
|
230
230
|
properties: {
|
|
@@ -234,7 +234,7 @@ new Set([
|
|
|
234
234
|
},
|
|
235
235
|
wait_for_attach: {
|
|
236
236
|
type: "boolean",
|
|
237
|
-
description: "If true, block after returning the QR until a page attaches to the relay (polls listTargets ~1 s interval, timeout
|
|
237
|
+
description: "If true, block after returning the QR until a page attaches to the relay (polls listTargets ~1 s interval, timeout 30 s). On attach, the response includes the attached page list. On timeout, call build_attach_url again to resume polling."
|
|
238
238
|
},
|
|
239
239
|
open_in_browser: {
|
|
240
240
|
type: "boolean",
|
|
@@ -267,7 +267,7 @@ new Set([
|
|
|
267
267
|
},
|
|
268
268
|
{
|
|
269
269
|
name: "take_screenshot",
|
|
270
|
-
description: "Captures a PNG screenshot of the attached mini-app page over CDP (Page.captureScreenshot) so the agent can see the phone screen directly. Read-only. Returns an image content block.",
|
|
270
|
+
description: "Captures a PNG screenshot of the attached mini-app page over CDP (Page.captureScreenshot) so the agent can see the phone screen directly. Read-only. Returns an image content block — this is the only debug tool that returns an image; all other debug tools return text (JSON).",
|
|
271
271
|
inputSchema: {
|
|
272
272
|
type: "object",
|
|
273
273
|
properties: {},
|
|
@@ -287,13 +287,19 @@ new Set([
|
|
|
287
287
|
},
|
|
288
288
|
{
|
|
289
289
|
name: "evaluate",
|
|
290
|
-
description: "Evaluates an arbitrary JavaScript expression on the attached mini-app page via CDP Runtime.evaluate (returnByValue: true) and returns the result. NOT read-only — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires the relay to be attached — call list_pages first. Throws if the evaluation throws an exception on the page.",
|
|
290
|
+
description: "Evaluates an arbitrary JavaScript expression on the attached mini-app page via CDP Runtime.evaluate (returnByValue: true) and returns the result. NOT read-only — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires the relay to be attached — call list_pages first. Throws if the evaluation throws an exception on the page.\n\nSECURITY: expression and result are not redacted — never include secrets or auth tokens in the expression.\n\nLIVE guard: when running against a live/production relay (relay-live env, MCP_ENV=relay-live), this tool requires `confirm: true` to acknowledge that the expression may affect real users. Without it the call is rejected with a structured error. mock and relay-dev sessions are unaffected.",
|
|
291
291
|
inputSchema: {
|
|
292
292
|
type: "object",
|
|
293
|
-
properties: {
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
293
|
+
properties: {
|
|
294
|
+
expression: {
|
|
295
|
+
type: "string",
|
|
296
|
+
description: "JavaScript expression to evaluate in the page context."
|
|
297
|
+
},
|
|
298
|
+
confirm: {
|
|
299
|
+
type: "boolean",
|
|
300
|
+
description: "Required when MCP_ENV=relay-live. Set to `true` to explicitly acknowledge that this expression may have side effects on real/live users. Omitting this in a relay-live session results in a structured rejection error. Has no effect in mock or relay-dev sessions."
|
|
301
|
+
}
|
|
302
|
+
},
|
|
297
303
|
required: ["expression"]
|
|
298
304
|
},
|
|
299
305
|
availableIn: "both"
|
|
@@ -313,7 +319,7 @@ new Set([
|
|
|
313
319
|
},
|
|
314
320
|
{
|
|
315
321
|
name: "call_sdk",
|
|
316
|
-
description: "Calls a dogfood SDK method via the window.__sdkCall bridge (exported by @apps-in-toss/web-framework only in __DEBUG_BUILD__ bundles). NOT read-only — SDK calls have side effects (navigation, payments, permissions, etc.). On env 2/3 (real device relay) this hits the real SDK; on env 1 (local mock) it hits the mock SDK. Requires the relay to be attached — call list_pages first. Returns {ok: true, value} on success or {ok: false, error} on failure. If a Runtime.exceptionThrown event was observed within [callStart-50ms, callEnd+200ms], the result also includes `recentException` for crash triage. Returns a clear error if window.__sdkCall is not available (non-dogfood bundle).\n\nIMPORTANT — 인자 시그니처 (잘못된 인자로 호출하면 토스 앱 crash 위험):\n setDeviceOrientation: call_sdk(\"setDeviceOrientation\", [{ type: \"landscape\" }]) // NOT \"landscape\"\n setIosSwipeGestureEnabled: call_sdk(\"setIosSwipeGestureEnabled\", [{ isEnabled: false }])\n setSecureScreen: call_sdk(\"setSecureScreen\", [{ enabled: true }])\n setScreenAwakeMode: call_sdk(\"setScreenAwakeMode\", [{ enabled: true }])\n getOperationalEnvironment: call_sdk(\"getOperationalEnvironment\", [])\n getPlatformOS: call_sdk(\"getPlatformOS\", [])\n getDeviceId: call_sdk(\"getDeviceId\", [])\n getLocale: call_sdk(\"getLocale\", [])\n getNetworkStatus: call_sdk(\"getNetworkStatus\", [])\n getSchemeUri: call_sdk(\"getSchemeUri\", [])\n requestReview: call_sdk(\"requestReview\", [])\n closeView: call_sdk(\"closeView\", [])",
|
|
322
|
+
description: "Calls a dogfood SDK method via the window.__sdkCall bridge (exported by @apps-in-toss/web-framework only in __DEBUG_BUILD__ bundles). NOT read-only — SDK calls have side effects (navigation, payments, permissions, etc.). On env 2/3 (real device relay) this hits the real SDK; on env 1 (local mock) it hits the mock SDK. Requires the relay to be attached — call list_pages first. Returns {ok: true, value} on success or {ok: false, error} on failure. If a Runtime.exceptionThrown event was observed within [callStart-50ms, callEnd+200ms], the result also includes `recentException` for crash triage. Returns a clear error if window.__sdkCall is not available (non-dogfood bundle) — redeploy via dogfood channel: `ait build && aitcc app deploy`.\n\nSECURITY: method name, args, and result value are not redacted — never include secrets.\n\nLIVE guard: when running against a live/production relay (relay-live env, MCP_ENV=relay-live), this tool requires `confirm: true` to acknowledge that the SDK call may affect real users. Without it the call is rejected with a structured error. mock and relay-dev sessions are unaffected.\n\nIMPORTANT — 인자 시그니처 (잘못된 인자로 호출하면 토스 앱 crash 위험):\n setDeviceOrientation: call_sdk(\"setDeviceOrientation\", [{ type: \"landscape\" }]) // NOT \"landscape\"\n setIosSwipeGestureEnabled: call_sdk(\"setIosSwipeGestureEnabled\", [{ isEnabled: false }])\n setSecureScreen: call_sdk(\"setSecureScreen\", [{ enabled: true }])\n setScreenAwakeMode: call_sdk(\"setScreenAwakeMode\", [{ enabled: true }])\n getOperationalEnvironment: call_sdk(\"getOperationalEnvironment\", [])\n getPlatformOS: call_sdk(\"getPlatformOS\", [])\n getDeviceId: call_sdk(\"getDeviceId\", [])\n getLocale: call_sdk(\"getLocale\", [])\n getNetworkStatus: call_sdk(\"getNetworkStatus\", [])\n getSchemeUri: call_sdk(\"getSchemeUri\", [])\n requestReview: call_sdk(\"requestReview\", [])\n closeView: call_sdk(\"closeView\", [])",
|
|
317
323
|
inputSchema: {
|
|
318
324
|
type: "object",
|
|
319
325
|
properties: {
|
|
@@ -325,6 +331,10 @@ new Set([
|
|
|
325
331
|
type: "array",
|
|
326
332
|
description: "Arguments to pass to the SDK method (optional, default []).",
|
|
327
333
|
items: {}
|
|
334
|
+
},
|
|
335
|
+
confirm: {
|
|
336
|
+
type: "boolean",
|
|
337
|
+
description: "Required when MCP_ENV=relay-live. Set to `true` to explicitly acknowledge that this SDK call may have side effects on real/live users. Omitting this in a relay-live session results in a structured rejection error. Has no effect in mock or relay-dev sessions."
|
|
328
338
|
}
|
|
329
339
|
},
|
|
330
340
|
required: ["name"]
|
|
@@ -363,7 +373,7 @@ new Set([
|
|
|
363
373
|
},
|
|
364
374
|
{
|
|
365
375
|
name: "get_diagnostics",
|
|
366
|
-
description: "Returns a single-call server status snapshot so the agent can diagnose \"why is this not working?\" without calling multiple tools. Fields: mcpVersion (MCP SDK version), devtoolsVersion (@ait-co/devtools package version), tunnel (up/wssUrl/pid/startedAt), pages (list_pages result + lastSeenAt stats), lastAttachAt, lastDetachAt, recentErrors (last N server-side errors, PII/secret redacted), environment (
|
|
376
|
+
description: "Returns a single-call server status snapshot so the agent can diagnose \"why is this not working?\" without calling multiple tools. Fields: mcpVersion (MCP SDK version), devtoolsVersion (@ait-co/devtools package version), tunnel (up/wssUrl/pid/startedAt), pages (list_pages result + lastSeenAt stats), lastAttachAt, lastDetachAt, recentErrors (last N server-side errors, PII/secret redacted), environment (kind: mock|relay-dev|relay-live, env: mock|relay backward-compat, reason, liveGuardActive: true when relay-live LIVE guard is active), serverLockHolder (pid + startedAt from the lock file, or null), nextRecommendedAction ({tool, reason} or null — the single next tool to call). All fields are nullable — missing data is null, not an error. debug-mode only — dev-mode (--mode=dev) does not support relay diagnostics. Tier C (both mock and relay). Call this first when debugging session state.",
|
|
367
377
|
inputSchema: {
|
|
368
378
|
type: "object",
|
|
369
379
|
properties: { recent_errors_limit: {
|
|
@@ -488,6 +498,27 @@ function getOperationalEnvironment(source) {
|
|
|
488
498
|
* (dev). `devtools_get_mock_state` (the original devtools#130 name) is kept as a
|
|
489
499
|
* backward-compatible alias of `AIT.getMockState`.
|
|
490
500
|
*
|
|
501
|
+
* Issue #305 (M2-1) — dev/debug tool-surface unification:
|
|
502
|
+
* dev-mode now also exposes `list_pages`, `get_diagnostics`, `measure_safe_area`,
|
|
503
|
+
* and `call_sdk` so the docs/qa/scenarios.md acceptance sequence
|
|
504
|
+
* `list_pages → measure_safe_area → call_sdk` works in dev mode without
|
|
505
|
+
* "Unknown tool" failures.
|
|
506
|
+
*
|
|
507
|
+
* - `list_pages` — shim: returns the Vite dev URL as a single-entry array.
|
|
508
|
+
* - `get_diagnostics` — dumps dev-mode server state (endpoint URL, last fetch
|
|
509
|
+
* error, reachability, mode/environment metadata).
|
|
510
|
+
* - `measure_safe_area`— reads safeAreaInsets from the mock state snapshot
|
|
511
|
+
* (source: 'mock-vite').
|
|
512
|
+
* - `call_sdk` — reads mock state and builds a mock-equivalent result
|
|
513
|
+
* using window.__ait.state for supported methods; returns
|
|
514
|
+
* an explicit tier-filter error for methods that require
|
|
515
|
+
* a live CDP bridge.
|
|
516
|
+
* - CDP-only tools (`evaluate`, `take_screenshot`, `get_dom_document`,
|
|
517
|
+
* `take_snapshot`, `list_console_messages`,
|
|
518
|
+
* `list_network_requests`, `list_exceptions`) — return an
|
|
519
|
+
* explicit tier-filter error explaining that CDP is unavailable
|
|
520
|
+
* in dev-mode and pointing to `--mode=local` or `--mode=debug`.
|
|
521
|
+
*
|
|
491
522
|
* This module is reached via the `devtools-mcp --mode=dev` CLI entry (see
|
|
492
523
|
* `cli.ts`); the default (no flag) bin mode is the debug-mode CDP/Chii server.
|
|
493
524
|
*
|
|
@@ -502,12 +533,18 @@ function getOperationalEnvironment(source) {
|
|
|
502
533
|
* }
|
|
503
534
|
* }
|
|
504
535
|
*/
|
|
536
|
+
/** Error message prefix for CDP-dependent tools called in dev-mode. */
|
|
537
|
+
const CDP_UNAVAILABLE_IN_DEV_MODE = "dev-mode에서는 CDP 연결이 없어 이 도구를 사용할 수 없습니다. 실기기 또는 로컬 Chromium에 붙이려면 `devtools-mcp --mode=local` 또는 `devtools-mcp` (debug 모드 기본)로 전환하세요.";
|
|
505
538
|
/**
|
|
506
539
|
* Tool descriptors served by the dev-mode server.
|
|
507
540
|
*
|
|
508
541
|
* All dev-mode tools are Tier C (both envs) per RFC #277 — the dev-mode server
|
|
509
542
|
* itself is the mock-side embodiment of those Tier C tools. `availableIn` is
|
|
510
543
|
* declared so the surface stays consistent with the debug-mode registry.
|
|
544
|
+
*
|
|
545
|
+
* Issue #305: CDP-only tools are also listed with explicit descriptions so
|
|
546
|
+
* agents do not get "Unknown tool" failures — they get a clear tier-filter
|
|
547
|
+
* error message instead.
|
|
511
548
|
*/
|
|
512
549
|
const DEV_TOOL_DEFINITIONS = [
|
|
513
550
|
{
|
|
@@ -549,30 +586,290 @@ const DEV_TOOL_DEFINITIONS = [
|
|
|
549
586
|
required: []
|
|
550
587
|
},
|
|
551
588
|
availableIn: "both"
|
|
589
|
+
},
|
|
590
|
+
{
|
|
591
|
+
name: "list_pages",
|
|
592
|
+
description: "dev-mode: returns the Vite dev server URL as a single-entry page list. No CDP relay is involved — `tunnel.up` is always false and `devMode: true` marks this as a shim result. Call this first to confirm the dev server is reachable. In debug mode (`devtools-mcp` / `--mode=local`) this returns real attached pages.",
|
|
593
|
+
inputSchema: {
|
|
594
|
+
type: "object",
|
|
595
|
+
properties: {},
|
|
596
|
+
required: []
|
|
597
|
+
},
|
|
598
|
+
availableIn: "both"
|
|
599
|
+
},
|
|
600
|
+
{
|
|
601
|
+
name: "get_diagnostics",
|
|
602
|
+
description: "dev-mode: returns server diagnostics — Vite endpoint URL, last fetch timestamp/error, mock state endpoint reachability, mode (\"dev\"), and environment metadata. Call this when the dev server connection is suspect. In debug mode this returns tunnel/relay/attach status instead.",
|
|
603
|
+
inputSchema: {
|
|
604
|
+
type: "object",
|
|
605
|
+
properties: { recent_errors_limit: {
|
|
606
|
+
type: "number",
|
|
607
|
+
description: "Ignored in dev-mode (no error ring buffer). Present for schema parity."
|
|
608
|
+
} },
|
|
609
|
+
required: []
|
|
610
|
+
},
|
|
611
|
+
availableIn: "both"
|
|
612
|
+
},
|
|
613
|
+
{
|
|
614
|
+
name: "measure_safe_area",
|
|
615
|
+
description: "dev-mode: reads safe-area insets from the mock state snapshot via the Vite endpoint. Returns `{ source: \"mock-vite\", sdkInsets, sdkInsetsSource: \"window.__ait\", ... }`. Values reflect what the DevTools panel reports at the time of the last state push. In debug mode this runs a Runtime.evaluate CDP probe on the attached page.",
|
|
616
|
+
inputSchema: {
|
|
617
|
+
type: "object",
|
|
618
|
+
properties: {},
|
|
619
|
+
required: []
|
|
620
|
+
},
|
|
621
|
+
availableIn: "both"
|
|
622
|
+
},
|
|
623
|
+
{
|
|
624
|
+
name: "call_sdk",
|
|
625
|
+
description: "dev-mode: calls a mock SDK method via the Vite mock state endpoint. Supported methods read from window.__ait mock state (e.g. getOperationalEnvironment). Returns the same `{ok, value}` / `{ok, error}` envelope as debug mode. In debug mode this calls the real SDK via window.__sdkCall over CDP.",
|
|
626
|
+
inputSchema: {
|
|
627
|
+
type: "object",
|
|
628
|
+
properties: {
|
|
629
|
+
name: {
|
|
630
|
+
type: "string",
|
|
631
|
+
description: "Mock SDK method name to call (e.g. \"getOperationalEnvironment\")."
|
|
632
|
+
},
|
|
633
|
+
args: {
|
|
634
|
+
type: "array",
|
|
635
|
+
description: "Arguments (ignored in dev-mode mock path; present for schema parity).",
|
|
636
|
+
items: {}
|
|
637
|
+
}
|
|
638
|
+
},
|
|
639
|
+
required: ["name"]
|
|
640
|
+
},
|
|
641
|
+
availableIn: "both"
|
|
642
|
+
},
|
|
643
|
+
{
|
|
644
|
+
name: "evaluate",
|
|
645
|
+
description: "Evaluates an arbitrary JavaScript expression via CDP Runtime.evaluate. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug` for CDP access.",
|
|
646
|
+
inputSchema: {
|
|
647
|
+
type: "object",
|
|
648
|
+
properties: { expression: {
|
|
649
|
+
type: "string",
|
|
650
|
+
description: "JavaScript expression to evaluate."
|
|
651
|
+
} },
|
|
652
|
+
required: ["expression"]
|
|
653
|
+
},
|
|
654
|
+
availableIn: "both"
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
name: "take_screenshot",
|
|
658
|
+
description: "Captures a PNG screenshot via CDP Page.captureScreenshot. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
659
|
+
inputSchema: {
|
|
660
|
+
type: "object",
|
|
661
|
+
properties: {},
|
|
662
|
+
required: []
|
|
663
|
+
},
|
|
664
|
+
availableIn: "both"
|
|
665
|
+
},
|
|
666
|
+
{
|
|
667
|
+
name: "get_dom_document",
|
|
668
|
+
description: "Returns the DOM tree via CDP DOM.getDocument. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
669
|
+
inputSchema: {
|
|
670
|
+
type: "object",
|
|
671
|
+
properties: {},
|
|
672
|
+
required: []
|
|
673
|
+
},
|
|
674
|
+
availableIn: "both"
|
|
675
|
+
},
|
|
676
|
+
{
|
|
677
|
+
name: "take_snapshot",
|
|
678
|
+
description: "Captures a serialized page snapshot via CDP DOMSnapshot.captureSnapshot. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
679
|
+
inputSchema: {
|
|
680
|
+
type: "object",
|
|
681
|
+
properties: {},
|
|
682
|
+
required: []
|
|
683
|
+
},
|
|
684
|
+
availableIn: "both"
|
|
685
|
+
},
|
|
686
|
+
{
|
|
687
|
+
name: "list_console_messages",
|
|
688
|
+
description: "Lists console messages captured via CDP Runtime.consoleAPICalled. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
689
|
+
inputSchema: {
|
|
690
|
+
type: "object",
|
|
691
|
+
properties: {},
|
|
692
|
+
required: []
|
|
693
|
+
},
|
|
694
|
+
availableIn: "both"
|
|
695
|
+
},
|
|
696
|
+
{
|
|
697
|
+
name: "list_network_requests",
|
|
698
|
+
description: "Lists network requests captured via CDP Network events. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
699
|
+
inputSchema: {
|
|
700
|
+
type: "object",
|
|
701
|
+
properties: {},
|
|
702
|
+
required: []
|
|
703
|
+
},
|
|
704
|
+
availableIn: "both"
|
|
705
|
+
},
|
|
706
|
+
{
|
|
707
|
+
name: "list_exceptions",
|
|
708
|
+
description: "Lists JS exceptions captured via CDP Runtime.exceptionThrown. NOT available in dev-mode (no CDP connection). Switch to `--mode=local` or `--mode=debug`.",
|
|
709
|
+
inputSchema: {
|
|
710
|
+
type: "object",
|
|
711
|
+
properties: { limit: {
|
|
712
|
+
type: "number",
|
|
713
|
+
description: "Maximum exceptions to return."
|
|
714
|
+
} },
|
|
715
|
+
required: []
|
|
716
|
+
},
|
|
717
|
+
availableIn: "both"
|
|
552
718
|
}
|
|
553
719
|
];
|
|
720
|
+
/** All tool names served in dev-mode (including tier-filter stubs). */
|
|
554
721
|
const DEV_TOOL_NAMES = new Set(DEV_TOOL_DEFINITIONS.map((t) => t.name));
|
|
722
|
+
/** CDP-only tools — return a tier-filter error in dev-mode. */
|
|
723
|
+
const CDP_ONLY_TOOL_NAMES = new Set([
|
|
724
|
+
"evaluate",
|
|
725
|
+
"take_screenshot",
|
|
726
|
+
"get_dom_document",
|
|
727
|
+
"take_snapshot",
|
|
728
|
+
"list_console_messages",
|
|
729
|
+
"list_network_requests",
|
|
730
|
+
"list_exceptions"
|
|
731
|
+
]);
|
|
732
|
+
/**
|
|
733
|
+
* Builds the `list_pages` dev-mode shim response.
|
|
734
|
+
* Returns the Vite dev URL as a single-entry page list with `devMode: true`.
|
|
735
|
+
*/
|
|
736
|
+
function buildDevListPagesResult(devtoolsUrl) {
|
|
737
|
+
return {
|
|
738
|
+
pages: [{
|
|
739
|
+
url: devtoolsUrl,
|
|
740
|
+
title: "dev fixture",
|
|
741
|
+
attached: true
|
|
742
|
+
}],
|
|
743
|
+
tunnel: { up: false },
|
|
744
|
+
devMode: true,
|
|
745
|
+
singleAttachModel: true
|
|
746
|
+
};
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Builds the `get_diagnostics` dev-mode response.
|
|
750
|
+
* Probes the mock state endpoint reachability and returns server metadata.
|
|
751
|
+
*/
|
|
752
|
+
async function buildDevDiagnostics(devtoolsUrl, stateEndpoint, fetchImpl) {
|
|
753
|
+
let reachable = false;
|
|
754
|
+
let lastFetchError = null;
|
|
755
|
+
let lastFetchAt = null;
|
|
756
|
+
try {
|
|
757
|
+
const res = await fetchImpl(stateEndpoint);
|
|
758
|
+
reachable = res.ok;
|
|
759
|
+
lastFetchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
760
|
+
if (!res.ok) lastFetchError = `HTTP ${res.status} ${res.statusText}`;
|
|
761
|
+
} catch (err) {
|
|
762
|
+
lastFetchError = err instanceof Error ? err.message : String(err);
|
|
763
|
+
lastFetchAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
764
|
+
}
|
|
765
|
+
return {
|
|
766
|
+
mode: "dev",
|
|
767
|
+
devtoolsUrl,
|
|
768
|
+
mcpStateEndpoint: stateEndpoint,
|
|
769
|
+
mockStateEndpointReachable: reachable,
|
|
770
|
+
lastFetchAt,
|
|
771
|
+
lastFetchError,
|
|
772
|
+
environment: {
|
|
773
|
+
kind: "mock",
|
|
774
|
+
reason: "dev-mode — Vite HTTP endpoint, no CDP connection"
|
|
775
|
+
},
|
|
776
|
+
nextRecommendedAction: reachable ? null : "mock state endpoint가 응답하지 않습니다. Vite dev 서버가 `mcp: true` 옵션으로 실행 중인지 확인하고, 필요하면 dev 서버를 재시작하세요."
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Builds the `measure_safe_area` dev-mode response from mock state.
|
|
781
|
+
* Reads `safeAreaInsets` from the AIT mock state and returns a parity-schema
|
|
782
|
+
* result with `source: 'mock-vite'`.
|
|
783
|
+
*/
|
|
784
|
+
async function buildDevMeasureSafeArea(aitSource) {
|
|
785
|
+
const rawInsets = (await aitSource.get("AIT.getMockState")).safeAreaInsets;
|
|
786
|
+
let sdkInsets = null;
|
|
787
|
+
if (rawInsets !== null && typeof rawInsets === "object" && !Array.isArray(rawInsets)) {
|
|
788
|
+
const r = rawInsets;
|
|
789
|
+
sdkInsets = {
|
|
790
|
+
top: typeof r.top === "number" ? r.top : 0,
|
|
791
|
+
right: typeof r.right === "number" ? r.right : 0,
|
|
792
|
+
bottom: typeof r.bottom === "number" ? r.bottom : 0,
|
|
793
|
+
left: typeof r.left === "number" ? r.left : 0
|
|
794
|
+
};
|
|
795
|
+
}
|
|
796
|
+
return {
|
|
797
|
+
source: "mock-vite",
|
|
798
|
+
cssEnv: {
|
|
799
|
+
top: 0,
|
|
800
|
+
right: 0,
|
|
801
|
+
bottom: 0,
|
|
802
|
+
left: 0
|
|
803
|
+
},
|
|
804
|
+
sdkInsets,
|
|
805
|
+
sdkInsetsSource: sdkInsets !== null ? "window.__ait" : null,
|
|
806
|
+
...sdkInsets === null ? { sdkInsetsError: "window.__ait.state.safeAreaInsets not found in mock state snapshot" } : {},
|
|
807
|
+
innerWidth: null,
|
|
808
|
+
innerHeight: null,
|
|
809
|
+
devicePixelRatio: null,
|
|
810
|
+
userAgent: null,
|
|
811
|
+
navBarHeight: null,
|
|
812
|
+
navBarHeightSource: "not-available-in-dev-mode"
|
|
813
|
+
};
|
|
814
|
+
}
|
|
815
|
+
/**
|
|
816
|
+
* Builds the `call_sdk` dev-mode response.
|
|
817
|
+
*
|
|
818
|
+
* Supported methods are served from the mock state snapshot. Unsupported
|
|
819
|
+
* methods return `{ ok: false, error: 'dev-mode-unsupported: ...' }` so the
|
|
820
|
+
* agent gets an informative message rather than a generic failure.
|
|
821
|
+
*/
|
|
822
|
+
async function buildDevCallSdk(methodName, aitSource) {
|
|
823
|
+
switch (methodName) {
|
|
824
|
+
case "getOperationalEnvironment": {
|
|
825
|
+
const env = await aitSource.get("AIT.getOperationalEnvironment");
|
|
826
|
+
return {
|
|
827
|
+
ok: true,
|
|
828
|
+
value: {
|
|
829
|
+
environment: env.environment,
|
|
830
|
+
sdkVersion: env.sdkVersion
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
default: return {
|
|
835
|
+
ok: false,
|
|
836
|
+
error: `dev-mode-unsupported: "${methodName}"은 dev-mode에서 직접 호출할 수 없습니다. CDP bridge(window.__sdkCall)가 없으므로 실제 SDK 호출은 \`--mode=local\` 또는 debug 모드에서만 가능합니다. 지원 메서드: getOperationalEnvironment (mock state에서 읽음).`
|
|
837
|
+
};
|
|
838
|
+
}
|
|
839
|
+
}
|
|
555
840
|
/** Builds the dev-mode MCP server (does not connect a transport). */
|
|
556
841
|
function createDevServer(deps = {}) {
|
|
557
|
-
const
|
|
842
|
+
const devtoolsUrl = process.env.AIT_DEVTOOLS_URL ?? "http://localhost:5173";
|
|
843
|
+
const stateEndpoint = `${devtoolsUrl}/api/ait-devtools/state`;
|
|
558
844
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
559
845
|
const server = new Server({
|
|
560
846
|
name: "ait-devtools",
|
|
561
|
-
version: "0.1.
|
|
847
|
+
version: "0.1.46"
|
|
562
848
|
}, { capabilities: { tools: {} } });
|
|
563
849
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
564
850
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
565
851
|
const name = request.params.name;
|
|
566
852
|
if (!DEV_TOOL_NAMES.has(name)) return mcpError(`알 수 없는 tool: ${name}`);
|
|
853
|
+
if (CDP_ONLY_TOOL_NAMES.has(name)) return mcpError(`${name}: ${CDP_UNAVAILABLE_IN_DEV_MODE}`);
|
|
567
854
|
try {
|
|
568
855
|
const effective = name === "devtools_get_mock_state" ? "AIT.getMockState" : name;
|
|
569
|
-
if (
|
|
570
|
-
switch (effective) {
|
|
856
|
+
if (isAitToolName(effective)) switch (effective) {
|
|
571
857
|
case "AIT.getMockState": return jsonResult(await getMockState(aitSource));
|
|
572
858
|
case "AIT.getOperationalEnvironment": return jsonResult(await getOperationalEnvironment(aitSource));
|
|
573
859
|
case "AIT.getSdkCallHistory": return jsonResult(await getSdkCallHistory(aitSource));
|
|
574
860
|
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
575
861
|
}
|
|
862
|
+
switch (name) {
|
|
863
|
+
case "list_pages": return jsonResult(buildDevListPagesResult(devtoolsUrl));
|
|
864
|
+
case "get_diagnostics": return jsonResult(await buildDevDiagnostics(devtoolsUrl, stateEndpoint, (url) => fetch(url)));
|
|
865
|
+
case "measure_safe_area": return jsonResult(await buildDevMeasureSafeArea(aitSource));
|
|
866
|
+
case "call_sdk": {
|
|
867
|
+
const sdkName = request.params.arguments?.name;
|
|
868
|
+
if (typeof sdkName !== "string" || sdkName === "") return mcpError("call_sdk: name 인자가 비어 있습니다. 호출할 메서드 이름을 전달하세요.");
|
|
869
|
+
return jsonResult(await buildDevCallSdk(sdkName, aitSource));
|
|
870
|
+
}
|
|
871
|
+
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
872
|
+
}
|
|
576
873
|
} catch (err) {
|
|
577
874
|
return mcpError(`${name} 실패: ${err instanceof Error ? err.message : String(err)}\nVite dev 서버가 @ait-co/devtools unplugin \`mcp: true\` 옵션으로 실행 중인지 확인하세요. AIT_DEVTOOLS_URL 환경변수가 올바르게 설정됐는지도 확인하세요.`);
|
|
578
875
|
}
|