@ait-co/devtools 0.1.43 → 0.1.45
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 +97 -7
- package/README.md +115 -7
- package/dist/mcp/cli.d.ts +8 -1
- package/dist/mcp/cli.d.ts.map +1 -1
- package/dist/mcp/cli.js +1163 -176
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +343 -41
- 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
|
@@ -38,6 +38,22 @@ var HttpAitSource = class {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
//#endregion
|
|
41
|
+
//#region src/mcp/errors.ts
|
|
42
|
+
/**
|
|
43
|
+
* 한국어 한 줄 "원인 + 다음 행동" 포맷으로 에러 결과를 빌드한다.
|
|
44
|
+
*
|
|
45
|
+
* @param message - 사용자에게 보여줄 에러 본문 (원인 + 다음 행동 포함).
|
|
46
|
+
*/
|
|
47
|
+
function mcpError(message) {
|
|
48
|
+
return {
|
|
49
|
+
content: [{
|
|
50
|
+
type: "text",
|
|
51
|
+
text: message
|
|
52
|
+
}],
|
|
53
|
+
isError: true
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
//#endregion
|
|
41
57
|
//#region src/mcp/sdk-signatures.ts
|
|
42
58
|
function isObject(v) {
|
|
43
59
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
@@ -198,7 +214,7 @@ new Set([
|
|
|
198
214
|
},
|
|
199
215
|
{
|
|
200
216
|
name: "list_pages",
|
|
201
|
-
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. 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.",
|
|
202
218
|
inputSchema: {
|
|
203
219
|
type: "object",
|
|
204
220
|
properties: {},
|
|
@@ -208,7 +224,7 @@ new Set([
|
|
|
208
224
|
},
|
|
209
225
|
{
|
|
210
226
|
name: "build_attach_url",
|
|
211
|
-
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 (set automatically when a relay tunnel is detected).",
|
|
212
228
|
inputSchema: {
|
|
213
229
|
type: "object",
|
|
214
230
|
properties: {
|
|
@@ -218,7 +234,7 @@ new Set([
|
|
|
218
234
|
},
|
|
219
235
|
wait_for_attach: {
|
|
220
236
|
type: "boolean",
|
|
221
|
-
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."
|
|
222
238
|
},
|
|
223
239
|
open_in_browser: {
|
|
224
240
|
type: "boolean",
|
|
@@ -251,7 +267,7 @@ new Set([
|
|
|
251
267
|
},
|
|
252
268
|
{
|
|
253
269
|
name: "take_screenshot",
|
|
254
|
-
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).",
|
|
255
271
|
inputSchema: {
|
|
256
272
|
type: "object",
|
|
257
273
|
properties: {},
|
|
@@ -271,13 +287,19 @@ new Set([
|
|
|
271
287
|
},
|
|
272
288
|
{
|
|
273
289
|
name: "evaluate",
|
|
274
|
-
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.",
|
|
275
291
|
inputSchema: {
|
|
276
292
|
type: "object",
|
|
277
|
-
properties: {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
+
},
|
|
281
303
|
required: ["expression"]
|
|
282
304
|
},
|
|
283
305
|
availableIn: "both"
|
|
@@ -297,7 +319,7 @@ new Set([
|
|
|
297
319
|
},
|
|
298
320
|
{
|
|
299
321
|
name: "call_sdk",
|
|
300
|
-
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\", [])",
|
|
301
323
|
inputSchema: {
|
|
302
324
|
type: "object",
|
|
303
325
|
properties: {
|
|
@@ -309,6 +331,10 @@ new Set([
|
|
|
309
331
|
type: "array",
|
|
310
332
|
description: "Arguments to pass to the SDK method (optional, default []).",
|
|
311
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."
|
|
312
338
|
}
|
|
313
339
|
},
|
|
314
340
|
required: ["name"]
|
|
@@ -344,6 +370,19 @@ new Set([
|
|
|
344
370
|
required: []
|
|
345
371
|
},
|
|
346
372
|
availableIn: "both"
|
|
373
|
+
},
|
|
374
|
+
{
|
|
375
|
+
name: "get_diagnostics",
|
|
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.",
|
|
377
|
+
inputSchema: {
|
|
378
|
+
type: "object",
|
|
379
|
+
properties: { recent_errors_limit: {
|
|
380
|
+
type: "number",
|
|
381
|
+
description: "Maximum number of recent server-side errors to include (default 10, max 50)."
|
|
382
|
+
} },
|
|
383
|
+
required: []
|
|
384
|
+
},
|
|
385
|
+
availableIn: "both"
|
|
347
386
|
}
|
|
348
387
|
].map((t) => t.name));
|
|
349
388
|
`
|
|
@@ -459,6 +498,27 @@ function getOperationalEnvironment(source) {
|
|
|
459
498
|
* (dev). `devtools_get_mock_state` (the original devtools#130 name) is kept as a
|
|
460
499
|
* backward-compatible alias of `AIT.getMockState`.
|
|
461
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
|
+
*
|
|
462
522
|
* This module is reached via the `devtools-mcp --mode=dev` CLI entry (see
|
|
463
523
|
* `cli.ts`); the default (no flag) bin mode is the debug-mode CDP/Chii server.
|
|
464
524
|
*
|
|
@@ -473,12 +533,18 @@ function getOperationalEnvironment(source) {
|
|
|
473
533
|
* }
|
|
474
534
|
* }
|
|
475
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 모드 기본)로 전환하세요.";
|
|
476
538
|
/**
|
|
477
539
|
* Tool descriptors served by the dev-mode server.
|
|
478
540
|
*
|
|
479
541
|
* All dev-mode tools are Tier C (both envs) per RFC #277 — the dev-mode server
|
|
480
542
|
* itself is the mock-side embodiment of those Tier C tools. `availableIn` is
|
|
481
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.
|
|
482
548
|
*/
|
|
483
549
|
const DEV_TOOL_DEFINITIONS = [
|
|
484
550
|
{
|
|
@@ -520,56 +586,292 @@ const DEV_TOOL_DEFINITIONS = [
|
|
|
520
586
|
required: []
|
|
521
587
|
},
|
|
522
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"
|
|
523
718
|
}
|
|
524
719
|
];
|
|
720
|
+
/** All tool names served in dev-mode (including tier-filter stubs). */
|
|
525
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
|
+
}
|
|
526
840
|
/** Builds the dev-mode MCP server (does not connect a transport). */
|
|
527
841
|
function createDevServer(deps = {}) {
|
|
528
|
-
const
|
|
842
|
+
const devtoolsUrl = process.env.AIT_DEVTOOLS_URL ?? "http://localhost:5173";
|
|
843
|
+
const stateEndpoint = `${devtoolsUrl}/api/ait-devtools/state`;
|
|
529
844
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
530
845
|
const server = new Server({
|
|
531
846
|
name: "ait-devtools",
|
|
532
|
-
version: "0.1.
|
|
847
|
+
version: "0.1.45"
|
|
533
848
|
}, { capabilities: { tools: {} } });
|
|
534
849
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
535
850
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
536
851
|
const name = request.params.name;
|
|
537
|
-
if (!DEV_TOOL_NAMES.has(name)) return {
|
|
538
|
-
|
|
539
|
-
type: "text",
|
|
540
|
-
text: `Unknown tool: ${name}`
|
|
541
|
-
}],
|
|
542
|
-
isError: true
|
|
543
|
-
};
|
|
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}`);
|
|
544
854
|
try {
|
|
545
855
|
const effective = name === "devtools_get_mock_state" ? "AIT.getMockState" : name;
|
|
546
|
-
if (
|
|
547
|
-
content: [{
|
|
548
|
-
type: "text",
|
|
549
|
-
text: `Unknown tool: ${name}`
|
|
550
|
-
}],
|
|
551
|
-
isError: true
|
|
552
|
-
};
|
|
553
|
-
switch (effective) {
|
|
856
|
+
if (isAitToolName(effective)) switch (effective) {
|
|
554
857
|
case "AIT.getMockState": return jsonResult(await getMockState(aitSource));
|
|
555
858
|
case "AIT.getOperationalEnvironment": return jsonResult(await getOperationalEnvironment(aitSource));
|
|
556
859
|
case "AIT.getSdkCallHistory": return jsonResult(await getSdkCallHistory(aitSource));
|
|
557
|
-
default: return {
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
860
|
+
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
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}`);
|
|
564
872
|
}
|
|
565
873
|
} catch (err) {
|
|
566
|
-
return {
|
|
567
|
-
content: [{
|
|
568
|
-
type: "text",
|
|
569
|
-
text: `${err instanceof Error ? err.message : String(err)}\nIs the Vite dev server running with the @ait-co/devtools unplugin option \`mcp: true\`? Is AIT_DEVTOOLS_URL set correctly?`
|
|
570
|
-
}],
|
|
571
|
-
isError: true
|
|
572
|
-
};
|
|
874
|
+
return mcpError(`${name} 실패: ${err instanceof Error ? err.message : String(err)}\nVite dev 서버가 @ait-co/devtools unplugin \`mcp: true\` 옵션으로 실행 중인지 확인하세요. AIT_DEVTOOLS_URL 환경변수가 올바르게 설정됐는지도 확인하세요.`);
|
|
573
875
|
}
|
|
574
876
|
});
|
|
575
877
|
return server;
|