@agent-native/core 0.19.1 → 0.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/cli/connect.d.ts +3 -2
  2. package/dist/cli/connect.d.ts.map +1 -1
  3. package/dist/cli/connect.js +12 -8
  4. package/dist/cli/connect.js.map +1 -1
  5. package/dist/cli/mcp-config-writers.d.ts +3 -3
  6. package/dist/cli/mcp-config-writers.d.ts.map +1 -1
  7. package/dist/cli/mcp-config-writers.js +19 -8
  8. package/dist/cli/mcp-config-writers.js.map +1 -1
  9. package/dist/mcp/build-server.d.ts +33 -1
  10. package/dist/mcp/build-server.d.ts.map +1 -1
  11. package/dist/mcp/build-server.js +33 -10
  12. package/dist/mcp/build-server.js.map +1 -1
  13. package/dist/mcp/builtin-tools.d.ts +3 -1
  14. package/dist/mcp/builtin-tools.d.ts.map +1 -1
  15. package/dist/mcp/builtin-tools.js +40 -10
  16. package/dist/mcp/builtin-tools.js.map +1 -1
  17. package/dist/mcp/connect-route.d.ts.map +1 -1
  18. package/dist/mcp/connect-route.js +299 -97
  19. package/dist/mcp/connect-route.js.map +1 -1
  20. package/dist/mcp/server.d.ts.map +1 -1
  21. package/dist/mcp/server.js +17 -3
  22. package/dist/mcp/server.js.map +1 -1
  23. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  24. package/dist/server/agent-chat-plugin.js +33 -0
  25. package/dist/server/agent-chat-plugin.js.map +1 -1
  26. package/dist/server/auth.d.ts +8 -0
  27. package/dist/server/auth.d.ts.map +1 -1
  28. package/dist/server/auth.js +8 -1
  29. package/dist/server/auth.js.map +1 -1
  30. package/dist/vite/client.d.ts.map +1 -1
  31. package/dist/vite/client.js +1 -0
  32. package/dist/vite/client.js.map +1 -1
  33. package/docs/content/external-agents.md +27 -6
  34. package/docs/content/mcp-clients.md +2 -0
  35. package/docs/content/mcp-protocol.md +4 -2
  36. package/package.json +1 -1
