@ait-co/devtools 0.1.46 → 0.1.48
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 +27 -8
- package/README.md +27 -8
- package/dist/mcp/cli.js +73 -17
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +114 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/panel/index.js +2 -2
- package/package.json +1 -1
package/README.en.md
CHANGED
|
@@ -70,12 +70,12 @@ No HMR (Toss WebView cold-load only). Details: [`docs/scenarios/env-3.md`](./doc
|
|
|
70
70
|
Attach a relay to a live OPENED app to observe runtime behavior.
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
devtools-mcp
|
|
73
|
+
MCP_ENV=relay-live devtools-mcp # start MCP server (LIVE guard enabled)
|
|
74
74
|
# call build_attach_url → scan QR → live app loads + relay attaches
|
|
75
|
-
# call_sdk / evaluate:
|
|
75
|
+
# call_sdk / evaluate: confirm: true required (LIVE guard — real users affected)
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
Details: [`docs/scenarios/env-4.md`](./docs/scenarios/env-4.md)
|
|
78
|
+
`MCP_ENV=relay-live` is required — without it the LIVE side-effect guard is inactive and SDK calls can affect real users. Details: [`docs/scenarios/env-4.md`](./docs/scenarios/env-4.md)
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
@@ -952,11 +952,12 @@ A local browser (env 1) and a phone Toss WebView (env 2/3) both speak CDP, so ev
|
|
|
952
952
|
|
|
953
953
|
| Mode + target | Invocation | Env var | Target | Tools |
|
|
954
954
|
|---|---|---|---|---|
|
|
955
|
-
| `--mode=debug --target=relay` (default) | `MCP_ENV=relay devtools-mcp` | `MCP_ENV=relay` recommended | Dogfood bundle on a phone (CDP/Chii relay + cloudflared tunnel, env
|
|
955
|
+
| `--mode=debug --target=relay` (default) | `MCP_ENV=relay-dev devtools-mcp` | `MCP_ENV=relay-dev` recommended (env 3, dogfood) | Dogfood bundle on a phone (CDP/Chii relay + cloudflared tunnel, env 3) | console/network/page + DOM/snapshot/screenshot + `AIT.*` |
|
|
956
|
+
| `--mode=debug --target=relay` LIVE | `MCP_ENV=relay-live devtools-mcp` | `MCP_ENV=relay-live` **required** (env 4, LIVE guard enabled) | Live deployed app (env 4) — `call_sdk`/`evaluate` require `confirm: true` | same |
|
|
956
957
|
| `--mode=debug --target=local` | `devtools-mcp --target=local` | `MCP_ENV=mock` (auto) | Local Chromium launched by the MCP server (CDP direct-attach, no relay needed, env 1) | same |
|
|
957
958
|
| `--mode=dev` | `devtools-mcp --mode=dev` | `MCP_ENV=mock` (auto) | Mock state from a running Vite dev server (AIT.* only, no CDP) | `AIT.*` (+ `devtools_get_mock_state` alias) |
|
|
958
959
|
|
|
959
|
-
`--target=local` opens `AIT_DEVTOOLS_URL` (default `http://localhost:5173`) and attaches directly to a local Chromium — no relay or tunnel required. `--mode=dev` reads the mock-state HTTP endpoint of the Vite dev server and does not provide CDP tools. For on-device sessions (env 3
|
|
960
|
+
`--target=local` opens `AIT_DEVTOOLS_URL` (default `http://localhost:5173`) and attaches directly to a local Chromium — no relay or tunnel required. `--mode=dev` reads the mock-state HTTP endpoint of the Vite dev server and does not provide CDP tools. For on-device sessions (env 3), setting `MCP_ENV=relay-dev` explicitly ensures the relay tool surface is visible before the tunnel URL is auto-detected. For env 4 (LIVE), `MCP_ENV=relay-live` is required — only this value activates the LIVE side-effect guard that protects real users.
|
|
960
961
|
|
|
961
962
|
### Debug mode (CDP via Chii)
|
|
962
963
|
|
|
@@ -966,6 +967,24 @@ Read-only tools only. Tools are registered in two tiers based on attach state
|
|
|
966
967
|
|
|
967
968
|
Running `devtools-mcp` as a stdio server starts a local Chii relay on an OS-assigned port and opens a cloudflared quick tunnel, printing a public `wss://*.trycloudflare.com` URL and a QR code in the terminal (secrets/auth codes are never printed). When the phone enters the dogfood entry point, the in-app attach UI connects to the relay with that URL, and the agent reads console/network/page state via `chrome-devtools-mcp`-compatible tools — diagnosing regressions without anyone watching the phone.
|
|
968
969
|
|
|
970
|
+
Environment 3 (dogfood relay):
|
|
971
|
+
|
|
972
|
+
```json
|
|
973
|
+
{
|
|
974
|
+
"mcpServers": {
|
|
975
|
+
"ait-debug": {
|
|
976
|
+
"command": "pnpm",
|
|
977
|
+
"args": ["exec", "devtools-mcp"],
|
|
978
|
+
"env": {
|
|
979
|
+
"MCP_ENV": "relay-dev"
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
Environment 4 (LIVE relay, LIVE guard enabled):
|
|
987
|
+
|
|
969
988
|
```json
|
|
970
989
|
{
|
|
971
990
|
"mcpServers": {
|
|
@@ -973,14 +992,14 @@ Running `devtools-mcp` as a stdio server starts a local Chii relay on an OS-assi
|
|
|
973
992
|
"command": "pnpm",
|
|
974
993
|
"args": ["exec", "devtools-mcp"],
|
|
975
994
|
"env": {
|
|
976
|
-
"MCP_ENV": "relay"
|
|
995
|
+
"MCP_ENV": "relay-live"
|
|
977
996
|
}
|
|
978
997
|
}
|
|
979
998
|
}
|
|
980
999
|
}
|
|
981
1000
|
```
|
|
982
1001
|
|
|
983
|
-
Setting `MCP_ENV=relay` explicitly ensures the relay tool surface is visible before the tunnel URL is auto-detected.
|
|
1002
|
+
Setting `MCP_ENV=relay-dev` explicitly ensures the relay tool surface is visible before the tunnel URL is auto-detected. `MCP_ENV=relay-live` activates the LIVE side-effect guard — any `call_sdk`/`evaluate` call without `confirm: true` is rejected to protect real users. `MCP_ENV=relay` is a backward-compat alias for `relay-dev`, so **always use `relay-live` explicitly for env 4**.
|
|
984
1003
|
|
|
985
1004
|
| Tool | CDP / AIT backing | Description |
|
|
986
1005
|
|---|---|---|
|
|
@@ -993,7 +1012,7 @@ Setting `MCP_ENV=relay` explicitly ensures the relay tool surface is visible bef
|
|
|
993
1012
|
| `take_screenshot` | `Page.captureScreenshot` | Page PNG screenshot (returned as an MCP image content block) |
|
|
994
1013
|
| `measure_safe_area` | `Runtime.evaluate` | Runs a safe-area probe on the attached page → returns normalized safe-area insets, viewport geometry, DPR, and User-Agent. Read-only. Use in a relay session to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires attach (`list_pages` first) |
|
|
995
1014
|
| `evaluate` | `Runtime.evaluate` | Evaluates an arbitrary JS expression on the attached page (returnByValue) and returns the result. **Not read-only** — the expression can have side effects (DOM mutations, SDK calls, state changes). Requires attach |
|
|
996
|
-
| `call_sdk` | `window.__sdkCall` bridge (via `Runtime.evaluate`) | Calls a dogfood SDK method via the `window.__sdkCall` bridge (exported by `@apps-in-toss/web-framework` in `__DEBUG_BUILD__` bundles only). **Not read-only** — SDK calls have side effects (navigation, payments, permissions, etc.). Hits the real SDK on env
|
|
1015
|
+
| `call_sdk` | `window.__sdkCall` bridge (via `Runtime.evaluate`) | Calls a dogfood SDK method via the `window.__sdkCall` bridge (exported by `@apps-in-toss/web-framework` in `__DEBUG_BUILD__` bundles only). **Not read-only** — SDK calls have side effects (navigation, payments, permissions, etc.). Hits the real SDK on env 3/4, mock SDK on env 1. Env 2 (PWA) does not inject the SDK — not available there. On env 4, `confirm: true` is required (LIVE guard). Requires attach. Returns `{ok,value}` / `{ok,error}` |
|
|
997
1016
|
| `AIT.getSdkCallHistory` | AIT domain | SDK call trace (method, args, result/error, timestamp) |
|
|
998
1017
|
| `AIT.getMockState` | AIT domain | Mock state snapshot (`window.__ait`) |
|
|
999
1018
|
| `AIT.getOperationalEnvironment` | AIT domain | `getOperationalEnvironment()` + SDK version |
|
package/README.md
CHANGED
|
@@ -70,12 +70,12 @@ HMR 없음(토스 WebView cold-load만). 상세: [`docs/scenarios/env-3.md`](./d
|
|
|
70
70
|
검수를 통과하고 OPENED 상태인 실 출시 앱에 relay를 붙여 런타임을 관측합니다.
|
|
71
71
|
|
|
72
72
|
```bash
|
|
73
|
-
devtools-mcp
|
|
73
|
+
MCP_ENV=relay-live devtools-mcp # MCP 서버 시작 (LIVE guard 활성화)
|
|
74
74
|
# build_attach_url 호출 → QR 스캔 → LIVE 앱 로드 + relay attach
|
|
75
|
-
# call_sdk / evaluate 는
|
|
75
|
+
# call_sdk / evaluate 는 confirm: true 필수 (LIVE guard — 실유저 영향)
|
|
76
76
|
```
|
|
77
77
|
|
|
78
|
-
상세: [`docs/scenarios/env-4.md`](./docs/scenarios/env-4.md)
|
|
78
|
+
`MCP_ENV=relay-live` 필수 — 미설정 시 LIVE side-effect guard가 비활성화되어 실유저에게 영향을 줄 수 있습니다. 상세: [`docs/scenarios/env-4.md`](./docs/scenarios/env-4.md)
|
|
79
79
|
|
|
80
80
|
---
|
|
81
81
|
|
|
@@ -982,11 +982,12 @@ AI 코딩 에이전트(Claude Code, Cursor 등)가 [MCP(Model Context Protocol)]
|
|
|
982
982
|
|
|
983
983
|
| 모드 + 타깃 | 호출 | 환경 변수 | 대상 | tool |
|
|
984
984
|
|---|---|---|---|---|
|
|
985
|
-
| `--mode=debug --target=relay` (기본값) | `MCP_ENV=relay devtools-mcp` | `MCP_ENV=relay` 권장 | 폰 안 dogfood 번들 (CDP/Chii relay + cloudflared 터널, 환경
|
|
985
|
+
| `--mode=debug --target=relay` (기본값) | `MCP_ENV=relay-dev devtools-mcp` | `MCP_ENV=relay-dev` 권장 (환경 3, dogfood) | 폰 안 dogfood 번들 (CDP/Chii relay + cloudflared 터널, 환경 3) | console/network/page + DOM/snapshot/screenshot + `AIT.*` |
|
|
986
|
+
| `--mode=debug --target=relay` LIVE | `MCP_ENV=relay-live devtools-mcp` | `MCP_ENV=relay-live` **필수** (환경 4, LIVE guard 활성화) | LIVE 배포 앱 (환경 4) — `call_sdk`/`evaluate`에 `confirm: true` 필요 | 동일 |
|
|
986
987
|
| `--mode=debug --target=local` | `devtools-mcp --target=local` | `MCP_ENV=mock` (자동) | MCP가 직접 기동한 로컬 Chromium (CDP direct-attach, relay 불필요, 환경 1) | 동일 |
|
|
987
988
|
| `--mode=dev` | `devtools-mcp --mode=dev` | `MCP_ENV=mock` (자동) | 실행 중인 Vite dev server의 mock state (AIT.* 전용, CDP 없음) | `AIT.*` (+ `devtools_get_mock_state` alias) |
|
|
988
989
|
|
|
989
|
-
`--target=local`은 `AIT_DEVTOOLS_URL`(기본 `http://localhost:5173`)을 열고 로컬 Chromium에 CDP direct-attach합니다 — relay나 터널이 필요하지 않습니다. `--mode=dev`는 Vite dev server의 mock-state HTTP endpoint를 읽으며 CDP tool은 제공하지 않습니다. 실기기(환경 3
|
|
990
|
+
`--target=local`은 `AIT_DEVTOOLS_URL`(기본 `http://localhost:5173`)을 열고 로컬 Chromium에 CDP direct-attach합니다 — relay나 터널이 필요하지 않습니다. `--mode=dev`는 Vite dev server의 mock-state HTTP endpoint를 읽으며 CDP tool은 제공하지 않습니다. 실기기(환경 3) 진입 시 `MCP_ENV=relay-dev`를 명시하면 터널 감지 전에도 relay tool이 올바르게 노출됩니다. 환경 4(LIVE)는 `MCP_ENV=relay-live` 필수 — LIVE side-effect guard(실유저 보호)가 이 값일 때만 활성화됩니다.
|
|
990
991
|
|
|
991
992
|
### Debug 모드 (CDP via Chii)
|
|
992
993
|
|
|
@@ -1004,6 +1005,24 @@ tunnel로 공개 `wss://*.trycloudflare.com` URL을 발급한 뒤 QR을 터미
|
|
|
1004
1005
|
에이전트가 `chrome-devtools-mcp` 호환 tool로 console/network/page 상태를 read합니다. 사람이 폰을
|
|
1005
1006
|
지켜볼 필요 없이 회귀를 단독 진단하는 것이 목표입니다.
|
|
1006
1007
|
|
|
1008
|
+
환경 3 (dogfood relay):
|
|
1009
|
+
|
|
1010
|
+
```json
|
|
1011
|
+
{
|
|
1012
|
+
"mcpServers": {
|
|
1013
|
+
"ait-debug": {
|
|
1014
|
+
"command": "pnpm",
|
|
1015
|
+
"args": ["exec", "devtools-mcp"],
|
|
1016
|
+
"env": {
|
|
1017
|
+
"MCP_ENV": "relay-dev"
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
환경 4 (LIVE relay, LIVE guard 활성화):
|
|
1025
|
+
|
|
1007
1026
|
```json
|
|
1008
1027
|
{
|
|
1009
1028
|
"mcpServers": {
|
|
@@ -1011,14 +1030,14 @@ tunnel로 공개 `wss://*.trycloudflare.com` URL을 발급한 뒤 QR을 터미
|
|
|
1011
1030
|
"command": "pnpm",
|
|
1012
1031
|
"args": ["exec", "devtools-mcp"],
|
|
1013
1032
|
"env": {
|
|
1014
|
-
"MCP_ENV": "relay"
|
|
1033
|
+
"MCP_ENV": "relay-live"
|
|
1015
1034
|
}
|
|
1016
1035
|
}
|
|
1017
1036
|
}
|
|
1018
1037
|
}
|
|
1019
1038
|
```
|
|
1020
1039
|
|
|
1021
|
-
`MCP_ENV=relay`를 명시하면 터널 URL 자동 감지 전에도 relay tool surface가 올바르게 노출됩니다.
|
|
1040
|
+
`MCP_ENV=relay-dev`를 명시하면 터널 URL 자동 감지 전에도 relay tool surface가 올바르게 노출됩니다. `MCP_ENV=relay-live`는 LIVE side-effect guard를 활성화합니다 — `call_sdk`/`evaluate`에 `confirm: true`가 없으면 거부하여 실유저 영향을 방지합니다. `MCP_ENV=relay`는 backward-compat alias로 `relay-dev`로 해석되므로 **환경 4에서는 `relay-live`를 명시해야 합니다**.
|
|
1022
1041
|
|
|
1023
1042
|
| Tool | CDP / AIT 백킹 | 설명 |
|
|
1024
1043
|
|---|---|---|
|
|
@@ -1031,7 +1050,7 @@ tunnel로 공개 `wss://*.trycloudflare.com` URL을 발급한 뒤 QR을 터미
|
|
|
1031
1050
|
| `take_screenshot` | `Page.captureScreenshot` | 페이지 PNG 스크린샷 (MCP image content block 반환) |
|
|
1032
1051
|
| `measure_safe_area` | `Runtime.evaluate` | attach된 페이지에서 safe-area 프로브 실행 → 정규화된 safe-area inset·뷰포트 geometry·DPR·User-Agent 반환. read-only. relay 세션(폰 attach)에서 viewport preset을 extrapolated/placeholder→measured로 승급할 ground truth 수집용. attach 필요 (`list_pages` 먼저) |
|
|
1033
1052
|
| `evaluate` | `Runtime.evaluate` | attach된 페이지에서 임의 JS 표현식 평가(returnByValue) → 결과 반환. **read-only 아님** — 표현식이 부작용(DOM 변경·SDK 호출·상태 변경)을 일으킬 수 있음. attach 필요 |
|
|
1034
|
-
| `call_sdk` | `window.__sdkCall` 브리지 (`Runtime.evaluate` 경유) | dogfood SDK 메서드를 `window.__sdkCall` 브리지로 호출 (`@apps-in-toss/web-framework`가 `__DEBUG_BUILD__` 번들에서만 export). **read-only 아님** — SDK 호출은 부작용(내비게이션·결제·권한 등). 환경
|
|
1053
|
+
| `call_sdk` | `window.__sdkCall` 브리지 (`Runtime.evaluate` 경유) | dogfood SDK 메서드를 `window.__sdkCall` 브리지로 호출 (`@apps-in-toss/web-framework`가 `__DEBUG_BUILD__` 번들에서만 export). **read-only 아님** — SDK 호출은 부작용(내비게이션·결제·권한 등). 환경 3·4(실기기 relay)에선 실 SDK, 환경 1(로컬 mock)에선 mock SDK. 환경 2(PWA)는 SDK 미주입으로 사용 불가. 환경 4에서는 `confirm: true` 필수(LIVE guard). attach 필요. `{ok,value}` / `{ok,error}` 반환 |
|
|
1035
1054
|
| `AIT.getSdkCallHistory` | AIT 도메인 | SDK 호출 trace (method, args, result/error, timestamp) |
|
|
1036
1055
|
| `AIT.getMockState` | AIT 도메인 | mock state 스냅샷 (`window.__ait`) |
|
|
1037
1056
|
| `AIT.getOperationalEnvironment` | AIT 도메인 | `getOperationalEnvironment()` + SDK 버전 |
|
package/dist/mcp/cli.js
CHANGED
|
@@ -2223,7 +2223,7 @@ const DEBUG_TOOL_DEFINITIONS = [
|
|
|
2223
2223
|
},
|
|
2224
2224
|
{
|
|
2225
2225
|
name: "measure_safe_area",
|
|
2226
|
-
description: "Runs a safe-area probe on the attached mini-app page via Runtime.evaluate and returns normalized safe-area insets, viewport geometry, device pixel ratio, and User-Agent. Read-only — does not modify page state. Tier C per RFC #277: the same Runtime.evaluate probe runs in both `mock` (devtools panel page with window.__ait state) and `relay` (real-device WebView with window.__sdk). The result includes a `source: \"mock\" | \"relay\"` field so consumers can identify provenance without inspecting payload values. Use in a relay session (phone attached) to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires a page to be attached — call list_pages first.",
|
|
2226
|
+
description: "Runs a safe-area probe on the attached mini-app page via Runtime.evaluate and returns normalized safe-area insets, viewport geometry, device pixel ratio, and User-Agent. Read-only — does not modify page state. Tier C per RFC #277: the same Runtime.evaluate probe runs in both `mock` (devtools panel page with window.__ait state) and `relay` (real-device WebView with window.__sdk). The result includes a `source: \"mock\" | \"relay-dev\" | \"relay-live\"` field so consumers can identify provenance without inspecting payload values. Use in a relay session (phone attached) to get ground-truth values for upgrading a viewport preset from extrapolated/placeholder to measured. Requires a page to be attached — call list_pages first.",
|
|
2227
2227
|
inputSchema: {
|
|
2228
2228
|
type: "object",
|
|
2229
2229
|
properties: {},
|
|
@@ -2265,7 +2265,7 @@ const DEBUG_TOOL_DEFINITIONS = [
|
|
|
2265
2265
|
},
|
|
2266
2266
|
{
|
|
2267
2267
|
name: "call_sdk",
|
|
2268
|
-
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
|
|
2268
|
+
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 3/4 (real device relay) this hits the real SDK; on env 1 (local mock) it hits the mock SDK. (env 2 PWA does not inject the SDK — call_sdk is not available there.) 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\", [])",
|
|
2269
2269
|
inputSchema: {
|
|
2270
2270
|
type: "object",
|
|
2271
2271
|
properties: {
|
|
@@ -2319,7 +2319,7 @@ const DEBUG_TOOL_DEFINITIONS = [
|
|
|
2319
2319
|
},
|
|
2320
2320
|
{
|
|
2321
2321
|
name: "get_diagnostics",
|
|
2322
|
-
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.",
|
|
2322
|
+
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; in local-target mode tunnel.up=false is normal so \"restart\" is never recommended). 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.",
|
|
2323
2323
|
inputSchema: {
|
|
2324
2324
|
type: "object",
|
|
2325
2325
|
properties: { recent_errors_limit: {
|
|
@@ -3148,7 +3148,8 @@ function readDevtoolsVersion() {
|
|
|
3148
3148
|
* Derives the next recommended action from a completed diagnostics snapshot.
|
|
3149
3149
|
*
|
|
3150
3150
|
* Branch rules (evaluated in priority order):
|
|
3151
|
-
* 1. tunnel.up === false
|
|
3151
|
+
* 1. tunnel.up === false AND env is relay → restart (relay needs a live tunnel)
|
|
3152
|
+
* 1b. tunnel.up === false AND env is mock → wait_for_page (local target: tunnel-less is normal)
|
|
3152
3153
|
* 2. tunnel.up, pages empty, env === relay → build_attach_url (start attach)
|
|
3153
3154
|
* 3. pages has entry + crashDetectedAt non-null → build_attach_url (re-attach after crash)
|
|
3154
3155
|
* 4. otherwise → null (session looks healthy)
|
|
@@ -3156,7 +3157,12 @@ function readDevtoolsVersion() {
|
|
|
3156
3157
|
* Pure — does not throw; receives the final assembled snapshot fields.
|
|
3157
3158
|
*/
|
|
3158
3159
|
function computeNextRecommendedAction(tunnel, pages, env) {
|
|
3159
|
-
if (!tunnel.up)
|
|
3160
|
+
if (!tunnel.up) if (!isRelayEnv(env)) {
|
|
3161
|
+
if (pages !== null && pages.pages.length === 0 && !pages.crashDetectedAt) return {
|
|
3162
|
+
tool: "wait_for_page",
|
|
3163
|
+
reason: "local Chromium spawn 직후 — 페이지 로드를 기다리거나 list_pages를 재호출하세요 (local 모드는 tunnel이 없는 게 정상입니다)"
|
|
3164
|
+
};
|
|
3165
|
+
} else return {
|
|
3160
3166
|
tool: "restart",
|
|
3161
3167
|
reason: "tunnel not up — run `npx @ait-co/devtools devtools-mcp` to restart"
|
|
3162
3168
|
};
|
|
@@ -3605,7 +3611,7 @@ function createDebugServer(deps) {
|
|
|
3605
3611
|
const collector = collectorDep ?? new InMemoryDiagnosticsCollector();
|
|
3606
3612
|
const server = new Server({
|
|
3607
3613
|
name: "ait-debug",
|
|
3608
|
-
version: "0.1.
|
|
3614
|
+
version: "0.1.48"
|
|
3609
3615
|
}, { capabilities: { tools: { listChanged: true } } });
|
|
3610
3616
|
server.setRequestHandler(ListToolsRequestSchema, () => {
|
|
3611
3617
|
const env = resolveEnvironment();
|
|
@@ -3659,7 +3665,7 @@ function createDebugServer(deps) {
|
|
|
3659
3665
|
recentErrorsLimit
|
|
3660
3666
|
});
|
|
3661
3667
|
const attached = connection.listTargets().length > 0;
|
|
3662
|
-
return envelopeResult(result, name, resolveEnvironment(), attached);
|
|
3668
|
+
return envelopeResult$1(result, name, resolveEnvironment(), attached);
|
|
3663
3669
|
} catch (err) {
|
|
3664
3670
|
return errorResult(err, name);
|
|
3665
3671
|
}
|
|
@@ -3839,7 +3845,7 @@ ${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stder
|
|
|
3839
3845
|
} catch {}
|
|
3840
3846
|
const pagesData = listPages(connection, getTunnelStatus());
|
|
3841
3847
|
const attached = connection.listTargets().length > 0;
|
|
3842
|
-
return envelopeResult(pagesData, name, resolveEnvironment(), attached);
|
|
3848
|
+
return envelopeResult$1(pagesData, name, resolveEnvironment(), attached);
|
|
3843
3849
|
}
|
|
3844
3850
|
return classifyEnableDomainError(err, name);
|
|
3845
3851
|
}
|
|
@@ -3857,7 +3863,7 @@ ${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stder
|
|
|
3857
3863
|
} catch {}
|
|
3858
3864
|
const listPagesData = listPages(connection, getTunnelStatus());
|
|
3859
3865
|
const listPagesAttached = connection.listTargets().length > 0;
|
|
3860
|
-
return envelopeResult(listPagesData, name, resolveEnvironment(), listPagesAttached);
|
|
3866
|
+
return envelopeResult$1(listPagesData, name, resolveEnvironment(), listPagesAttached);
|
|
3861
3867
|
}
|
|
3862
3868
|
case "get_dom_document": return jsonResult$1(await getDomDocument(connection));
|
|
3863
3869
|
case "take_snapshot": return jsonResult$1(await takeSnapshot(connection));
|
|
@@ -3872,7 +3878,7 @@ ${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stder
|
|
|
3872
3878
|
case "measure_safe_area": {
|
|
3873
3879
|
const safeAreaData = await measureSafeArea(connection, resolveEnvironment());
|
|
3874
3880
|
const safeAreaAttached = connection.listTargets().length > 0;
|
|
3875
|
-
return envelopeResult(safeAreaData, name, resolveEnvironment(), safeAreaAttached);
|
|
3881
|
+
return envelopeResult$1(safeAreaData, name, resolveEnvironment(), safeAreaAttached);
|
|
3876
3882
|
}
|
|
3877
3883
|
case "evaluate": {
|
|
3878
3884
|
const expression = request.params.arguments?.expression;
|
|
@@ -3889,7 +3895,7 @@ ${browserResult.httpUrl}\n또는 PNG로 받기: ${browserResult.pngUrl}` + stder
|
|
|
3889
3895
|
const sdkResult = await callSdk(connection, sdkName, sdkArgs);
|
|
3890
3896
|
if (!sdkResult.ok && typeof sdkResult.error === "string" && sdkResult.error.startsWith("sdk-absent:")) return sdkAbsentError("call_sdk");
|
|
3891
3897
|
const callSdkAttached = connection.listTargets().length > 0;
|
|
3892
|
-
return envelopeResult(sdkResult, name, resolveEnvironment(), callSdkAttached);
|
|
3898
|
+
return envelopeResult$1(sdkResult, name, resolveEnvironment(), callSdkAttached);
|
|
3893
3899
|
}
|
|
3894
3900
|
default: return unknownTool(name);
|
|
3895
3901
|
}
|
|
@@ -3910,7 +3916,7 @@ function jsonResult$1(value) {
|
|
|
3910
3916
|
* as a text content block. When `AIT_MCP_COMPAT=chrome-devtools` is set the
|
|
3911
3917
|
* envelope is skipped and the raw value is returned — identical to `jsonResult`.
|
|
3912
3918
|
*/
|
|
3913
|
-
function envelopeResult(value, tool, env, attached) {
|
|
3919
|
+
function envelopeResult$1(value, tool, env, attached) {
|
|
3914
3920
|
const wrapped = wrapEnvelope(value, {
|
|
3915
3921
|
tool,
|
|
3916
3922
|
env,
|
|
@@ -4419,6 +4425,29 @@ const DEV_TOOL_DEFINITIONS = [
|
|
|
4419
4425
|
},
|
|
4420
4426
|
availableIn: "both"
|
|
4421
4427
|
},
|
|
4428
|
+
{
|
|
4429
|
+
name: "build_attach_url",
|
|
4430
|
+
description: "Turns an `ait deploy --scheme-only` URL into a self-attaching deep link for a real device. NOT available in dev-mode — requires a live cloudflared relay (Tier B, relay-only). To use this tool: restart the MCP server with `--mode=debug` (or omit --mode) and set MCP_ENV=relay, then call build_attach_url to generate the QR for phone scanning. See: https://docs.aitc.dev/guides/debug-relay",
|
|
4431
|
+
inputSchema: {
|
|
4432
|
+
type: "object",
|
|
4433
|
+
properties: {
|
|
4434
|
+
scheme_url: {
|
|
4435
|
+
type: "string",
|
|
4436
|
+
description: "The intoss-private:// URL from `ait deploy --scheme-only`."
|
|
4437
|
+
},
|
|
4438
|
+
wait_for_attach: {
|
|
4439
|
+
type: "boolean",
|
|
4440
|
+
description: "If true, block until a page attaches."
|
|
4441
|
+
},
|
|
4442
|
+
open_in_browser: {
|
|
4443
|
+
type: "boolean",
|
|
4444
|
+
description: "If true (default), open the QR PNG in the OS browser."
|
|
4445
|
+
}
|
|
4446
|
+
},
|
|
4447
|
+
required: ["scheme_url"]
|
|
4448
|
+
},
|
|
4449
|
+
availableIn: "relay"
|
|
4450
|
+
},
|
|
4422
4451
|
{
|
|
4423
4452
|
name: "evaluate",
|
|
4424
4453
|
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.",
|
|
@@ -4509,6 +4538,12 @@ const CDP_ONLY_TOOL_NAMES = new Set([
|
|
|
4509
4538
|
"list_exceptions"
|
|
4510
4539
|
]);
|
|
4511
4540
|
/**
|
|
4541
|
+
* Tier B tools — relay-only per RFC #277.
|
|
4542
|
+
* Listed in dev-mode tool surface (issue #323) so agents get a hand-off hint
|
|
4543
|
+
* toward `--mode=debug` instead of "Unknown tool".
|
|
4544
|
+
*/
|
|
4545
|
+
const TIER_B_TOOL_NAMES = new Set(["build_attach_url"]);
|
|
4546
|
+
/**
|
|
4512
4547
|
* Builds the `list_pages` dev-mode shim response.
|
|
4513
4548
|
* Returns the Vite dev URL as a single-entry page list with `devMode: true`.
|
|
4514
4549
|
*/
|
|
@@ -4623,13 +4658,14 @@ function createDevServer(deps = {}) {
|
|
|
4623
4658
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
4624
4659
|
const server = new Server({
|
|
4625
4660
|
name: "ait-devtools",
|
|
4626
|
-
version: "0.1.
|
|
4661
|
+
version: "0.1.48"
|
|
4627
4662
|
}, { capabilities: { tools: {} } });
|
|
4628
4663
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
4629
4664
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
4630
4665
|
const name = request.params.name;
|
|
4631
4666
|
if (!DEV_TOOL_NAMES.has(name)) return mcpError(`알 수 없는 tool: ${name}`);
|
|
4632
4667
|
if (CDP_ONLY_TOOL_NAMES.has(name)) return mcpError(`${name}: ${CDP_UNAVAILABLE_IN_DEV_MODE}`);
|
|
4668
|
+
if (TIER_B_TOOL_NAMES.has(name)) return tierRejectionError(name, "relay", "mock", "dev-mode — Vite HTTP endpoint, no CDP/relay connection. `--mode=debug` (または `devtools-mcp` without --mode) + MCP_ENV=relay로 재시작하세요.");
|
|
4633
4669
|
try {
|
|
4634
4670
|
const effective = name === "devtools_get_mock_state" ? "AIT.getMockState" : name;
|
|
4635
4671
|
if (isAitToolName(effective)) switch (effective) {
|
|
@@ -4639,13 +4675,13 @@ function createDevServer(deps = {}) {
|
|
|
4639
4675
|
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
4640
4676
|
}
|
|
4641
4677
|
switch (name) {
|
|
4642
|
-
case "list_pages": return
|
|
4643
|
-
case "get_diagnostics": return
|
|
4644
|
-
case "measure_safe_area": return
|
|
4678
|
+
case "list_pages": return envelopeResult("list_pages", buildDevListPagesResult(devtoolsUrl));
|
|
4679
|
+
case "get_diagnostics": return envelopeResult("get_diagnostics", await buildDevDiagnostics(devtoolsUrl, stateEndpoint, (url) => fetch(url)));
|
|
4680
|
+
case "measure_safe_area": return envelopeResult("measure_safe_area", await buildDevMeasureSafeArea(aitSource));
|
|
4645
4681
|
case "call_sdk": {
|
|
4646
4682
|
const sdkName = request.params.arguments?.name;
|
|
4647
4683
|
if (typeof sdkName !== "string" || sdkName === "") return mcpError("call_sdk: name 인자가 비어 있습니다. 호출할 메서드 이름을 전달하세요.");
|
|
4648
|
-
return
|
|
4684
|
+
return envelopeResult("call_sdk", await buildDevCallSdk(sdkName, aitSource));
|
|
4649
4685
|
}
|
|
4650
4686
|
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
4651
4687
|
}
|
|
@@ -4661,6 +4697,26 @@ function jsonResult(value) {
|
|
|
4661
4697
|
text: JSON.stringify(value, null, 2)
|
|
4662
4698
|
}] };
|
|
4663
4699
|
}
|
|
4700
|
+
/**
|
|
4701
|
+
* Wraps `value` in a `ToolEnvelope` (when compat mode is off) and returns it
|
|
4702
|
+
* as a text content block. In dev-mode `env` is always `'mock'` and
|
|
4703
|
+
* `attached` is always `true` (the Vite dev server is the single implicit
|
|
4704
|
+
* "attached" page).
|
|
4705
|
+
*
|
|
4706
|
+
* When `AIT_MCP_COMPAT=chrome-devtools` the envelope is skipped and the raw
|
|
4707
|
+
* value is returned — identical to `jsonResult` (0.1.x back-compat).
|
|
4708
|
+
*/
|
|
4709
|
+
function envelopeResult(tool, value) {
|
|
4710
|
+
const wrapped = wrapEnvelope(value, {
|
|
4711
|
+
tool,
|
|
4712
|
+
env: "mock",
|
|
4713
|
+
attached: true
|
|
4714
|
+
});
|
|
4715
|
+
return { content: [{
|
|
4716
|
+
type: "text",
|
|
4717
|
+
text: JSON.stringify(wrapped, null, 2)
|
|
4718
|
+
}] };
|
|
4719
|
+
}
|
|
4664
4720
|
/** Builds the dev-mode server and connects it over stdio. */
|
|
4665
4721
|
async function runDevServer() {
|
|
4666
4722
|
const server = createDevServer();
|