@ait-co/devtools 0.1.45 → 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 +31 -8
- package/README.md +31 -8
- package/dist/mcp/cli.js +270 -106
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +115 -9
- 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;;;UC6P/C,mBAAA;ED9PS;ECgQxB,SAAA,GAAY,SAAA;AAAA;;iBA8IE,eAAA,CAAgB,IAAA,GAAM,mBAAA,GAA2B,MAAA;;iBAqH3C,YAAA,CAAA,GAAgB,OAAA"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -38,6 +38,51 @@ var HttpAitSource = class {
|
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
//#endregion
|
|
41
|
+
//#region src/mcp/envelope.ts
|
|
42
|
+
/**
|
|
43
|
+
* Returns `true` when `AIT_MCP_COMPAT=chrome-devtools` is set, which bypasses
|
|
44
|
+
* envelope wrapping and returns raw payloads (0.1.x back-compat).
|
|
45
|
+
*/
|
|
46
|
+
function isCompatMode() {
|
|
47
|
+
return process.env.AIT_MCP_COMPAT === "chrome-devtools";
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Maps `McpEnvironment` to `EnvelopeEnv`. After #307 these are the same
|
|
51
|
+
* union (`mock | relay-dev | relay-live`), so this is identity — kept as a
|
|
52
|
+
* named export for surface stability if envelope env diverges in the future.
|
|
53
|
+
*/
|
|
54
|
+
function toEnvelopeEnv(env) {
|
|
55
|
+
return env;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Wraps `data` in a `ToolEnvelope<T>` **unless** compat mode is active, in
|
|
59
|
+
* which case `data` is returned as-is.
|
|
60
|
+
*
|
|
61
|
+
* Use this at every tool call-site in `debug-server.ts` and `server.ts`.
|
|
62
|
+
*
|
|
63
|
+
* @example
|
|
64
|
+
* ```ts
|
|
65
|
+
* return jsonResult(wrapEnvelope(listPages(connection, tunnel), {
|
|
66
|
+
* tool: 'list_pages',
|
|
67
|
+
* env: resolveEnvironment(),
|
|
68
|
+
* attached: connection.listTargets().length > 0,
|
|
69
|
+
* }));
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
function wrapEnvelope(data, ctx) {
|
|
73
|
+
if (isCompatMode()) return data;
|
|
74
|
+
return {
|
|
75
|
+
ok: true,
|
|
76
|
+
data,
|
|
77
|
+
meta: {
|
|
78
|
+
tool: ctx.tool,
|
|
79
|
+
env: toEnvelopeEnv(ctx.env),
|
|
80
|
+
attached: ctx.attached,
|
|
81
|
+
contentType: ctx.contentType ?? "json"
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
41
86
|
//#region src/mcp/errors.ts
|
|
42
87
|
/**
|
|
43
88
|
* 한국어 한 줄 "원인 + 다음 행동" 포맷으로 에러 결과를 빌드한다.
|
|
@@ -53,6 +98,17 @@ function mcpError(message) {
|
|
|
53
98
|
isError: true
|
|
54
99
|
};
|
|
55
100
|
}
|
|
101
|
+
/**
|
|
102
|
+
* Tier A/B 환경 불일치 거부 메시지.
|
|
103
|
+
*
|
|
104
|
+
* @param toolName - 거부된 tool 이름.
|
|
105
|
+
* @param requiredEnv - 해당 tool이 요구하는 환경 ('mock' | 'relay').
|
|
106
|
+
* @param currentEnv - 현재 세션 환경.
|
|
107
|
+
* @param reason - 환경이 결정된 근거 (EnvironmentReason 문자열).
|
|
108
|
+
*/
|
|
109
|
+
function tierRejectionError(toolName, requiredEnv, currentEnv, reason) {
|
|
110
|
+
return mcpError(`${`${toolName}은 ${requiredEnv === "relay" ? "relay (실기기 연결)" : "mock (로컬 브라우저)"} 환경에서만 사용할 수 있습니다. 현재 환경: ${currentEnv === "relay" ? "relay" : "mock"} (${reason}). ${requiredEnv === "relay" ? "relay로 전환하려면 MCP_ENV=relay 설정 후 서버를 재시작하고 build_attach_url → QR 스캔으로 실기기를 attach하세요." : "mock으로 전환하려면 MCP_ENV=mock 설정 후 서버를 재시작하세요."}`}\n\n${`tool ${toolName} is available only in ${requiredEnv}. Current environment is ${currentEnv} (${reason}).`}`);
|
|
111
|
+
}
|
|
56
112
|
//#endregion
|
|
57
113
|
//#region src/mcp/sdk-signatures.ts
|
|
58
114
|
function isObject(v) {
|
|
@@ -224,7 +280,7 @@ new Set([
|
|
|
224
280
|
},
|
|
225
281
|
{
|
|
226
282
|
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. 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
|
|
283
|
+
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
284
|
inputSchema: {
|
|
229
285
|
type: "object",
|
|
230
286
|
properties: {
|
|
@@ -277,7 +333,7 @@ new Set([
|
|
|
277
333
|
},
|
|
278
334
|
{
|
|
279
335
|
name: "measure_safe_area",
|
|
280
|
-
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.",
|
|
336
|
+
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.",
|
|
281
337
|
inputSchema: {
|
|
282
338
|
type: "object",
|
|
283
339
|
properties: {},
|
|
@@ -319,7 +375,7 @@ new Set([
|
|
|
319
375
|
},
|
|
320
376
|
{
|
|
321
377
|
name: "call_sdk",
|
|
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
|
|
378
|
+
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\", [])",
|
|
323
379
|
inputSchema: {
|
|
324
380
|
type: "object",
|
|
325
381
|
properties: {
|
|
@@ -373,7 +429,7 @@ new Set([
|
|
|
373
429
|
},
|
|
374
430
|
{
|
|
375
431
|
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.",
|
|
432
|
+
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.",
|
|
377
433
|
inputSchema: {
|
|
378
434
|
type: "object",
|
|
379
435
|
properties: { recent_errors_limit: {
|
|
@@ -640,6 +696,29 @@ const DEV_TOOL_DEFINITIONS = [
|
|
|
640
696
|
},
|
|
641
697
|
availableIn: "both"
|
|
642
698
|
},
|
|
699
|
+
{
|
|
700
|
+
name: "build_attach_url",
|
|
701
|
+
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",
|
|
702
|
+
inputSchema: {
|
|
703
|
+
type: "object",
|
|
704
|
+
properties: {
|
|
705
|
+
scheme_url: {
|
|
706
|
+
type: "string",
|
|
707
|
+
description: "The intoss-private:// URL from `ait deploy --scheme-only`."
|
|
708
|
+
},
|
|
709
|
+
wait_for_attach: {
|
|
710
|
+
type: "boolean",
|
|
711
|
+
description: "If true, block until a page attaches."
|
|
712
|
+
},
|
|
713
|
+
open_in_browser: {
|
|
714
|
+
type: "boolean",
|
|
715
|
+
description: "If true (default), open the QR PNG in the OS browser."
|
|
716
|
+
}
|
|
717
|
+
},
|
|
718
|
+
required: ["scheme_url"]
|
|
719
|
+
},
|
|
720
|
+
availableIn: "relay"
|
|
721
|
+
},
|
|
643
722
|
{
|
|
644
723
|
name: "evaluate",
|
|
645
724
|
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.",
|
|
@@ -730,6 +809,12 @@ const CDP_ONLY_TOOL_NAMES = new Set([
|
|
|
730
809
|
"list_exceptions"
|
|
731
810
|
]);
|
|
732
811
|
/**
|
|
812
|
+
* Tier B tools — relay-only per RFC #277.
|
|
813
|
+
* Listed in dev-mode tool surface (issue #323) so agents get a hand-off hint
|
|
814
|
+
* toward `--mode=debug` instead of "Unknown tool".
|
|
815
|
+
*/
|
|
816
|
+
const TIER_B_TOOL_NAMES = new Set(["build_attach_url"]);
|
|
817
|
+
/**
|
|
733
818
|
* Builds the `list_pages` dev-mode shim response.
|
|
734
819
|
* Returns the Vite dev URL as a single-entry page list with `devMode: true`.
|
|
735
820
|
*/
|
|
@@ -844,13 +929,14 @@ function createDevServer(deps = {}) {
|
|
|
844
929
|
const aitSource = deps.aitSource ?? new HttpAitSource({ stateEndpoint });
|
|
845
930
|
const server = new Server({
|
|
846
931
|
name: "ait-devtools",
|
|
847
|
-
version: "0.1.
|
|
932
|
+
version: "0.1.48"
|
|
848
933
|
}, { capabilities: { tools: {} } });
|
|
849
934
|
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: DEV_TOOL_DEFINITIONS.map((tool) => ({ ...tool })) }));
|
|
850
935
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
851
936
|
const name = request.params.name;
|
|
852
937
|
if (!DEV_TOOL_NAMES.has(name)) return mcpError(`알 수 없는 tool: ${name}`);
|
|
853
938
|
if (CDP_ONLY_TOOL_NAMES.has(name)) return mcpError(`${name}: ${CDP_UNAVAILABLE_IN_DEV_MODE}`);
|
|
939
|
+
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로 재시작하세요.");
|
|
854
940
|
try {
|
|
855
941
|
const effective = name === "devtools_get_mock_state" ? "AIT.getMockState" : name;
|
|
856
942
|
if (isAitToolName(effective)) switch (effective) {
|
|
@@ -860,13 +946,13 @@ function createDevServer(deps = {}) {
|
|
|
860
946
|
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
861
947
|
}
|
|
862
948
|
switch (name) {
|
|
863
|
-
case "list_pages": return
|
|
864
|
-
case "get_diagnostics": return
|
|
865
|
-
case "measure_safe_area": return
|
|
949
|
+
case "list_pages": return envelopeResult("list_pages", buildDevListPagesResult(devtoolsUrl));
|
|
950
|
+
case "get_diagnostics": return envelopeResult("get_diagnostics", await buildDevDiagnostics(devtoolsUrl, stateEndpoint, (url) => fetch(url)));
|
|
951
|
+
case "measure_safe_area": return envelopeResult("measure_safe_area", await buildDevMeasureSafeArea(aitSource));
|
|
866
952
|
case "call_sdk": {
|
|
867
953
|
const sdkName = request.params.arguments?.name;
|
|
868
954
|
if (typeof sdkName !== "string" || sdkName === "") return mcpError("call_sdk: name 인자가 비어 있습니다. 호출할 메서드 이름을 전달하세요.");
|
|
869
|
-
return
|
|
955
|
+
return envelopeResult("call_sdk", await buildDevCallSdk(sdkName, aitSource));
|
|
870
956
|
}
|
|
871
957
|
default: return mcpError(`알 수 없는 tool: ${name}`);
|
|
872
958
|
}
|
|
@@ -882,6 +968,26 @@ function jsonResult(value) {
|
|
|
882
968
|
text: JSON.stringify(value, null, 2)
|
|
883
969
|
}] };
|
|
884
970
|
}
|
|
971
|
+
/**
|
|
972
|
+
* Wraps `value` in a `ToolEnvelope` (when compat mode is off) and returns it
|
|
973
|
+
* as a text content block. In dev-mode `env` is always `'mock'` and
|
|
974
|
+
* `attached` is always `true` (the Vite dev server is the single implicit
|
|
975
|
+
* "attached" page).
|
|
976
|
+
*
|
|
977
|
+
* When `AIT_MCP_COMPAT=chrome-devtools` the envelope is skipped and the raw
|
|
978
|
+
* value is returned — identical to `jsonResult` (0.1.x back-compat).
|
|
979
|
+
*/
|
|
980
|
+
function envelopeResult(tool, value) {
|
|
981
|
+
const wrapped = wrapEnvelope(value, {
|
|
982
|
+
tool,
|
|
983
|
+
env: "mock",
|
|
984
|
+
attached: true
|
|
985
|
+
});
|
|
986
|
+
return { content: [{
|
|
987
|
+
type: "text",
|
|
988
|
+
text: JSON.stringify(wrapped, null, 2)
|
|
989
|
+
}] };
|
|
990
|
+
}
|
|
885
991
|
/** Builds the dev-mode server and connects it over stdio. */
|
|
886
992
|
async function runDevServer() {
|
|
887
993
|
const server = createDevServer();
|