@@ -65,15 +65,16 @@ export interface ConnectDeps {
65
65
  * other terminal failure — the caller maps that to a non-zero exit.
66
66
  */
67
67
  export declare function runDeviceFlow(baseUrl: string, appSlug: string, clientArg: string, deps?: ConnectDeps): Promise<{
68
- token: string;
68
+ token?: string;
69
69
  mcpUrl: string;
70
70
  serverName: string;
71
+ headers?: Record<string, string>;
71
72
  } | null>;
72
73
  /**
73
74
  * Write the HTTP MCP entry into every requested client config idempotently.
74
75
  * Returns the list of files written so the caller can print them.
75
76
  */
76
- export declare function writeConfigs(clients: ClientId[], serverName: string, mcpUrl: string, token: string, scope: string, baseDir?: string): {
77
+ export declare function writeConfigs(clients: ClientId[], serverName: string, mcpUrl: string, token: string | undefined, scope: string, baseDir?: string, headers?: Record<string, string>): {
77
78
  client: ClientId;
78
79
  file: string;
79
80
  }[];
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,EAEL,QAAQ,EAET,MAAM,yBAAyB,CAAC;AAkBjC,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,GAAG,EAAE,OAAO,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAsBlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmChD;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAOzD;AAuED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AA4CD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,CAkHvE;AAWD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,QAAQ,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAyB,GACjC;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CActC;AAmDD,8EAA8E;AAC9E,wBAAgB,UAAU,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAI5D;AA8DD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAMH,OAAO,EAEL,QAAQ,EAET,MAAM,yBAAyB,CAAC;AAkBjC,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;IACf,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,GAAG,EAAE,OAAO,CAAC;CACd;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,iBAAiB,CAsBlE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmChD;AAED,0EAA0E;AAC1E,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,EAAE,CAOzD;AAuED,mEAAmE;AACnE,MAAM,WAAW,WAAW;IAC1B,gCAAgC;IAChC,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,0EAA0E;IAC1E,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,0EAA0E;IAC1E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AA4CD;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC;IACT,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC,GAAG,IAAI,CAAC,CAqHR;AAWD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,QAAQ,EAAE,EACnB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,MAAyB,EAClC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,CAetC;AA6DD,8EAA8E;AAC9E,wBAAgB,UAAU,IAAI;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,EAAE,CAI5D;AA8DD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,IAAI,EAAE,MAAM,EAAE,EACd,IAAI,GAAE,WAAgB,GACrB,OAAO,CAAC,IAAI,CAAC,CA6Bf"}
@@ -247,12 +247,14 @@ export async function runDeviceFlow(baseUrl, appSlug, clientArg, deps = {}) {
247
247
  const token = poll.token ?? "";
248
248
  const mcpUrl = poll.mcpUrl ?? `${baseUrl}/_agent-native/mcp`;
249
249
  const serverName = poll.serverName ?? `${SERVER_NAME_PREFIX}-${appSlug}`;
250
- if (!token) {
251
- logErr(" Server approved but returned no token. Aborting.");
252
- return null;
253
- }
250
+ const headers = poll.mcpServerEntry &&
251
+ typeof poll.mcpServerEntry === "object" &&
252
+ poll.mcpServerEntry.headers &&
253
+ typeof poll.mcpServerEntry.headers === "object"
254
+ ? poll.mcpServerEntry.headers
255
+ : undefined;
254
256
  logOut(" Approved.");
255
- return { token, mcpUrl, serverName };
257
+ return { token: token || undefined, mcpUrl, serverName, headers };
256
258
  }
257
259
  if (poll.status === "expired") {
258
260
  if (isTTY)
@@ -296,10 +298,10 @@ function projectBaseDir() {
296
298
  * Write the HTTP MCP entry into every requested client config idempotently.
297
299
  * Returns the list of files written so the caller can print them.
298
300
  */
299
- export function writeConfigs(clients, serverName, mcpUrl, token, scope, baseDir = projectBaseDir()) {
301
+ export function writeConfigs(clients, serverName, mcpUrl, token, scope, baseDir = projectBaseDir(), headers) {
300
302
  const written = [];
301
303
  for (const client of clients) {
302
- const file = writeHttpEntryForClient(client, serverName, mcpUrl, token, baseDir, scope);
304
+ const file = writeHttpEntryForClient(client, serverName, mcpUrl, token, baseDir, scope, headers);
303
305
  written.push({ client, file });
304
306
  }
305
307
  return written;
@@ -315,6 +317,7 @@ async function connectOne(rawUrl, parsed, deps) {
315
317
  let token;
316
318
  let mcpUrl;
317
319
  let serverName;
320
+ let headers;
318
321
  if (parsed.token) {
319
322
  // No-browser fallback: skip the device flow entirely.
320
323
  token = parsed.token;
@@ -330,8 +333,9 @@ async function connectOne(rawUrl, parsed, deps) {
330
333
  token = grant.token;
331
334
  mcpUrl = grant.mcpUrl;
332
335
  serverName = parsed.name ?? grant.serverName ?? defaultServerName(baseUrl);
336
+ headers = grant.headers;
333
337
  }
334
- const written = writeConfigs(clients, serverName, mcpUrl, token, scope);
338
+ const written = writeConfigs(clients, serverName, mcpUrl, token, scope, undefined, headers);
335
339
  logOut("");
336
340
  logOut(` Connected "${serverName}" → ${mcpUrl}`);
337
341
  for (const w of written) {
@@ -1 +1 @@
1
- {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `agent-native connect <url>` — wire your local Claude Code / Codex / Cowork\n * to a DEPLOYED agent-native app using a browser device-code flow. No token\n * copying: open the verification URL, approve in the browser, and the minted\n * HTTP MCP server entry is written into your client config(s) idempotently.\n *\n * agent-native connect <url> [--client all|claude-code|claude-code-cli|\n * codex|cowork] [--scope user|project]\n * [--name <serverName>]\n * agent-native connect <url> --token <token> (no-browser fallback)\n * agent-native connect --all [--client ...] (every first-party app)\n *\n * Server contract (implemented by another agent on `<url>`):\n * POST <url>/_agent-native/mcp/connect/device/start (no auth)\n * body { client?, app? }\n * → { device_code, user_code, verification_uri,\n * verification_uri_complete, interval, expires_in }\n * POST <url>/_agent-native/mcp/connect/device/poll (no auth)\n * body { device_code }\n * → { status: \"pending\" }\n * | { status: \"approved\", token, mcpUrl, serverName, mcpServerEntry }\n * | { status: \"expired\" }\n * | { status: \"consumed\" }\n * | { status: \"error\" | \"not_found\", message? }\n *\n * Node-only CLI module. No new npm deps (Node built-ins + global fetch only).\n */\n\nimport { spawn } from \"node:child_process\";\nimport path from \"node:path\";\n\nimport { findWorkspaceRoot } from \"../mcp/workspace-resolve.js\";\nimport {\n CLIENTS,\n ClientId,\n writeHttpEntryForClient,\n} from \"./mcp-config-writers.js\";\nimport { visibleTemplates } from \"./templates-meta.js\";\n\nconst DEVICE_START_PATH = \"/_agent-native/mcp/connect/device/start\";\nconst DEVICE_POLL_PATH = \"/_agent-native/mcp/connect/device/poll\";\nconst SERVER_NAME_PREFIX = \"agent-native\";\n\nfunction logOut(msg: string): void {\n process.stdout.write(`${msg}\\n`);\n}\nfunction logErr(msg: string): void {\n process.stderr.write(`${msg}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Arg parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedConnectArgs {\n /** Positional URL (the deployed app origin). Undefined for `--all`. */\n url?: string;\n /** all | claude-code | claude-code-cli | codex | cowork (default \"all\"). */\n client: string;\n /** user | project (default \"user\"). */\n scope: string;\n /** Override the minted MCP server name. */\n name?: string;\n /** No-browser fallback: skip device flow, use this token directly. */\n token?: string;\n /** Connect every first-party hosted app. */\n all: boolean;\n}\n\nexport function parseConnectArgs(argv: string[]): ParsedConnectArgs {\n const out: ParsedConnectArgs = {\n client: \"all\",\n scope: \"user\",\n all: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n const eat = (flag: string): string | undefined => {\n if (a === flag) return argv[++i];\n if (a.startsWith(`${flag}=`)) return a.slice(flag.length + 1);\n return undefined;\n };\n let v: string | undefined;\n if (a === \"--all\") out.all = true;\n else if ((v = eat(\"--client\")) !== undefined) out.client = v;\n else if ((v = eat(\"--scope\")) !== undefined) out.scope = v;\n else if ((v = eat(\"--name\")) !== undefined) out.name = v;\n else if ((v = eat(\"--token\")) !== undefined) out.token = v;\n else if (!a.startsWith(\"-\") && !out.url) out.url = a;\n }\n return out;\n}\n\n/**\n * Normalize a user-supplied app URL: trim, require http/https, strip the\n * trailing slash. Throws a friendly Error otherwise.\n */\nexport function normalizeUrl(raw: string): string {\n const trimmed = (raw ?? \"\").trim();\n if (!trimmed) {\n throw new Error(\"Missing app URL. Usage: agent-native connect <url>\");\n }\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(\n `Not a valid URL: \"${raw}\". Pass a full origin, e.g. ` +\n `agent-native connect https://mail.agent-native.com`,\n );\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\n `Unsupported URL scheme \"${parsed.protocol}\". Use http:// or https://`,\n );\n }\n const host = parsed.hostname.toLowerCase();\n const isLoopback =\n host === \"localhost\" ||\n host === \"127.0.0.1\" ||\n host === \"::1\" ||\n host === \"[::1]\" ||\n host.startsWith(\"127.\");\n if (parsed.protocol === \"http:\" && !isLoopback) {\n throw new Error(\n `Refusing plaintext HTTP for non-loopback host \"${parsed.hostname}\". ` +\n `Use https:// so bearer tokens are not sent in cleartext.`,\n );\n }\n // origin + pathname, trailing slash stripped (origin keeps no path).\n const base = `${parsed.origin}${parsed.pathname}`.replace(/\\/+$/, \"\");\n return base;\n}\n\n/** Resolve the requested clients list. \"all\" → every supported client. */\nexport function resolveClients(client: string): ClientId[] {\n const c = (client ?? \"all\").toLowerCase();\n if (c === \"all\" || c === \"\") return [...CLIENTS];\n if ((CLIENTS as string[]).includes(c)) return [c as ClientId];\n throw new Error(\n `Unknown --client \"${client}\". Use: all, ${CLIENTS.join(\", \")}`,\n );\n}\n\n/** Derive an app slug from a deployed origin, e.g. mail.agent-native.com → mail. */\nfunction appSlugFromUrl(url: string): string {\n try {\n const host = new URL(url).hostname;\n const first = host.split(\".\")[0];\n return first && first !== \"www\" ? first : \"app\";\n } catch {\n return \"app\";\n }\n}\n\nfunction defaultServerName(url: string): string {\n return `${SERVER_NAME_PREFIX}-${appSlugFromUrl(url)}`;\n}\n\n// ---------------------------------------------------------------------------\n// Browser open (mirrors workspace-dev.ts openBrowser)\n// ---------------------------------------------------------------------------\n\nfunction openInBrowser(url: string): void {\n if (process.env.AGENT_NATIVE_NO_OPEN === \"1\") return;\n try {\n const command =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"cmd\"\n : \"xdg-open\";\n const openArgs =\n process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n const child = spawn(command, openArgs, {\n stdio: \"ignore\",\n detached: true,\n });\n child.unref();\n } catch {\n // Non-fatal: the user can open the URL manually (we already printed it).\n }\n}\n\n// ---------------------------------------------------------------------------\n// Device-code flow\n// ---------------------------------------------------------------------------\n\ninterface DeviceStartResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n interval?: number;\n expires_in?: number;\n}\n\ninterface DevicePollResponse {\n status:\n | \"pending\"\n | \"approved\"\n | \"expired\"\n | \"consumed\"\n | \"error\"\n | \"not_found\";\n token?: string;\n mcpUrl?: string;\n serverName?: string;\n mcpServerEntry?: Record<string, unknown>;\n message?: string;\n error?: string;\n}\n\n/** Injectable hooks so the poll state machine is unit-testable. */\nexport interface ConnectDeps {\n /** Defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Sleep between polls (ms). Defaults to real setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Open the verification URL. Defaults to the platform browser opener. */\n openBrowser?: (url: string) => void;\n /** Override \"now\" for the expiry cap (ms epoch). Defaults to Date.now. */\n now?: () => number;\n}\n\nfunction realSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function postJson(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<{ status: number; json: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body ?? {}),\n signal: controller.signal,\n });\n let json: any = null;\n try {\n json = await response.json();\n } catch {\n json = null;\n }\n return { status: response.status, json };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction responseMessage(json: any, fallback: string): string {\n const message =\n typeof json?.message === \"string\"\n ? json.message\n : typeof json?.error === \"string\"\n ? json.error\n : \"\";\n return message.trim() || fallback;\n}\n\nconst SPINNER = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\n/**\n * Run the device-code flow against `baseUrl` and return the approved grant.\n * Resolves with `null` (and prints a clear message) on expired/consumed or\n * other terminal failure — the caller maps that to a non-zero exit.\n */\nexport async function runDeviceFlow(\n baseUrl: string,\n appSlug: string,\n clientArg: string,\n deps: ConnectDeps = {},\n): Promise<{ token: string; mcpUrl: string; serverName: string } | null> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? realSleep;\n const open = deps.openBrowser ?? openInBrowser;\n const now = deps.now ?? (() => Date.now());\n\n let start: DeviceStartResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_START_PATH}`,\n { client: clientArg, app: appSlug },\n );\n if (status < 200 || status >= 300 || !json?.device_code) {\n logErr(\n ` Could not start the connect flow on ${baseUrl} ` +\n `(HTTP ${status}). Is this an agent-native app, and is it ` +\n `deployed with the connect endpoint enabled?`,\n );\n return null;\n }\n start = json as DeviceStartResponse;\n } catch (err: any) {\n logErr(\n ` Could not reach ${baseUrl} (${err?.message ?? err}). ` +\n `Check the URL and your network.`,\n );\n return null;\n }\n\n const interval = Math.max(1, Number(start.interval) || 5);\n const expiresIn = Math.max(interval, Number(start.expires_in) || 600);\n const deadline = now() + expiresIn * 1000;\n\n logOut(\"\");\n logOut(` Connecting to ${baseUrl}`);\n logOut(\"\");\n logOut(` Your code: ${start.user_code}`);\n logOut(` Open: ${start.verification_uri_complete}`);\n logOut(\"\");\n logOut(\" Approve in the browser to finish. Opening it now…\");\n open(start.verification_uri_complete);\n\n let spin = 0;\n const isTTY = !!process.stdout.isTTY;\n while (now() < deadline) {\n let poll: DevicePollResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_POLL_PATH}`,\n { device_code: start.device_code },\n );\n if (status < 200 || status >= 300) {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\n ` Connect polling failed (HTTP ${status}): ` +\n responseMessage(json, \"server returned an error.\"),\n );\n return null;\n }\n poll = (json ?? { status: \"pending\" }) as DevicePollResponse;\n } catch {\n // Transient network error — keep polling until the deadline.\n poll = { status: \"pending\" };\n }\n\n if (poll.status === \"approved\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n const token = poll.token ?? \"\";\n const mcpUrl = poll.mcpUrl ?? `${baseUrl}/_agent-native/mcp`;\n const serverName = poll.serverName ?? `${SERVER_NAME_PREFIX}-${appSlug}`;\n if (!token) {\n logErr(\" Server approved but returned no token. Aborting.\");\n return null;\n }\n logOut(\" Approved.\");\n return { token, mcpUrl, serverName };\n }\n if (poll.status === \"expired\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" The connect request expired before it was approved.\");\n logErr(\" Run the command again to retry.\");\n return null;\n }\n if (poll.status === \"consumed\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" This connect code was already used. Run the command again.\");\n return null;\n }\n if (poll.status === \"error\" || poll.status === \"not_found\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\n ` Connect polling failed: ${responseMessage(\n poll,\n poll.status === \"not_found\"\n ? \"device code was not found.\"\n : \"server returned an error.\",\n )}`,\n );\n return null;\n }\n\n if (isTTY) {\n process.stdout.write(\n `\\r ${SPINNER[spin++ % SPINNER.length]} Waiting for approval…`,\n );\n }\n await sleep(interval * 1000);\n }\n\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" Timed out waiting for approval. Run the command again to retry.\");\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Writing config(s)\n// ---------------------------------------------------------------------------\n\nfunction projectBaseDir(): string {\n const cwd = process.cwd();\n return findWorkspaceRoot(cwd) ?? path.resolve(cwd);\n}\n\n/**\n * Write the HTTP MCP entry into every requested client config idempotently.\n * Returns the list of files written so the caller can print them.\n */\nexport function writeConfigs(\n clients: ClientId[],\n serverName: string,\n mcpUrl: string,\n token: string,\n scope: string,\n baseDir: string = projectBaseDir(),\n): { client: ClientId; file: string }[] {\n const written: { client: ClientId; file: string }[] = [];\n for (const client of clients) {\n const file = writeHttpEntryForClient(\n client,\n serverName,\n mcpUrl,\n token,\n baseDir,\n scope,\n );\n written.push({ client, file });\n }\n return written;\n}\n\n// ---------------------------------------------------------------------------\n// Single-app connect\n// ---------------------------------------------------------------------------\n\nasync function connectOne(\n rawUrl: string,\n parsed: ParsedConnectArgs,\n deps: ConnectDeps,\n): Promise<{ ok: boolean; serverName?: string; files?: string[] }> {\n const baseUrl = normalizeUrl(rawUrl);\n const appSlug = appSlugFromUrl(baseUrl);\n const clients = resolveClients(parsed.client);\n const scope = parsed.scope === \"user\" ? \"user\" : \"project\";\n\n let token: string;\n let mcpUrl: string;\n let serverName: string;\n\n if (parsed.token) {\n // No-browser fallback: skip the device flow entirely.\n token = parsed.token;\n mcpUrl = `${baseUrl}/_agent-native/mcp`;\n serverName = parsed.name ?? defaultServerName(baseUrl);\n logOut(\"\");\n logOut(` Using supplied --token for ${baseUrl} (skipping browser flow).`);\n } else {\n const grant = await runDeviceFlow(baseUrl, appSlug, parsed.client, deps);\n if (!grant) return { ok: false };\n token = grant.token;\n mcpUrl = grant.mcpUrl;\n serverName = parsed.name ?? grant.serverName ?? defaultServerName(baseUrl);\n }\n\n const written = writeConfigs(clients, serverName, mcpUrl, token, scope);\n\n logOut(\"\");\n logOut(` Connected \"${serverName}\" → ${mcpUrl}`);\n for (const w of written) {\n logOut(` ${w.client.padEnd(18)} ${w.file}`);\n }\n logOut(\"\");\n logOut(\" Restart your coding agent to pick up the new MCP server.\");\n return { ok: true, serverName, files: written.map((w) => w.file) };\n}\n\n// ---------------------------------------------------------------------------\n// --all : connect every first-party hosted app\n// ---------------------------------------------------------------------------\n\n/** Hosted first-party apps: visible (non-hidden) templates with a prodUrl. */\nexport function hostedApps(): { name: string; url: string }[] {\n return visibleTemplates()\n .filter((t) => typeof t.prodUrl === \"string\" && t.prodUrl.length > 0)\n .map((t) => ({ name: t.name, url: t.prodUrl as string }));\n}\n\nasync function connectAll(\n parsed: ParsedConnectArgs,\n deps: ConnectDeps,\n): Promise<boolean> {\n const apps = hostedApps();\n if (apps.length === 0) {\n logErr(\" No hosted first-party apps found in the template registry.\");\n return false;\n }\n logOut(\"\");\n logOut(` Connecting ${apps.length} first-party hosted apps…`);\n\n const results: { name: string; status: string; files: string[] }[] = [];\n for (const app of apps) {\n logOut(\"\");\n logOut(` ── ${app.name} (${app.url}) ──`);\n try {\n const res = await connectOne(app.url, parsed, deps);\n results.push({\n name: app.name,\n status: res.ok ? \"connected\" : \"skipped\",\n files: res.files ?? [],\n });\n } catch (err: any) {\n logErr(` ${app.name}: ${err?.message ?? err}`);\n results.push({ name: app.name, status: \"error\", files: [] });\n }\n }\n\n logOut(\"\");\n logOut(\" Summary\");\n for (const r of results) {\n const files = r.files.length ? r.files.join(\", \") : \"—\";\n logOut(` ${r.name.padEnd(14)} ${r.status.padEnd(10)} ${files}`);\n }\n return results.every((r) => r.status === \"connected\");\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nconst HELP = `agent-native connect — wire your coding agent to a deployed app\n\nUsage:\n agent-native connect <url> [--client <c>] [--scope user|project] [--name <n>]\n Browser device-code flow. Prints a code, opens the verification URL,\n polls until approved, then writes the HTTP MCP entry into your\n client config(s). Idempotent — re-running replaces the same entry.\n\n agent-native connect <url> --token <token>\n No-browser fallback. Skip the device flow and write the entry with\n the supplied token (get it from the app's Connect page).\n\n agent-native connect --all [--client <c>] [--scope user|project]\n Connect every first-party hosted app at once.\n\nClients: all (default), claude-code, claude-code-cli, codex, cowork\nScope: project (default, .mcp.json) or user (~/.claude.json)`;\n\n/**\n * `agent-native connect` entry point. `deps` is injectable for tests; the\n * dispatcher in index.ts calls it with just `args`.\n *\n * Sets `process.exitCode = 1` on failure (so the process exits non-zero\n * once the event loop drains) rather than calling `process.exit`, keeping\n * the function testable — same pattern as `audit-agent-web`.\n */\nexport async function runConnect(\n args: string[],\n deps: ConnectDeps = {},\n): Promise<void> {\n if (args[0] === \"--help\" || args[0] === \"-h\" || args[0] === \"help\") {\n logOut(HELP);\n return;\n }\n\n const parsed = parseConnectArgs(args);\n\n try {\n if (parsed.all) {\n const ok = await connectAll(parsed, deps);\n if (!ok) process.exitCode = 1;\n return;\n }\n\n if (!parsed.url) {\n logErr(\" Missing app URL.\");\n logErr(\"\");\n logOut(HELP);\n process.exitCode = 1;\n return;\n }\n\n const res = await connectOne(parsed.url, parsed, deps);\n if (!res.ok) process.exitCode = 1;\n } catch (err: any) {\n logErr(` ${err?.message ?? err}`);\n process.exitCode = 1;\n }\n}\n"]}
1
+ {"version":3,"file":"connect.js","sourceRoot":"","sources":["../../src/cli/connect.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * `agent-native connect <url>` — wire your local Claude Code / Codex / Cowork\n * to a DEPLOYED agent-native app using a browser device-code flow. No token\n * copying: open the verification URL, approve in the browser, and the minted\n * HTTP MCP server entry is written into your client config(s) idempotently.\n *\n * agent-native connect <url> [--client all|claude-code|claude-code-cli|\n * codex|cowork] [--scope user|project]\n * [--name <serverName>]\n * agent-native connect <url> --token <token> (no-browser fallback)\n * agent-native connect --all [--client ...] (every first-party app)\n *\n * Server contract (implemented by another agent on `<url>`):\n * POST <url>/_agent-native/mcp/connect/device/start (no auth)\n * body { client?, app? }\n * → { device_code, user_code, verification_uri,\n * verification_uri_complete, interval, expires_in }\n * POST <url>/_agent-native/mcp/connect/device/poll (no auth)\n * body { device_code }\n * → { status: \"pending\" }\n * | { status: \"approved\", token, mcpUrl, serverName, mcpServerEntry }\n * | { status: \"expired\" }\n * | { status: \"consumed\" }\n * | { status: \"error\" | \"not_found\", message? }\n *\n * Node-only CLI module. No new npm deps (Node built-ins + global fetch only).\n */\n\nimport { spawn } from \"node:child_process\";\nimport path from \"node:path\";\n\nimport { findWorkspaceRoot } from \"../mcp/workspace-resolve.js\";\nimport {\n CLIENTS,\n ClientId,\n writeHttpEntryForClient,\n} from \"./mcp-config-writers.js\";\nimport { visibleTemplates } from \"./templates-meta.js\";\n\nconst DEVICE_START_PATH = \"/_agent-native/mcp/connect/device/start\";\nconst DEVICE_POLL_PATH = \"/_agent-native/mcp/connect/device/poll\";\nconst SERVER_NAME_PREFIX = \"agent-native\";\n\nfunction logOut(msg: string): void {\n process.stdout.write(`${msg}\\n`);\n}\nfunction logErr(msg: string): void {\n process.stderr.write(`${msg}\\n`);\n}\n\n// ---------------------------------------------------------------------------\n// Arg parsing\n// ---------------------------------------------------------------------------\n\nexport interface ParsedConnectArgs {\n /** Positional URL (the deployed app origin). Undefined for `--all`. */\n url?: string;\n /** all | claude-code | claude-code-cli | codex | cowork (default \"all\"). */\n client: string;\n /** user | project (default \"user\"). */\n scope: string;\n /** Override the minted MCP server name. */\n name?: string;\n /** No-browser fallback: skip device flow, use this token directly. */\n token?: string;\n /** Connect every first-party hosted app. */\n all: boolean;\n}\n\nexport function parseConnectArgs(argv: string[]): ParsedConnectArgs {\n const out: ParsedConnectArgs = {\n client: \"all\",\n scope: \"user\",\n all: false,\n };\n for (let i = 0; i < argv.length; i++) {\n const a = argv[i];\n const eat = (flag: string): string | undefined => {\n if (a === flag) return argv[++i];\n if (a.startsWith(`${flag}=`)) return a.slice(flag.length + 1);\n return undefined;\n };\n let v: string | undefined;\n if (a === \"--all\") out.all = true;\n else if ((v = eat(\"--client\")) !== undefined) out.client = v;\n else if ((v = eat(\"--scope\")) !== undefined) out.scope = v;\n else if ((v = eat(\"--name\")) !== undefined) out.name = v;\n else if ((v = eat(\"--token\")) !== undefined) out.token = v;\n else if (!a.startsWith(\"-\") && !out.url) out.url = a;\n }\n return out;\n}\n\n/**\n * Normalize a user-supplied app URL: trim, require http/https, strip the\n * trailing slash. Throws a friendly Error otherwise.\n */\nexport function normalizeUrl(raw: string): string {\n const trimmed = (raw ?? \"\").trim();\n if (!trimmed) {\n throw new Error(\"Missing app URL. Usage: agent-native connect <url>\");\n }\n let parsed: URL;\n try {\n parsed = new URL(trimmed);\n } catch {\n throw new Error(\n `Not a valid URL: \"${raw}\". Pass a full origin, e.g. ` +\n `agent-native connect https://mail.agent-native.com`,\n );\n }\n if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") {\n throw new Error(\n `Unsupported URL scheme \"${parsed.protocol}\". Use http:// or https://`,\n );\n }\n const host = parsed.hostname.toLowerCase();\n const isLoopback =\n host === \"localhost\" ||\n host === \"127.0.0.1\" ||\n host === \"::1\" ||\n host === \"[::1]\" ||\n host.startsWith(\"127.\");\n if (parsed.protocol === \"http:\" && !isLoopback) {\n throw new Error(\n `Refusing plaintext HTTP for non-loopback host \"${parsed.hostname}\". ` +\n `Use https:// so bearer tokens are not sent in cleartext.`,\n );\n }\n // origin + pathname, trailing slash stripped (origin keeps no path).\n const base = `${parsed.origin}${parsed.pathname}`.replace(/\\/+$/, \"\");\n return base;\n}\n\n/** Resolve the requested clients list. \"all\" → every supported client. */\nexport function resolveClients(client: string): ClientId[] {\n const c = (client ?? \"all\").toLowerCase();\n if (c === \"all\" || c === \"\") return [...CLIENTS];\n if ((CLIENTS as string[]).includes(c)) return [c as ClientId];\n throw new Error(\n `Unknown --client \"${client}\". Use: all, ${CLIENTS.join(\", \")}`,\n );\n}\n\n/** Derive an app slug from a deployed origin, e.g. mail.agent-native.com → mail. */\nfunction appSlugFromUrl(url: string): string {\n try {\n const host = new URL(url).hostname;\n const first = host.split(\".\")[0];\n return first && first !== \"www\" ? first : \"app\";\n } catch {\n return \"app\";\n }\n}\n\nfunction defaultServerName(url: string): string {\n return `${SERVER_NAME_PREFIX}-${appSlugFromUrl(url)}`;\n}\n\n// ---------------------------------------------------------------------------\n// Browser open (mirrors workspace-dev.ts openBrowser)\n// ---------------------------------------------------------------------------\n\nfunction openInBrowser(url: string): void {\n if (process.env.AGENT_NATIVE_NO_OPEN === \"1\") return;\n try {\n const command =\n process.platform === \"darwin\"\n ? \"open\"\n : process.platform === \"win32\"\n ? \"cmd\"\n : \"xdg-open\";\n const openArgs =\n process.platform === \"win32\" ? [\"/c\", \"start\", \"\", url] : [url];\n const child = spawn(command, openArgs, {\n stdio: \"ignore\",\n detached: true,\n });\n child.unref();\n } catch {\n // Non-fatal: the user can open the URL manually (we already printed it).\n }\n}\n\n// ---------------------------------------------------------------------------\n// Device-code flow\n// ---------------------------------------------------------------------------\n\ninterface DeviceStartResponse {\n device_code: string;\n user_code: string;\n verification_uri: string;\n verification_uri_complete: string;\n interval?: number;\n expires_in?: number;\n}\n\ninterface DevicePollResponse {\n status:\n | \"pending\"\n | \"approved\"\n | \"expired\"\n | \"consumed\"\n | \"error\"\n | \"not_found\";\n token?: string;\n mcpUrl?: string;\n serverName?: string;\n mcpServerEntry?: Record<string, unknown>;\n message?: string;\n error?: string;\n}\n\n/** Injectable hooks so the poll state machine is unit-testable. */\nexport interface ConnectDeps {\n /** Defaults to global fetch. */\n fetchImpl?: typeof fetch;\n /** Sleep between polls (ms). Defaults to real setTimeout. */\n sleep?: (ms: number) => Promise<void>;\n /** Open the verification URL. Defaults to the platform browser opener. */\n openBrowser?: (url: string) => void;\n /** Override \"now\" for the expiry cap (ms epoch). Defaults to Date.now. */\n now?: () => number;\n}\n\nfunction realSleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nasync function postJson(\n fetchImpl: typeof fetch,\n url: string,\n body: unknown,\n): Promise<{ status: number; json: any }> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const response = await fetchImpl(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(body ?? {}),\n signal: controller.signal,\n });\n let json: any = null;\n try {\n json = await response.json();\n } catch {\n json = null;\n }\n return { status: response.status, json };\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction responseMessage(json: any, fallback: string): string {\n const message =\n typeof json?.message === \"string\"\n ? json.message\n : typeof json?.error === \"string\"\n ? json.error\n : \"\";\n return message.trim() || fallback;\n}\n\nconst SPINNER = [\"⠋\", \"⠙\", \"⠹\", \"⠸\", \"⠼\", \"⠴\", \"⠦\", \"⠧\", \"⠇\", \"⠏\"];\n\n/**\n * Run the device-code flow against `baseUrl` and return the approved grant.\n * Resolves with `null` (and prints a clear message) on expired/consumed or\n * other terminal failure — the caller maps that to a non-zero exit.\n */\nexport async function runDeviceFlow(\n baseUrl: string,\n appSlug: string,\n clientArg: string,\n deps: ConnectDeps = {},\n): Promise<{\n token?: string;\n mcpUrl: string;\n serverName: string;\n headers?: Record<string, string>;\n} | null> {\n const fetchImpl = deps.fetchImpl ?? fetch;\n const sleep = deps.sleep ?? realSleep;\n const open = deps.openBrowser ?? openInBrowser;\n const now = deps.now ?? (() => Date.now());\n\n let start: DeviceStartResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_START_PATH}`,\n { client: clientArg, app: appSlug },\n );\n if (status < 200 || status >= 300 || !json?.device_code) {\n logErr(\n ` Could not start the connect flow on ${baseUrl} ` +\n `(HTTP ${status}). Is this an agent-native app, and is it ` +\n `deployed with the connect endpoint enabled?`,\n );\n return null;\n }\n start = json as DeviceStartResponse;\n } catch (err: any) {\n logErr(\n ` Could not reach ${baseUrl} (${err?.message ?? err}). ` +\n `Check the URL and your network.`,\n );\n return null;\n }\n\n const interval = Math.max(1, Number(start.interval) || 5);\n const expiresIn = Math.max(interval, Number(start.expires_in) || 600);\n const deadline = now() + expiresIn * 1000;\n\n logOut(\"\");\n logOut(` Connecting to ${baseUrl}`);\n logOut(\"\");\n logOut(` Your code: ${start.user_code}`);\n logOut(` Open: ${start.verification_uri_complete}`);\n logOut(\"\");\n logOut(\" Approve in the browser to finish. Opening it now…\");\n open(start.verification_uri_complete);\n\n let spin = 0;\n const isTTY = !!process.stdout.isTTY;\n while (now() < deadline) {\n let poll: DevicePollResponse;\n try {\n const { status, json } = await postJson(\n fetchImpl,\n `${baseUrl}${DEVICE_POLL_PATH}`,\n { device_code: start.device_code },\n );\n if (status < 200 || status >= 300) {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\n ` Connect polling failed (HTTP ${status}): ` +\n responseMessage(json, \"server returned an error.\"),\n );\n return null;\n }\n poll = (json ?? { status: \"pending\" }) as DevicePollResponse;\n } catch {\n // Transient network error — keep polling until the deadline.\n poll = { status: \"pending\" };\n }\n\n if (poll.status === \"approved\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n const token = poll.token ?? \"\";\n const mcpUrl = poll.mcpUrl ?? `${baseUrl}/_agent-native/mcp`;\n const serverName = poll.serverName ?? `${SERVER_NAME_PREFIX}-${appSlug}`;\n const headers =\n poll.mcpServerEntry &&\n typeof poll.mcpServerEntry === \"object\" &&\n poll.mcpServerEntry.headers &&\n typeof poll.mcpServerEntry.headers === \"object\"\n ? (poll.mcpServerEntry.headers as Record<string, string>)\n : undefined;\n logOut(\" Approved.\");\n return { token: token || undefined, mcpUrl, serverName, headers };\n }\n if (poll.status === \"expired\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" The connect request expired before it was approved.\");\n logErr(\" Run the command again to retry.\");\n return null;\n }\n if (poll.status === \"consumed\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" This connect code was already used. Run the command again.\");\n return null;\n }\n if (poll.status === \"error\" || poll.status === \"not_found\") {\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\n ` Connect polling failed: ${responseMessage(\n poll,\n poll.status === \"not_found\"\n ? \"device code was not found.\"\n : \"server returned an error.\",\n )}`,\n );\n return null;\n }\n\n if (isTTY) {\n process.stdout.write(\n `\\r ${SPINNER[spin++ % SPINNER.length]} Waiting for approval…`,\n );\n }\n await sleep(interval * 1000);\n }\n\n if (isTTY) process.stdout.write(\"\\r\\x1b[K\");\n logErr(\" Timed out waiting for approval. Run the command again to retry.\");\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Writing config(s)\n// ---------------------------------------------------------------------------\n\nfunction projectBaseDir(): string {\n const cwd = process.cwd();\n return findWorkspaceRoot(cwd) ?? path.resolve(cwd);\n}\n\n/**\n * Write the HTTP MCP entry into every requested client config idempotently.\n * Returns the list of files written so the caller can print them.\n */\nexport function writeConfigs(\n clients: ClientId[],\n serverName: string,\n mcpUrl: string,\n token: string | undefined,\n scope: string,\n baseDir: string = projectBaseDir(),\n headers?: Record<string, string>,\n): { client: ClientId; file: string }[] {\n const written: { client: ClientId; file: string }[] = [];\n for (const client of clients) {\n const file = writeHttpEntryForClient(\n client,\n serverName,\n mcpUrl,\n token,\n baseDir,\n scope,\n headers,\n );\n written.push({ client, file });\n }\n return written;\n}\n\n// ---------------------------------------------------------------------------\n// Single-app connect\n// ---------------------------------------------------------------------------\n\nasync function connectOne(\n rawUrl: string,\n parsed: ParsedConnectArgs,\n deps: ConnectDeps,\n): Promise<{ ok: boolean; serverName?: string; files?: string[] }> {\n const baseUrl = normalizeUrl(rawUrl);\n const appSlug = appSlugFromUrl(baseUrl);\n const clients = resolveClients(parsed.client);\n const scope = parsed.scope === \"user\" ? \"user\" : \"project\";\n\n let token: string | undefined;\n let mcpUrl: string;\n let serverName: string;\n let headers: Record<string, string> | undefined;\n\n if (parsed.token) {\n // No-browser fallback: skip the device flow entirely.\n token = parsed.token;\n mcpUrl = `${baseUrl}/_agent-native/mcp`;\n serverName = parsed.name ?? defaultServerName(baseUrl);\n logOut(\"\");\n logOut(` Using supplied --token for ${baseUrl} (skipping browser flow).`);\n } else {\n const grant = await runDeviceFlow(baseUrl, appSlug, parsed.client, deps);\n if (!grant) return { ok: false };\n token = grant.token;\n mcpUrl = grant.mcpUrl;\n serverName = parsed.name ?? grant.serverName ?? defaultServerName(baseUrl);\n headers = grant.headers;\n }\n\n const written = writeConfigs(\n clients,\n serverName,\n mcpUrl,\n token,\n scope,\n undefined,\n headers,\n );\n\n logOut(\"\");\n logOut(` Connected \"${serverName}\" → ${mcpUrl}`);\n for (const w of written) {\n logOut(` ${w.client.padEnd(18)} ${w.file}`);\n }\n logOut(\"\");\n logOut(\" Restart your coding agent to pick up the new MCP server.\");\n return { ok: true, serverName, files: written.map((w) => w.file) };\n}\n\n// ---------------------------------------------------------------------------\n// --all : connect every first-party hosted app\n// ---------------------------------------------------------------------------\n\n/** Hosted first-party apps: visible (non-hidden) templates with a prodUrl. */\nexport function hostedApps(): { name: string; url: string }[] {\n return visibleTemplates()\n .filter((t) => typeof t.prodUrl === \"string\" && t.prodUrl.length > 0)\n .map((t) => ({ name: t.name, url: t.prodUrl as string }));\n}\n\nasync function connectAll(\n parsed: ParsedConnectArgs,\n deps: ConnectDeps,\n): Promise<boolean> {\n const apps = hostedApps();\n if (apps.length === 0) {\n logErr(\" No hosted first-party apps found in the template registry.\");\n return false;\n }\n logOut(\"\");\n logOut(` Connecting ${apps.length} first-party hosted apps…`);\n\n const results: { name: string; status: string; files: string[] }[] = [];\n for (const app of apps) {\n logOut(\"\");\n logOut(` ── ${app.name} (${app.url}) ──`);\n try {\n const res = await connectOne(app.url, parsed, deps);\n results.push({\n name: app.name,\n status: res.ok ? \"connected\" : \"skipped\",\n files: res.files ?? [],\n });\n } catch (err: any) {\n logErr(` ${app.name}: ${err?.message ?? err}`);\n results.push({ name: app.name, status: \"error\", files: [] });\n }\n }\n\n logOut(\"\");\n logOut(\" Summary\");\n for (const r of results) {\n const files = r.files.length ? r.files.join(\", \") : \"—\";\n logOut(` ${r.name.padEnd(14)} ${r.status.padEnd(10)} ${files}`);\n }\n return results.every((r) => r.status === \"connected\");\n}\n\n// ---------------------------------------------------------------------------\n// Entry point\n// ---------------------------------------------------------------------------\n\nconst HELP = `agent-native connect — wire your coding agent to a deployed app\n\nUsage:\n agent-native connect <url> [--client <c>] [--scope user|project] [--name <n>]\n Browser device-code flow. Prints a code, opens the verification URL,\n polls until approved, then writes the HTTP MCP entry into your\n client config(s). Idempotent — re-running replaces the same entry.\n\n agent-native connect <url> --token <token>\n No-browser fallback. Skip the device flow and write the entry with\n the supplied token (get it from the app's Connect page).\n\n agent-native connect --all [--client <c>] [--scope user|project]\n Connect every first-party hosted app at once.\n\nClients: all (default), claude-code, claude-code-cli, codex, cowork\nScope: project (default, .mcp.json) or user (~/.claude.json)`;\n\n/**\n * `agent-native connect` entry point. `deps` is injectable for tests; the\n * dispatcher in index.ts calls it with just `args`.\n *\n * Sets `process.exitCode = 1` on failure (so the process exits non-zero\n * once the event loop drains) rather than calling `process.exit`, keeping\n * the function testable — same pattern as `audit-agent-web`.\n */\nexport async function runConnect(\n args: string[],\n deps: ConnectDeps = {},\n): Promise<void> {\n if (args[0] === \"--help\" || args[0] === \"-h\" || args[0] === \"help\") {\n logOut(HELP);\n return;\n }\n\n const parsed = parseConnectArgs(args);\n\n try {\n if (parsed.all) {\n const ok = await connectAll(parsed, deps);\n if (!ok) process.exitCode = 1;\n return;\n }\n\n if (!parsed.url) {\n logErr(\" Missing app URL.\");\n logErr(\"\");\n logOut(HELP);\n process.exitCode = 1;\n return;\n }\n\n const res = await connectOne(parsed.url, parsed, deps);\n if (!res.ok) process.exitCode = 1;\n } catch (err: any) {\n logErr(` ${err?.message ?? err}`);\n process.exitCode = 1;\n }\n}\n"]}
@@ -27,7 +27,7 @@ export interface HttpMcpEntry {
27
27
  headers?: Record<string, string>;
28
28
  }
29
29
  /** Build the HTTP MCP server entry for a deployed agent-native app. */
30
- export declare function buildHttpMcpEntry(mcpUrl: string, token?: string): HttpMcpEntry;
30
+ export declare function buildHttpMcpEntry(mcpUrl: string, token?: string, headers?: Record<string, string>): HttpMcpEntry;
31
31
  /**
32
32
  * Cowork consumes MCP exactly like Claude Code (same JSON server-entry
33
33
  * shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.
@@ -52,7 +52,7 @@ export declare function configPathFor(client: ClientId, baseDir: string, scope:
52
52
  export declare function writeJsonMcpEntry(file: string, name: string, entry: Record<string, unknown> | null): void;
53
53
  export declare function hasJsonMcpEntry(file: string, name: string): boolean;
54
54
  /** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */
55
- export declare function buildCodexHttpBlock(name: string, mcpUrl: string, token?: string): string;
55
+ export declare function buildCodexHttpBlock(name: string, mcpUrl: string, token?: string, headers?: Record<string, string>): string;
56
56
  /**
57
57
  * Replace (or append) the `[mcp_servers.<name>]` block in a TOML file
58
58
  * without disturbing other content. A block is the header line plus every
@@ -67,5 +67,5 @@ export declare function codexHasBlock(file: string, name: string): boolean;
67
67
  * given client's config file and return the file path that was written.
68
68
  * Re-running replaces the same named entry — never duplicates.
69
69
  */
70
- export declare function writeHttpEntryForClient(client: ClientId, serverName: string, mcpUrl: string, token: string | undefined, baseDir: string, scope: string | undefined): string;
70
+ export declare function writeHttpEntryForClient(client: ClientId, serverName: string, mcpUrl: string, token: string | undefined, baseDir: string, scope: string | undefined, headers?: Record<string, string>): string;
71
71
  //# sourceMappingURL=mcp-config-writers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,iBAAiB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE9E,eAAO,MAAM,OAAO,EAAE,QAAQ,EAK7B,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,YAAY,CAMd;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAYR;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,IAAI,CAYN;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnE;AAkBD,wEAAwE;AACxE,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,GACb,MAAM,CASR;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI,CA2CN;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAYjE;AAMD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAgBR"}
1
+ {"version":3,"file":"mcp-config-writers.d.ts","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,MAAM,QAAQ,GAAG,aAAa,GAAG,iBAAiB,GAAG,OAAO,GAAG,QAAQ,CAAC;AAE9E,eAAO,MAAM,OAAO,EAAE,QAAQ,EAK7B,CAAC;AAEF,mEAAmE;AACnE,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,uEAAuE;AACvE,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,YAAY,CAUd;AAMD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAE7C;AAED,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,MAAM,CAYR;AAgBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GACpC,IAAI,CAYN;AAED,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAGnE;AAkBD,wEAAwE;AACxE,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,CAAC,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAgBR;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GAAG,IAAI,GACnB,IAAI,CA2CN;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAYjE;AAMD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,QAAQ,EAChB,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,MAAM,CAmBR"}
@@ -28,11 +28,15 @@ export const CLIENTS = [
28
28
  "cowork",
29
29
  ];
30
30
  /** Build the HTTP MCP server entry for a deployed agent-native app. */
31
- export function buildHttpMcpEntry(mcpUrl, token) {
31
+ export function buildHttpMcpEntry(mcpUrl, token, headers) {
32
+ const mergedHeaders = {
33
+ ...(headers ?? {}),
34
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
35
+ };
32
36
  return {
33
37
  type: "http",
34
38
  url: mcpUrl,
35
- ...(token ? { headers: { Authorization: `Bearer ${token}` } } : {}),
39
+ ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),
36
40
  };
37
41
  }
38
42
  // ---------------------------------------------------------------------------
@@ -123,11 +127,18 @@ function legacyCodexMcpHeader(name) {
123
127
  return /^[A-Za-z0-9_-]+$/.test(name) ? `[mcp_servers.${name}]` : null;
124
128
  }
125
129
  /** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */
126
- export function buildCodexHttpBlock(name, mcpUrl, token) {
130
+ export function buildCodexHttpBlock(name, mcpUrl, token, headers) {
127
131
  const lines = [codexMcpHeader(name)];
128
132
  lines.push(`url = ${tomlQuote(mcpUrl)}`);
129
- if (token) {
130
- lines.push(`http_headers = { Authorization = ${tomlQuote(`Bearer ${token}`)} }`);
133
+ const mergedHeaders = {
134
+ ...(headers ?? {}),
135
+ ...(token ? { Authorization: `Bearer ${token}` } : {}),
136
+ };
137
+ const headerEntries = Object.entries(mergedHeaders);
138
+ if (headerEntries.length) {
139
+ lines.push(`http_headers = { ${headerEntries
140
+ .map(([key, value]) => `${tomlQuote(key)} = ${tomlQuote(value)}`)
141
+ .join(", ")} }`);
131
142
  }
132
143
  return lines.join("\n") + "\n";
133
144
  }
@@ -197,13 +208,13 @@ export function codexHasBlock(file, name) {
197
208
  * given client's config file and return the file path that was written.
198
209
  * Re-running replaces the same named entry — never duplicates.
199
210
  */
200
- export function writeHttpEntryForClient(client, serverName, mcpUrl, token, baseDir, scope) {
211
+ export function writeHttpEntryForClient(client, serverName, mcpUrl, token, baseDir, scope, headers) {
201
212
  const file = configPathFor(client, baseDir, scope);
202
213
  if (client === "codex") {
203
- writeCodexBlock(file, serverName, buildCodexHttpBlock(serverName, mcpUrl, token));
214
+ writeCodexBlock(file, serverName, buildCodexHttpBlock(serverName, mcpUrl, token, headers));
204
215
  }
205
216
  else {
206
- writeJsonMcpEntry(file, serverName, buildHttpMcpEntry(mcpUrl, token));
217
+ writeJsonMcpEntry(file, serverName, buildHttpMcpEntry(mcpUrl, token, headers));
207
218
  }
208
219
  return file;
209
220
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-config-writers.js","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared MCP client-config writers.\n *\n * Extracted so both `agent-native mcp install` (see `mcp.ts`) and\n * `agent-native connect` (see `connect.ts`) write the EXACT same on-disk\n * config file targets and formats for every supported client. `mcp.ts`\n * intentionally keeps its own hand-rolled copies of these writers (its\n * external behavior is unchanged); new code should import from here so the\n * formats never diverge.\n *\n * Supported clients and their config files:\n * - claude-code / claude-code-cli → `.mcp.json` (project) or\n * `~/.claude.json` (user). JSON `mcpServers[name] = entry`.\n * - cowork → `~/.cowork/mcp.json`. Same JSON shape.\n * - codex → `~/.codex/config.toml`.\n * `[mcp_servers.<name>]` block.\n *\n * Node-only. No new npm deps — hand-rolled JSON merge + minimal TOML block\n * merge, mirroring `mcp.ts`.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport type ClientId = \"claude-code\" | \"claude-code-cli\" | \"codex\" | \"cowork\";\n\nexport const CLIENTS: ClientId[] = [\n \"claude-code\",\n \"claude-code-cli\",\n \"codex\",\n \"cowork\",\n];\n\n/** The HTTP MCP server entry written into a JSON client config. */\nexport interface HttpMcpEntry {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Build the HTTP MCP server entry for a deployed agent-native app. */\nexport function buildHttpMcpEntry(\n mcpUrl: string,\n token?: string,\n): HttpMcpEntry {\n return {\n type: \"http\",\n url: mcpUrl,\n ...(token ? { headers: { Authorization: `Bearer ${token}` } } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Config file locations — kept identical to `mcp.ts`.\n// ---------------------------------------------------------------------------\n\n/**\n * Cowork consumes MCP exactly like Claude Code (same JSON server-entry\n * shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.\n */\nexport function coworkConfigPath(): string {\n return path.join(os.homedir(), \".cowork\", \"mcp.json\");\n}\n\nexport function claudeCodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".mcp.json\");\n}\n\nexport function claudeCodeUserConfig(): string {\n return path.join(os.homedir(), \".claude.json\");\n}\n\nexport function codexConfigPath(): string {\n return path.join(os.homedir(), \".codex\", \"config.toml\");\n}\n\n/**\n * Resolve the on-disk config path for a client.\n *\n * `scope` only affects Claude Code / Claude Code CLI: `\"user\"` → the global\n * `~/.claude.json`, anything else → the project-local `.mcp.json` rooted at\n * `baseDir`.\n */\nexport function configPathFor(\n client: ClientId,\n baseDir: string,\n scope: string | undefined,\n): string {\n switch (client) {\n case \"claude-code\":\n case \"claude-code-cli\":\n return scope === \"user\"\n ? claudeCodeUserConfig()\n : claudeCodeProjectConfig(baseDir);\n case \"cowork\":\n return coworkConfigPath();\n case \"codex\":\n return codexConfigPath();\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON client configs (Claude Code, Claude Code CLI, Cowork)\n// ---------------------------------------------------------------------------\n\nfunction readJsonFile(file: string): Record<string, any> {\n try {\n const raw = fs.readFileSync(file, \"utf-8\");\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Idempotently write `mcpServers[name] = entry` into a JSON config file.\n * Pass `entry === null` to delete the named entry. Re-running with the same\n * name replaces the existing entry in place — never duplicates.\n */\nexport function writeJsonMcpEntry(\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n const config = readJsonFile(file);\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n if (entry === null) {\n delete config.mcpServers[name];\n } else {\n config.mcpServers[name] = entry;\n }\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport function hasJsonMcpEntry(file: string, name: string): boolean {\n const config = readJsonFile(file);\n return !!config?.mcpServers && name in config.mcpServers;\n}\n\n// ---------------------------------------------------------------------------\n// Codex TOML (hand-rolled minimal block merge, no new dep)\n// ---------------------------------------------------------------------------\n\nfunction tomlQuote(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction codexMcpHeader(name: string): string {\n return `[mcp_servers.${tomlQuote(name)}]`;\n}\n\nfunction legacyCodexMcpHeader(name: string): string | null {\n return /^[A-Za-z0-9_-]+$/.test(name) ? `[mcp_servers.${name}]` : null;\n}\n\n/** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */\nexport function buildCodexHttpBlock(\n name: string,\n mcpUrl: string,\n token?: string,\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`url = ${tomlQuote(mcpUrl)}`);\n if (token) {\n lines.push(\n `http_headers = { Authorization = ${tomlQuote(`Bearer ${token}`)} }`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Replace (or append) the `[mcp_servers.<name>]` block in a TOML file\n * without disturbing other content. A block is the header line plus every\n * following line until the next top-level `[` table header or EOF. Pass\n * `block === null` to remove the block. Identical algorithm to `mcp.ts`'s\n * `writeCodexBlock` so the two never diverge.\n */\nexport function writeCodexBlock(\n file: string,\n name: string,\n block: string | null,\n): void {\n let content = \"\";\n try {\n content = fs.readFileSync(file, \"utf-8\");\n } catch {\n content = \"\";\n }\n\n const headers = new Set(\n [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(\n Boolean,\n ) as string[],\n );\n const lines = content.split(/\\r?\\n/);\n const out: string[] = [];\n let i = 0;\n let removed = false;\n while (i < lines.length) {\n const line = lines[i];\n if (headers.has(line.trim())) {\n // Skip this block entirely (header + body until next table header).\n removed = true;\n i++;\n while (i < lines.length && !/^\\s*\\[/.test(lines[i])) i++;\n continue;\n }\n out.push(line);\n i++;\n }\n\n let next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n if (block !== null) {\n next = next.replace(/\\n*$/, \"\\n\");\n if (next.trim().length) next += \"\\n\";\n next += block;\n }\n if (block === null && !removed) return; // nothing to do\n\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, next, \"utf-8\");\n}\n\nexport function codexHasBlock(file: string, name: string): boolean {\n try {\n const content = fs.readFileSync(file, \"utf-8\");\n const headers = new Set(\n [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(\n Boolean,\n ) as string[],\n );\n return content.split(/\\r?\\n/).some((line) => headers.has(line.trim()));\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unified write helper\n// ---------------------------------------------------------------------------\n\n/**\n * Idempotently write the HTTP MCP server entry for `serverName` into the\n * given client's config file and return the file path that was written.\n * Re-running replaces the same named entry — never duplicates.\n */\nexport function writeHttpEntryForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n token: string | undefined,\n baseDir: string,\n scope: string | undefined,\n): string {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n writeCodexBlock(\n file,\n serverName,\n buildCodexHttpBlock(serverName, mcpUrl, token),\n );\n } else {\n writeJsonMcpEntry(\n file,\n serverName,\n buildHttpMcpEntry(mcpUrl, token) as unknown as Record<string, unknown>,\n );\n }\n return file;\n}\n"]}
1
+ {"version":3,"file":"mcp-config-writers.js","sourceRoot":"","sources":["../../src/cli/mcp-config-writers.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Shared MCP client-config writers.\n *\n * Extracted so both `agent-native mcp install` (see `mcp.ts`) and\n * `agent-native connect` (see `connect.ts`) write the EXACT same on-disk\n * config file targets and formats for every supported client. `mcp.ts`\n * intentionally keeps its own hand-rolled copies of these writers (its\n * external behavior is unchanged); new code should import from here so the\n * formats never diverge.\n *\n * Supported clients and their config files:\n * - claude-code / claude-code-cli → `.mcp.json` (project) or\n * `~/.claude.json` (user). JSON `mcpServers[name] = entry`.\n * - cowork → `~/.cowork/mcp.json`. Same JSON shape.\n * - codex → `~/.codex/config.toml`.\n * `[mcp_servers.<name>]` block.\n *\n * Node-only. No new npm deps — hand-rolled JSON merge + minimal TOML block\n * merge, mirroring `mcp.ts`.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nexport type ClientId = \"claude-code\" | \"claude-code-cli\" | \"codex\" | \"cowork\";\n\nexport const CLIENTS: ClientId[] = [\n \"claude-code\",\n \"claude-code-cli\",\n \"codex\",\n \"cowork\",\n];\n\n/** The HTTP MCP server entry written into a JSON client config. */\nexport interface HttpMcpEntry {\n type: \"http\";\n url: string;\n headers?: Record<string, string>;\n}\n\n/** Build the HTTP MCP server entry for a deployed agent-native app. */\nexport function buildHttpMcpEntry(\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): HttpMcpEntry {\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n return {\n type: \"http\",\n url: mcpUrl,\n ...(Object.keys(mergedHeaders).length ? { headers: mergedHeaders } : {}),\n };\n}\n\n// ---------------------------------------------------------------------------\n// Config file locations — kept identical to `mcp.ts`.\n// ---------------------------------------------------------------------------\n\n/**\n * Cowork consumes MCP exactly like Claude Code (same JSON server-entry\n * shape). Resolved lazily so `os.homedir()` reflects the current `$HOME`.\n */\nexport function coworkConfigPath(): string {\n return path.join(os.homedir(), \".cowork\", \"mcp.json\");\n}\n\nexport function claudeCodeProjectConfig(baseDir: string): string {\n return path.join(baseDir, \".mcp.json\");\n}\n\nexport function claudeCodeUserConfig(): string {\n return path.join(os.homedir(), \".claude.json\");\n}\n\nexport function codexConfigPath(): string {\n return path.join(os.homedir(), \".codex\", \"config.toml\");\n}\n\n/**\n * Resolve the on-disk config path for a client.\n *\n * `scope` only affects Claude Code / Claude Code CLI: `\"user\"` → the global\n * `~/.claude.json`, anything else → the project-local `.mcp.json` rooted at\n * `baseDir`.\n */\nexport function configPathFor(\n client: ClientId,\n baseDir: string,\n scope: string | undefined,\n): string {\n switch (client) {\n case \"claude-code\":\n case \"claude-code-cli\":\n return scope === \"user\"\n ? claudeCodeUserConfig()\n : claudeCodeProjectConfig(baseDir);\n case \"cowork\":\n return coworkConfigPath();\n case \"codex\":\n return codexConfigPath();\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON client configs (Claude Code, Claude Code CLI, Cowork)\n// ---------------------------------------------------------------------------\n\nfunction readJsonFile(file: string): Record<string, any> {\n try {\n const raw = fs.readFileSync(file, \"utf-8\");\n const parsed = JSON.parse(raw);\n return parsed && typeof parsed === \"object\" ? parsed : {};\n } catch {\n return {};\n }\n}\n\n/**\n * Idempotently write `mcpServers[name] = entry` into a JSON config file.\n * Pass `entry === null` to delete the named entry. Re-running with the same\n * name replaces the existing entry in place — never duplicates.\n */\nexport function writeJsonMcpEntry(\n file: string,\n name: string,\n entry: Record<string, unknown> | null,\n): void {\n const config = readJsonFile(file);\n if (!config.mcpServers || typeof config.mcpServers !== \"object\") {\n config.mcpServers = {};\n }\n if (entry === null) {\n delete config.mcpServers[name];\n } else {\n config.mcpServers[name] = entry;\n }\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, JSON.stringify(config, null, 2) + \"\\n\", \"utf-8\");\n}\n\nexport function hasJsonMcpEntry(file: string, name: string): boolean {\n const config = readJsonFile(file);\n return !!config?.mcpServers && name in config.mcpServers;\n}\n\n// ---------------------------------------------------------------------------\n// Codex TOML (hand-rolled minimal block merge, no new dep)\n// ---------------------------------------------------------------------------\n\nfunction tomlQuote(s: string): string {\n return `\"${s.replace(/\\\\/g, \"\\\\\\\\\").replace(/\"/g, '\\\\\"')}\"`;\n}\n\nfunction codexMcpHeader(name: string): string {\n return `[mcp_servers.${tomlQuote(name)}]`;\n}\n\nfunction legacyCodexMcpHeader(name: string): string | null {\n return /^[A-Za-z0-9_-]+$/.test(name) ? `[mcp_servers.${name}]` : null;\n}\n\n/** Build a `[mcp_servers.<name>]` block for an HTTP-type MCP server. */\nexport function buildCodexHttpBlock(\n name: string,\n mcpUrl: string,\n token?: string,\n headers?: Record<string, string>,\n): string {\n const lines: string[] = [codexMcpHeader(name)];\n lines.push(`url = ${tomlQuote(mcpUrl)}`);\n const mergedHeaders = {\n ...(headers ?? {}),\n ...(token ? { Authorization: `Bearer ${token}` } : {}),\n };\n const headerEntries = Object.entries(mergedHeaders);\n if (headerEntries.length) {\n lines.push(\n `http_headers = { ${headerEntries\n .map(([key, value]) => `${tomlQuote(key)} = ${tomlQuote(value)}`)\n .join(\", \")} }`,\n );\n }\n return lines.join(\"\\n\") + \"\\n\";\n}\n\n/**\n * Replace (or append) the `[mcp_servers.<name>]` block in a TOML file\n * without disturbing other content. A block is the header line plus every\n * following line until the next top-level `[` table header or EOF. Pass\n * `block === null` to remove the block. Identical algorithm to `mcp.ts`'s\n * `writeCodexBlock` so the two never diverge.\n */\nexport function writeCodexBlock(\n file: string,\n name: string,\n block: string | null,\n): void {\n let content = \"\";\n try {\n content = fs.readFileSync(file, \"utf-8\");\n } catch {\n content = \"\";\n }\n\n const headers = new Set(\n [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(\n Boolean,\n ) as string[],\n );\n const lines = content.split(/\\r?\\n/);\n const out: string[] = [];\n let i = 0;\n let removed = false;\n while (i < lines.length) {\n const line = lines[i];\n if (headers.has(line.trim())) {\n // Skip this block entirely (header + body until next table header).\n removed = true;\n i++;\n while (i < lines.length && !/^\\s*\\[/.test(lines[i])) i++;\n continue;\n }\n out.push(line);\n i++;\n }\n\n let next = out\n .join(\"\\n\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .replace(/\\n*$/, \"\\n\");\n if (block !== null) {\n next = next.replace(/\\n*$/, \"\\n\");\n if (next.trim().length) next += \"\\n\";\n next += block;\n }\n if (block === null && !removed) return; // nothing to do\n\n fs.mkdirSync(path.dirname(file), { recursive: true });\n fs.writeFileSync(file, next, \"utf-8\");\n}\n\nexport function codexHasBlock(file: string, name: string): boolean {\n try {\n const content = fs.readFileSync(file, \"utf-8\");\n const headers = new Set(\n [codexMcpHeader(name), legacyCodexMcpHeader(name)].filter(\n Boolean,\n ) as string[],\n );\n return content.split(/\\r?\\n/).some((line) => headers.has(line.trim()));\n } catch {\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Unified write helper\n// ---------------------------------------------------------------------------\n\n/**\n * Idempotently write the HTTP MCP server entry for `serverName` into the\n * given client's config file and return the file path that was written.\n * Re-running replaces the same named entry — never duplicates.\n */\nexport function writeHttpEntryForClient(\n client: ClientId,\n serverName: string,\n mcpUrl: string,\n token: string | undefined,\n baseDir: string,\n scope: string | undefined,\n headers?: Record<string, string>,\n): string {\n const file = configPathFor(client, baseDir, scope);\n if (client === \"codex\") {\n writeCodexBlock(\n file,\n serverName,\n buildCodexHttpBlock(serverName, mcpUrl, token, headers),\n );\n } else {\n writeJsonMcpEntry(\n file,\n serverName,\n buildHttpMcpEntry(mcpUrl, token, headers) as unknown as Record<\n string,\n unknown\n >,\n );\n }\n return file;\n}\n"]}
@@ -36,6 +36,19 @@ export interface MCPConfig {
36
36
  version?: string;
37
37
  /** Action registry — same as agent chat and A2A */
38
38
  actions: Record<string, ActionEntry>;
39
+ /**
40
+ * Full ("production") action surface served to an **authenticated real
41
+ * caller** — a connect-minted token, an `agent-native mcp install` stdio
42
+ * proxy (owner-email header / `AGENT_NATIVE_OWNER_EMAIL`), or a deployed /
43
+ * `AGENT_MODE=production` app. In local dev `actions` is intentionally the
44
+ * sparse, dev-toggled surface (builtins + read-only public-agent actions)
45
+ * so the local agent chat and unauthenticated dev probes don't see every
46
+ * mutating tool; but per the external-agents contract a real caller that
47
+ * connected with a token MUST get the full surface even in dev. When unset
48
+ * (production, where `actions` already IS the full set) the swap is a
49
+ * no-op. See `external-agents` skill, "Dev vs production tool surface".
50
+ */
51
+ productionActions?: Record<string, ActionEntry>;
39
52
  /** Handler for the ask-agent meta-tool — runs the full agent loop */
40
53
  askAgent?: (message: string) => Promise<string>;
41
54
  /**
@@ -68,6 +81,15 @@ export interface MCPRequestMeta {
68
81
  origin?: string;
69
82
  /** Optional client preference for which URL the *markdown* link uses. */
70
83
  target?: "browser" | "desktop" | "terminal";
84
+ /**
85
+ * The caller authenticated with a real credential (verified A2A/connect
86
+ * JWT, matching ACCESS_TOKEN, or a forwarded owner-email header from
87
+ * `agent-native mcp install`) — not the unauthenticated local dev-open
88
+ * path. When true, `createMCPServerForRequest` serves
89
+ * `config.productionActions` (the full surface) instead of the sparse dev
90
+ * `config.actions`. Set by `mountMCP` from `verifyAuth`.
91
+ */
92
+ fullSurface?: boolean;
71
93
  }
72
94
  /**
73
95
  * Build the deep-link content block + structured `_meta` for a tool result.
@@ -144,9 +166,19 @@ export declare function getAccessTokens(): string[];
144
166
  * verified JWT identity), so the install flow runs tools as the configured
145
167
  * owner instead of an unscoped anonymous caller.
146
168
  */
147
- export declare function verifyAuth(authHeader: string | undefined, ownerEmailHeader?: string | undefined): Promise<{
169
+ export declare function verifyAuth(authHeader: string | undefined, ownerEmailHeader?: string | undefined, options?: {
170
+ allowDevOpen?: boolean;
171
+ }): Promise<{
148
172
  authed: boolean;
149
173
  identity?: MCPCallerIdentity;
174
+ /**
175
+ * The caller presented a real credential — a verified A2A/connect JWT, a
176
+ * matching ACCESS_TOKEN, or (on the no-auth-configured path) a forwarded
177
+ * owner-email header from `agent-native mcp install`. Drives the full vs
178
+ * sparse MCP tool surface in local dev. The pure unauthenticated dev-open
179
+ * path (no secret, no token, no owner header) is `false`.
180
+ */
181
+ fullSurface?: boolean;
150
182
  }>;
151
183
  export declare function resolveOrgIdFromDomain(orgDomain: string | undefined): Promise<string | undefined>;
152
184
  //# sourceMappingURL=build-server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-server.d.ts","sourceRoot":"","sources":["../../src/mcp/build-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAMhE,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED;;;kEAGkE;AAClE,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;CAC7C;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,cAAc,GAAG,SAAS,GAC/B;IACD,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAsBA;AA2BD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,WAAW,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8J7B;AAOD,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAc1C;AAyCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GACpC,OAAO,CAAC;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAA;CAAE,CAAC,CAkF5D;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS7B"}
1
+ {"version":3,"file":"build-server.d.ts","sourceRoot":"","sources":["../../src/mcp/build-server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAMhE,MAAM,WAAW,SAAS;IACxB,wCAAwC;IACxC,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;OAOG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,WAAW,EAAE,MAAM,CAAC;IACpB,uCAAuC;IACvC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,mDAAmD;IACnD,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACrC;;;;;;;;;;;OAWG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAChD,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAChD;;;;;;OAMG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED;;;kEAGkE;AAClE,MAAM,WAAW,cAAc;IAC7B,+DAA+D;IAC/D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,SAAS,GAAG,SAAS,GAAG,UAAU,CAAC;IAC5C;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,WAAW,EAClB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzB,MAAM,EAAE,GAAG,EACX,IAAI,EAAE,cAAc,GAAG,SAAS,GAC/B;IACD,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACvC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC,CAsBA;AA+BD;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,MAAM,EAAE,SAAS,EACjB,QAAQ,EAAE,iBAAiB,GAAG,SAAS,EACvC,WAAW,CAAC,EAAE,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAyK7B;AAOD,wBAAgB,eAAe,IAAI,MAAM,EAAE,CAc1C;AAyCD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,UAAU,CAC9B,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,EACrC,OAAO,GAAE;IAAE,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACvC,OAAO,CAAC;IACT,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;;;;;OAMG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB,CAAC,CA+FD;AAED,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAS7B"}
@@ -62,13 +62,13 @@ export function buildLinkArtifacts(entry, args, result, meta) {
62
62
  * The builtins are pure-ish navigators / scaffolders; they call back into the
63
63
  * same `config.actions` / `config.askAgent` so there is no second agent loop.
64
64
  */
65
- function mergeBuiltinTools(config) {
65
+ function mergeBuiltinTools(config, baseActions, requestMeta) {
66
66
  if (config.builtinCrossAppTools === false)
67
- return config.actions;
68
- const builtins = getBuiltinCrossAppTools(config);
67
+ return baseActions;
68
+ const builtins = getBuiltinCrossAppTools(config, requestMeta);
69
69
  const merged = { ...builtins };
70
70
  // Template / app actions overwrite same-named builtins.
71
- for (const [name, entry] of Object.entries(config.actions)) {
71
+ for (const [name, entry] of Object.entries(baseActions)) {
72
72
  merged[name] = entry;
73
73
  }
74
74
  return merged;
@@ -88,9 +88,6 @@ export async function createMCPServerForRequest(config, identity, requestMeta) {
88
88
  const { Server } = await import("@modelcontextprotocol/sdk/server/index.js");
89
89
  const { ListToolsRequestSchema, CallToolRequestSchema } = await import("@modelcontextprotocol/sdk/types.js");
90
90
  const server = new Server({ name: config.name, version: config.version ?? "1.0.0" }, { capabilities: { tools: {} } });
91
- // The action set the request handlers operate on = template actions +
92
- // generic cross-app builtins (template wins on name collision).
93
- const actions = mergeBuiltinTools(config);
94
91
  // Resolve the effective caller identity. JWT / header-derived identity
95
92
  // (passed by `mountMCP` via `verifyAuth`) wins. When the caller passed no
96
93
  // identity — the stdio **standalone** path — fall back to the
@@ -104,6 +101,19 @@ export async function createMCPServerForRequest(config, identity, requestMeta) {
104
101
  (ownerFromEnv
105
102
  ? { userEmail: ownerFromEnv, orgDomain: undefined }
106
103
  : undefined);
104
+ // The action set the request handlers operate on = base actions + generic
105
+ // cross-app builtins (template wins on name collision). An authenticated
106
+ // real caller (connect-minted token / `mcp install` owner / production —
107
+ // `requestMeta.fullSurface`, or the stdio standalone path identified by
108
+ // `AGENT_NATIVE_OWNER_EMAIL`) gets the full `productionActions` surface
109
+ // even in local dev; the unauthenticated dev-open path keeps the sparse
110
+ // `config.actions`. See `external-agents` skill, "Dev vs production tool
111
+ // surface".
112
+ const useFullSurface = requestMeta?.fullSurface === true || !!ownerFromEnv;
113
+ const baseActions = useFullSurface && config.productionActions
114
+ ? config.productionActions
115
+ : config.actions;
116
+ const actions = mergeBuiltinTools(config, baseActions, requestMeta);
107
117
  // Resolve orgId once per request (DB lookup) so subsequent wraps are
108
118
  // synchronous. The caller identity may be undefined for true dev-open —
109
119
  // in that case we run with no userEmail/orgId, which makes downstream
@@ -291,15 +301,24 @@ function deriveStaticTokenIdentity(ownerEmailHeader) {
291
301
  * verified JWT identity), so the install flow runs tools as the configured
292
302
  * owner instead of an unscoped anonymous caller.
293
303
  */
294
- export async function verifyAuth(authHeader, ownerEmailHeader) {
295
- // No auth configured → allow (dev mode). Still honour an owner hint
296
- // (env or forwarded header) so the install flow stays tenant-scoped.
304
+ export async function verifyAuth(authHeader, ownerEmailHeader, options = {}) {
305
+ // No auth configured → allow only when the route caller has already
306
+ // established that this is a loopback/local dev request. Still honour an
307
+ // owner hint there so the local install/connect flow stays tenant-scoped.
297
308
  const accessTokens = getAccessTokens();
298
309
  const hasA2ASecret = !!process.env.A2A_SECRET;
299
310
  if (accessTokens.length === 0 && !hasA2ASecret) {
311
+ if (options.allowDevOpen === false) {
312
+ return { authed: false };
313
+ }
300
314
  return {
301
315
  authed: true,
302
316
  identity: deriveStaticTokenIdentity(ownerEmailHeader),
317
+ // `mcp install`'s stdio proxy forwards an owner-email header even when
318
+ // the local app has no secret configured — that is a real, identified
319
+ // caller and gets the full surface. A bare browser/curl dev probe with
320
+ // no owner hint stays on the sparse dev surface.
321
+ fullSurface: !!(ownerEmailHeader && ownerEmailHeader.trim()),
303
322
  };
304
323
  }
305
324
  if (!authHeader?.startsWith("Bearer "))
@@ -347,6 +366,8 @@ export async function verifyAuth(authHeader, ownerEmailHeader) {
347
366
  ? payload.org_domain
348
367
  : undefined,
349
368
  },
369
+ // Verified JWT (connect-minted or A2A delegation) — a real caller.
370
+ fullSurface: true,
350
371
  };
351
372
  }
352
373
  catch {
@@ -360,6 +381,8 @@ export async function verifyAuth(authHeader, ownerEmailHeader) {
360
381
  return {
361
382
  authed: true,
362
383
  identity: deriveStaticTokenIdentity(ownerEmailHeader),
384
+ // Matched a configured ACCESS_TOKEN — a real caller.
385
+ fullSurface: true,
363
386
  };
364
387
  }
365
388
  return { authed: false };