@agent-native/core 0.22.12 → 0.22.15
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/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/registry.d.ts.map +1 -1
- package/dist/agent/engine/registry.js +13 -1
- package/dist/agent/engine/registry.js.map +1 -1
- package/dist/agent/model-config.d.ts +6 -6
- package/dist/agent/model-config.js +3 -3
- package/dist/agent/model-config.js.map +1 -1
- package/dist/chat-threads/store.d.ts.map +1 -1
- package/dist/chat-threads/store.js +6 -2
- package/dist/chat-threads/store.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
- package/dist/client/MultiTabAssistantChat.js +5 -6
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat.d.ts.map +1 -1
- package/dist/client/agent-chat.js +13 -0
- package/dist/client/agent-chat.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/mcp-app-host.d.ts +40 -0
- package/dist/client/mcp-app-host.d.ts.map +1 -0
- package/dist/client/mcp-app-host.js +165 -0
- package/dist/client/mcp-app-host.js.map +1 -0
- package/dist/client/sharing/ShareButton.d.ts +9 -0
- package/dist/client/sharing/ShareButton.d.ts.map +1 -1
- package/dist/client/sharing/ShareButton.js +19 -2
- package/dist/client/sharing/ShareButton.js.map +1 -1
- package/dist/client/use-chat-models.d.ts.map +1 -1
- package/dist/client/use-chat-models.js +4 -5
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/db/client.d.ts +1 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +33 -17
- package/dist/db/client.js.map +1 -1
- package/dist/db/create-get-db.d.ts.map +1 -1
- package/dist/db/create-get-db.js +2 -8
- package/dist/db/create-get-db.js.map +1 -1
- package/dist/index.browser.d.ts +2 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +2 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/build-server.d.ts +2 -0
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +59 -3
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/builtin-tools.d.ts.map +1 -1
- package/dist/mcp/builtin-tools.js +2 -4
- package/dist/mcp/builtin-tools.js.map +1 -1
- package/dist/mcp/connect-route.d.ts.map +1 -1
- package/dist/mcp/connect-route.js +14 -0
- package/dist/mcp/connect-route.js.map +1 -1
- package/dist/mcp/embed-app.d.ts.map +1 -1
- package/dist/mcp/embed-app.js +167 -1
- package/dist/mcp/embed-app.js.map +1 -1
- package/dist/mcp/embed-route.d.ts +26 -0
- package/dist/mcp/embed-route.d.ts.map +1 -0
- package/dist/mcp/embed-route.js +38 -0
- package/dist/mcp/embed-route.js.map +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +16 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.d.ts.map +1 -1
- package/dist/scripts/agent-engines/list-agent-engines.js +18 -12
- package/dist/scripts/agent-engines/list-agent-engines.js.map +1 -1
- package/dist/server/better-auth-instance.d.ts.map +1 -1
- package/dist/server/better-auth-instance.js +2 -1
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +22 -1
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/embed-route.d.ts.map +1 -1
- package/dist/server/embed-route.js +7 -1
- package/dist/server/embed-route.js.map +1 -1
- package/dist/server/embed-session.d.ts.map +1 -1
- package/dist/server/embed-session.js +55 -2
- package/dist/server/embed-session.js.map +1 -1
- package/dist/shared/embed-auth.d.ts +1 -0
- package/dist/shared/embed-auth.d.ts.map +1 -1
- package/dist/shared/embed-auth.js +1 -0
- package/dist/shared/embed-auth.js.map +1 -1
- package/dist/vite/client.d.ts +2 -0
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +5 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/actions.md +22 -7
- package/docs/content/client.md +43 -0
- package/docs/content/external-agents.md +40 -1
- package/docs/content/mcp-protocol.md +25 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed-app.js","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AAEA,MAAM,cAAc,GAClB,mEAAmE,CAAC;AAEtE,MAAM,CAAC,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAalE,SAAS,IAAI,CAAC,KAAyB;IACrC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,UAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;IAEnE,OAAO;QACL,KAAK;QACL,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,EAAE,GAAG,EAAE,CAAC;;;;;;;;;oDASoC,MAAM;;;;;;+CAMX,MAAM,GAAG,EAAE;oDACN,MAAM,GAAG,EAAE;iEACE,MAAM,GAAG,EAAE;;;;oBAIxD,IAAI,CAAC,KAAK,CAAC;uBACR,IAAI,CAAC,WAAW,CAAC;qBACnB,IAAI,CAAC,SAAS,CAAC;qBACf,IAAI,CAAC,aAAa,CAAC;wBAChB,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;;;4CAIN,IAAI,CAAC,KAAK,CAAC;;mDAEJ,IAAI,CAAC,SAAS,CAAC;;;;;;;;2BAQvC,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAwHjC;QACJ,GAAG,EAAE;YACH,cAAc,EAAE,CAAC,gBAAgB,CAAC;YAClC,eAAe,EAAE,CAAC,gBAAgB,CAAC;YACnC,YAAY,EAAE;gBACZ,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;SACF;QACD,aAAa,EAAE,KAAK;KACrB,CAAC;AACJ,CAAC","sourcesContent":["import type { ActionMcpAppResourceConfig } from \"../action.js\";\n\nconst MCP_APP_IMPORT =\n \"https://esm.sh/@modelcontextprotocol/ext-apps@1.7.2/app-with-deps\";\n\nexport const MCP_APP_REQUEST_ORIGIN_CSP_SOURCE = \"$requestOrigin\";\n\nexport interface EmbedAppOptions {\n title?: string;\n description?: string;\n iframeTitle?: string;\n openLabel?: string;\n embedByDefault?: boolean;\n startToolName?: string;\n frameDomains?: string[];\n height?: number;\n}\n\nfunction attr(value: string | undefined): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\nexport function embedApp(\n options: EmbedAppOptions = {},\n): ActionMcpAppResourceConfig {\n const title = options.title ?? \"Open app\";\n const iframeTitle = options.iframeTitle ?? \"Agent Native app\";\n const openLabel = options.openLabel ?? \"Open in app\";\n const startToolName = options.startToolName ?? \"create_embed_session\";\n const embedByDefault = options.embedByDefault !== false;\n const height = Math.max(320, Math.min(900, options.height ?? 900));\n\n return {\n title,\n ...(options.description ? { description: options.description } : {}),\n html: () => `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: Canvas; color: CanvasText; }\n * { box-sizing: border-box; }\n body { margin: 0; }\n .shell { display: grid; gap: 8px; min-height: ${height}px; padding: 0; }\n .bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, Canvas); }\n .title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: color-mix(in srgb, CanvasText 72%, Canvas); }\n .actions { display: flex; align-items: center; gap: 6px; }\n button { min-height: 28px; border: 1px solid color-mix(in srgb, CanvasText 14%, Canvas); border-radius: 7px; background: Canvas; color: CanvasText; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; padding: 0 9px; }\n button:disabled { opacity: .55; cursor: default; }\n .stage { position: relative; min-height: ${height - 44}px; }\n iframe { display: block; width: 100%; height: ${height - 44}px; border: 0; background: Canvas; }\n .message { display: grid; place-items: center; min-height: ${height - 44}px; padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }\n </style>\n</head>\n<body\n data-app-title=\"${attr(title)}\"\n data-iframe-title=\"${attr(iframeTitle)}\"\n data-open-label=\"${attr(openLabel)}\"\n data-start-tool=\"${attr(startToolName)}\"\n data-embed-default=\"${embedByDefault ? \"1\" : \"0\"}\"\n>\n <main class=\"shell\">\n <div class=\"bar\">\n <div class=\"title\" data-title-label>${attr(title)}</div>\n <div class=\"actions\">\n <button type=\"button\" data-open disabled>${attr(openLabel)}</button>\n </div>\n </div>\n <section class=\"stage\" data-stage>\n <div class=\"message\">Preparing app</div>\n </section>\n </main>\n <script type=\"module\">\n import { App } from \"${MCP_APP_IMPORT}\";\n\n const app = new App({ name: \"Agent Native Embed\", version: \"1.0.0\" }, {});\n const body = document.body;\n const stage = document.querySelector(\"[data-stage]\");\n const titleEl = document.querySelector(\"[data-title-label]\");\n const openButton = document.querySelector(\"[data-open]\");\n const startTool = body.dataset.startTool || \"create_embed_session\";\n const embedByDefault = body.dataset.embedDefault !== \"0\";\n let toolInput = {};\n let openUrl = \"\";\n let startedFor = \"\";\n\n function esc(value) {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n\n function parseJson(value, fallback) {\n if (value && typeof value === \"object\") return value;\n if (typeof value !== \"string\" || !value.trim()) return fallback;\n try { return JSON.parse(value); } catch { return fallback; }\n }\n\n function parseToolResult(params) {\n if (!params) return {};\n if (params.structuredContent && typeof params.structuredContent === \"object\") {\n return params.structuredContent;\n }\n const parts = Array.isArray(params.content) ? params.content : [];\n const textPart = parts.find((part) => part && part.type === \"text\" && typeof part.text === \"string\");\n return parseJson(textPart ? textPart.text : \"\", {});\n }\n\n function openLinkFrom(params, data) {\n const metaUrl = params && params._meta && params._meta[\"agent-native/openLink\"]\n ? params._meta[\"agent-native/openLink\"].webUrl\n : \"\";\n return metaUrl || data.url || data.deepLink || data.openUrl || \"\";\n }\n\n function wantsEmbed() {\n if (toolInput.embed === false || toolInput.embed === \"false\") return false;\n if (embedByDefault) return true;\n return toolInput.embed === true || toolInput.embed === \"true\";\n }\n\n function setMessage(message) {\n stage.innerHTML = '<div class=\"message\">' + esc(message) + '</div>';\n }\n\n function renderFrame(src) {\n const frame = document.createElement(\"iframe\");\n frame.title = body.dataset.iframeTitle || \"Agent Native app\";\n frame.src = src;\n frame.allow = \"clipboard-read; clipboard-write\";\n stage.replaceChildren(frame);\n }\n\n async function launchEmbed() {\n if (!openUrl) {\n setMessage(\"Open link was not available.\");\n return;\n }\n if (!wantsEmbed()) {\n setMessage(\"Ready to open.\");\n return;\n }\n if (startedFor === openUrl) return;\n startedFor = openUrl;\n setMessage(\"Loading app\");\n try {\n const result = await app.callServerTool({\n name: startTool,\n arguments: {\n url: openUrl,\n chrome: typeof toolInput.chrome === \"string\" ? toolInput.chrome : \"full\"\n }\n });\n const data = parseToolResult(result);\n if (!data.startUrl) {\n startedFor = \"\";\n setMessage(data.error || \"This app can be opened, but not embedded from this MCP server.\");\n return;\n }\n renderFrame(data.startUrl);\n } catch (err) {\n startedFor = \"\";\n setMessage(err && err.message ? err.message : \"Could not launch embedded app.\");\n }\n }\n\n function updateOpenButton() {\n openButton.disabled = !openUrl;\n openButton.onclick = () => {\n if (openUrl) void app.openLink({ url: openUrl });\n };\n }\n\n function updateTitle(data) {\n const label = data.label || data.app || data.view || body.dataset.appTitle || \"App\";\n titleEl.textContent = String(label);\n }\n\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n openUrl = openLinkFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n await app.connect();\n </script>\n</body>\n</html>`,\n csp: {\n connectDomains: [\"https://esm.sh\"],\n resourceDomains: [\"https://esm.sh\"],\n frameDomains: [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.frameDomains ?? []),\n ],\n },\n prefersBorder: false,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"embed-app.js","sourceRoot":"","sources":["../../src/mcp/embed-app.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,+BAA+B,EAAE,MAAM,yBAAyB,CAAC;AAE1E,MAAM,cAAc,GAClB,mEAAmE,CAAC;AAEtE,MAAM,CAAC,MAAM,iCAAiC,GAAG,gBAAgB,CAAC;AAalE,SAAS,IAAI,CAAC,KAAyB;IACrC,OAAO,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC3B,CAAC;AAED,MAAM,UAAU,QAAQ,CACtB,UAA2B,EAAE;IAE7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC;IAC1C,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,CAAC;IAC9D,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,aAAa,CAAC;IACrD,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,IAAI,sBAAsB,CAAC;IACtE,MAAM,cAAc,GAAG,OAAO,CAAC,cAAc,KAAK,KAAK,CAAC;IACxD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC;IAEnE,OAAO;QACL,KAAK;QACL,GAAG,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACpE,IAAI,EAAE,GAAG,EAAE,CAAC;;;;;;;;;oDASoC,MAAM;;;;;;+CAMX,MAAM,GAAG,EAAE;oDACN,MAAM,GAAG,EAAE;iEACE,MAAM,GAAG,EAAE;;;;oBAIxD,IAAI,CAAC,KAAK,CAAC;uBACR,IAAI,CAAC,WAAW,CAAC;qBACnB,IAAI,CAAC,SAAS,CAAC;qBACf,IAAI,CAAC,aAAa,CAAC;wBAChB,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG;;;;4CAIN,IAAI,CAAC,KAAK,CAAC;;;mDAGJ,IAAI,CAAC,SAAS,CAAC;;;;;;;;2BAQvC,cAAc;;;;;;;;;;8BAUX,IAAI,CAAC,SAAS,CAAC,+BAA+B,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QAkRrE;QACJ,GAAG,EAAE;YACH,cAAc,EAAE,CAAC,gBAAgB,CAAC;YAClC,eAAe,EAAE,CAAC,gBAAgB,CAAC;YACnC,YAAY,EAAE;gBACZ,iCAAiC;gBACjC,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC;aAChC;SACF;QACD,aAAa,EAAE,KAAK;KACrB,CAAC;AACJ,CAAC","sourcesContent":["import type { ActionMcpAppResourceConfig } from \"../action.js\";\nimport { MCP_APP_CHAT_BRIDGE_QUERY_PARAM } from \"../shared/embed-auth.js\";\n\nconst MCP_APP_IMPORT =\n \"https://esm.sh/@modelcontextprotocol/ext-apps@1.7.2/app-with-deps\";\n\nexport const MCP_APP_REQUEST_ORIGIN_CSP_SOURCE = \"$requestOrigin\";\n\nexport interface EmbedAppOptions {\n title?: string;\n description?: string;\n iframeTitle?: string;\n openLabel?: string;\n embedByDefault?: boolean;\n startToolName?: string;\n frameDomains?: string[];\n height?: number;\n}\n\nfunction attr(value: string | undefined): string {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/\"/g, \""\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\");\n}\n\nexport function embedApp(\n options: EmbedAppOptions = {},\n): ActionMcpAppResourceConfig {\n const title = options.title ?? \"Open app\";\n const iframeTitle = options.iframeTitle ?? \"Agent Native app\";\n const openLabel = options.openLabel ?? \"Open in app\";\n const startToolName = options.startToolName ?? \"create_embed_session\";\n const embedByDefault = options.embedByDefault !== false;\n const height = Math.max(320, Math.min(900, options.height ?? 900));\n\n return {\n title,\n ...(options.description ? { description: options.description } : {}),\n html: () => `<!doctype html>\n<html lang=\"en\">\n<head>\n <meta charset=\"utf-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n <style>\n :root { color-scheme: light dark; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif; background: Canvas; color: CanvasText; }\n * { box-sizing: border-box; }\n body { margin: 0; }\n .shell { display: grid; gap: 8px; min-height: ${height}px; padding: 0; }\n .bar { display: flex; align-items: center; justify-content: space-between; gap: 8px; min-height: 36px; padding: 6px 8px; border-bottom: 1px solid color-mix(in srgb, CanvasText 12%, Canvas); }\n .title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; color: color-mix(in srgb, CanvasText 72%, Canvas); }\n .actions { display: flex; align-items: center; gap: 6px; }\n button { min-height: 28px; border: 1px solid color-mix(in srgb, CanvasText 14%, Canvas); border-radius: 7px; background: Canvas; color: CanvasText; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; padding: 0 9px; }\n button:disabled { opacity: .55; cursor: default; }\n .stage { position: relative; min-height: ${height - 44}px; }\n iframe { display: block; width: 100%; height: ${height - 44}px; border: 0; background: Canvas; }\n .message { display: grid; place-items: center; min-height: ${height - 44}px; padding: 18px; color: color-mix(in srgb, CanvasText 62%, Canvas); font-size: 13px; line-height: 1.45; text-align: center; }\n </style>\n</head>\n<body\n data-app-title=\"${attr(title)}\"\n data-iframe-title=\"${attr(iframeTitle)}\"\n data-open-label=\"${attr(openLabel)}\"\n data-start-tool=\"${attr(startToolName)}\"\n data-embed-default=\"${embedByDefault ? \"1\" : \"0\"}\"\n>\n <main class=\"shell\">\n <div class=\"bar\">\n <div class=\"title\" data-title-label>${attr(title)}</div>\n <div class=\"actions\">\n <button type=\"button\" data-display hidden disabled>Fullscreen</button>\n <button type=\"button\" data-open disabled>${attr(openLabel)}</button>\n </div>\n </div>\n <section class=\"stage\" data-stage>\n <div class=\"message\">Preparing app</div>\n </section>\n </main>\n <script type=\"module\">\n import { App } from \"${MCP_APP_IMPORT}\";\n\n const app = new App({ name: \"Agent Native Embed\", version: \"1.0.0\" }, {});\n const body = document.body;\n const stage = document.querySelector(\"[data-stage]\");\n const titleEl = document.querySelector(\"[data-title-label]\");\n const openButton = document.querySelector(\"[data-open]\");\n const displayButton = document.querySelector(\"[data-display]\");\n const startTool = body.dataset.startTool || \"create_embed_session\";\n const embedByDefault = body.dataset.embedDefault !== \"0\";\n const chatBridgeParam = ${JSON.stringify(MCP_APP_CHAT_BRIDGE_QUERY_PARAM)};\n let toolInput = {};\n let openUrl = \"\";\n let startedFor = \"\";\n let appFrame = null;\n\n function esc(value) {\n return String(value ?? \"\")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\");\n }\n\n function parseJson(value, fallback) {\n if (value && typeof value === \"object\") return value;\n if (typeof value !== \"string\" || !value.trim()) return fallback;\n try { return JSON.parse(value); } catch { return fallback; }\n }\n\n function parseToolResult(params) {\n if (!params) return {};\n if (params.structuredContent && typeof params.structuredContent === \"object\") {\n return params.structuredContent;\n }\n const parts = Array.isArray(params.content) ? params.content : [];\n const textPart = parts.find((part) => part && part.type === \"text\" && typeof part.text === \"string\");\n return parseJson(textPart ? textPart.text : \"\", {});\n }\n\n function openLinkFrom(params, data) {\n const metaUrl = params && params._meta && params._meta[\"agent-native/openLink\"]\n ? params._meta[\"agent-native/openLink\"].webUrl\n : \"\";\n return metaUrl || data.url || data.deepLink || data.openUrl || \"\";\n }\n\n function hostState() {\n return {\n context: app.getHostContext ? app.getHostContext() : undefined,\n capabilities: app.getHostCapabilities ? app.getHostCapabilities() : undefined,\n version: app.getHostVersion ? app.getHostVersion() : undefined\n };\n }\n\n function sendToAppFrame(message) {\n if (!appFrame || !appFrame.contentWindow) return;\n try { appFrame.contentWindow.postMessage(message, \"*\"); } catch {}\n }\n\n function sendHostContext() {\n sendToAppFrame({ type: \"agentNative.mcpHostContext\", data: hostState() });\n }\n\n function sendFrameReadyMessages(frame) {\n const originPayload = { type: \"agentNative.frameOrigin\", origin: window.location.origin };\n [0, 200, 500, 1500].forEach((delay) => {\n setTimeout(() => {\n try { frame.contentWindow && frame.contentWindow.postMessage(originPayload, \"*\"); } catch {}\n sendHostContext();\n }, delay);\n });\n }\n\n function withChatBridgeParam(value) {\n if (typeof value !== \"string\" || !value) return value;\n try {\n const base = \"http://agent-native.invalid\";\n const url = value.startsWith(\"/\") ? new URL(value, base) : new URL(value);\n url.searchParams.set(chatBridgeParam, \"1\");\n return value.startsWith(\"/\")\n ? url.pathname + url.search + url.hash\n : url.toString();\n } catch {\n return value;\n }\n }\n\n function wantsEmbed() {\n if (toolInput.embed === false || toolInput.embed === \"false\") return false;\n if (embedByDefault) return true;\n return toolInput.embed === true || toolInput.embed === \"true\";\n }\n\n function supportedDisplayMode(mode) {\n const modes = hostState().context && hostState().context.availableDisplayModes;\n return Array.isArray(modes) && modes.includes(mode);\n }\n\n async function requestHostDisplayMode(mode) {\n const result = await app.requestDisplayMode({ mode });\n updateDisplayButton();\n sendHostContext();\n return result;\n }\n\n function updateDisplayButton() {\n const context = hostState().context || {};\n const nextMode = context.displayMode === \"fullscreen\" ? \"inline\" : \"fullscreen\";\n const supported = supportedDisplayMode(nextMode);\n displayButton.hidden = !supported;\n displayButton.disabled = !supported;\n displayButton.textContent = nextMode === \"fullscreen\" ? \"Fullscreen\" : \"Inline\";\n displayButton.onclick = () => {\n if (!supportedDisplayMode(nextMode)) return;\n void requestHostDisplayMode(nextMode).catch((err) => {\n console.warn(\"[agent-native] MCP host rejected display mode request\", err);\n });\n };\n }\n\n function setMessage(message) {\n stage.innerHTML = '<div class=\"message\">' + esc(message) + '</div>';\n }\n\n function renderFrame(src) {\n const frame = document.createElement(\"iframe\");\n frame.title = body.dataset.iframeTitle || \"Agent Native app\";\n frame.src = src;\n frame.allow = \"clipboard-read; clipboard-write\";\n appFrame = frame;\n frame.addEventListener(\"load\", () => sendFrameReadyMessages(frame));\n stage.replaceChildren(frame);\n }\n\n async function updateHostModelContext(data) {\n const params = {};\n if (Array.isArray(data && data.content)) params.content = data.content;\n if (data && data.structuredContent && typeof data.structuredContent === \"object\") {\n params.structuredContent = data.structuredContent;\n }\n await app.updateModelContext(params);\n }\n\n async function openHostLink(data) {\n const url = typeof (data && data.url) === \"string\" ? data.url : \"\";\n if (!url) return { isError: true };\n return await app.openLink({ url });\n }\n\n function respondToAppFrame(requestId, work) {\n if (!requestId) return;\n Promise.resolve(work)\n .then((result) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: { requestId, ok: true, result }\n });\n })\n .catch((err) => {\n sendToAppFrame({\n type: \"agentNative.mcpHost.response\",\n data: {\n requestId,\n ok: false,\n error: err && err.message ? err.message : String(err)\n }\n });\n });\n }\n\n async function sendHostChat(chat) {\n if (!chat || chat.submit === false) return;\n const message = typeof chat.message === \"string\" ? chat.message : \"\";\n if (!message.trim()) return;\n const context = typeof chat.context === \"string\" ? chat.context : \"\";\n if (context.trim()) {\n try {\n await app.updateModelContext({\n content: [{ type: \"text\", text: context }]\n });\n } catch (err) {\n console.warn(\"[agent-native] MCP host rejected model context update\", err);\n }\n }\n try {\n const result = await app.sendMessage({\n role: \"user\",\n content: [{ type: \"text\", text: message }]\n });\n if (result && result.isError) {\n console.warn(\"[agent-native] MCP host rejected chat message\", result);\n }\n } catch (err) {\n console.warn(\"[agent-native] MCP host chat bridge failed\", err);\n }\n }\n\n window.addEventListener(\"message\", (event) => {\n if (!appFrame || event.source !== appFrame.contentWindow) return;\n if (!event.data) return;\n const data = event.data.data || {};\n if (event.data.type === \"agentNative.submitChat\") {\n void sendHostChat(data);\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.updateModelContext\") {\n respondToAppFrame(data.requestId, updateHostModelContext(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.openLink\") {\n respondToAppFrame(data.requestId, openHostLink(data));\n return;\n }\n if (event.data.type === \"agentNative.mcpHost.requestDisplayMode\") {\n respondToAppFrame(data.requestId, requestHostDisplayMode(data.mode));\n }\n });\n\n async function launchEmbed() {\n if (!openUrl) {\n setMessage(\"Open link was not available.\");\n return;\n }\n if (!wantsEmbed()) {\n setMessage(\"Ready to open.\");\n return;\n }\n if (startedFor === openUrl) return;\n startedFor = openUrl;\n setMessage(\"Loading app\");\n try {\n const embedUrl = withChatBridgeParam(openUrl);\n const result = await app.callServerTool({\n name: startTool,\n arguments: {\n url: embedUrl,\n chrome: typeof toolInput.chrome === \"string\" ? toolInput.chrome : \"full\"\n }\n });\n const data = parseToolResult(result);\n if (!data.startUrl) {\n startedFor = \"\";\n setMessage(data.error || \"This app can be opened, but not embedded from this MCP server.\");\n return;\n }\n renderFrame(data.startUrl);\n } catch (err) {\n startedFor = \"\";\n setMessage(err && err.message ? err.message : \"Could not launch embedded app.\");\n }\n }\n\n function updateOpenButton() {\n openButton.disabled = !openUrl;\n openButton.onclick = () => {\n if (openUrl) void app.openLink({ url: openUrl });\n };\n }\n\n function updateTitle(data) {\n const label = data.label || data.app || data.view || body.dataset.appTitle || \"App\";\n titleEl.textContent = String(label);\n }\n\n app.ontoolinput = (params) => {\n toolInput = params.arguments || {};\n };\n app.ontoolresult = (params) => {\n const data = parseToolResult(params);\n openUrl = openLinkFrom(params, data);\n updateTitle(data);\n updateOpenButton();\n void launchEmbed();\n };\n app.onhostcontextchanged = () => {\n updateDisplayButton();\n sendHostContext();\n };\n await app.connect();\n updateDisplayButton();\n sendHostContext();\n </script>\n</body>\n</html>`,\n csp: {\n connectDomains: [\"https://esm.sh\"],\n resourceDomains: [\"https://esm.sh\"],\n frameDomains: [\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n ...(options.frameDomains ?? []),\n ],\n },\n prefersBorder: false,\n };\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ActionDeepLink, ActionLinkBuilder, ActionMcpAppConfig } from "../action.js";
|
|
2
|
+
import { type EmbedAppOptions } from "./embed-app.js";
|
|
3
|
+
export interface EmbedRouteContext<TArgs extends Record<string, any> = Record<string, any>, TResult = any> {
|
|
4
|
+
args: TArgs;
|
|
5
|
+
result: TResult;
|
|
6
|
+
}
|
|
7
|
+
export type EmbedRoutePathBuilder<TArgs extends Record<string, any> = Record<string, any>, TResult = any> = (ctx: EmbedRouteContext<TArgs, TResult>) => string | ActionDeepLink | null | undefined;
|
|
8
|
+
export interface EmbedRouteOptions<TArgs extends Record<string, any> = Record<string, any>, TResult = any> extends Pick<EmbedAppOptions, "description" | "iframeTitle" | "embedByDefault" | "startToolName" | "frameDomains" | "height"> {
|
|
9
|
+
title: string;
|
|
10
|
+
openLabel: string;
|
|
11
|
+
/** Build the app route or full deep-link surfaced after an action completes. */
|
|
12
|
+
path: EmbedRoutePathBuilder<TArgs, TResult>;
|
|
13
|
+
}
|
|
14
|
+
export interface EmbedRouteResult {
|
|
15
|
+
link: ActionLinkBuilder;
|
|
16
|
+
mcpApp: ActionMcpAppConfig;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Create matching action `link` and `mcpApp` metadata for an embeddable route.
|
|
20
|
+
*
|
|
21
|
+
* The `path` builder stays pure and synchronous, just like action link
|
|
22
|
+
* builders. Return an app-relative path string for the common case, or an
|
|
23
|
+
* `ActionDeepLink` when you need a custom label/view.
|
|
24
|
+
*/
|
|
25
|
+
export declare function embedRoute<TArgs extends Record<string, any> = Record<string, any>, TResult = any>(options: EmbedRouteOptions<TArgs, TResult>): EmbedRouteResult;
|
|
26
|
+
//# sourceMappingURL=embed-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-route.d.ts","sourceRoot":"","sources":["../../src/mcp/embed-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EAAY,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEhE,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvD,OAAO,GAAG,GAAG;IAEb,IAAI,EAAE,KAAK,CAAC;IACZ,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,MAAM,qBAAqB,CAC/B,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvD,OAAO,GAAG,GAAG,IACX,CACF,GAAG,EAAE,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,KACnC,MAAM,GAAG,cAAc,GAAG,IAAI,GAAG,SAAS,CAAC;AAEhD,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvD,OAAO,GAAG,GAAG,CACb,SAAQ,IAAI,CACZ,eAAe,EACb,aAAa,GACb,aAAa,GACb,gBAAgB,GAChB,eAAe,GACf,cAAc,GACd,QAAQ,CACX;IACC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,IAAI,EAAE,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,kBAAkB,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,KAAK,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACvD,OAAO,GAAG,GAAG,EACb,OAAO,EAAE,iBAAiB,CAAC,KAAK,EAAE,OAAO,CAAC,GAAG,gBAAgB,CA4B9D"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { embedApp } from "./embed-app.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create matching action `link` and `mcpApp` metadata for an embeddable route.
|
|
4
|
+
*
|
|
5
|
+
* The `path` builder stays pure and synchronous, just like action link
|
|
6
|
+
* builders. Return an app-relative path string for the common case, or an
|
|
7
|
+
* `ActionDeepLink` when you need a custom label/view.
|
|
8
|
+
*/
|
|
9
|
+
export function embedRoute(options) {
|
|
10
|
+
const label = options.openLabel;
|
|
11
|
+
return {
|
|
12
|
+
link: ({ args, result }) => {
|
|
13
|
+
const route = options.path({
|
|
14
|
+
args: args,
|
|
15
|
+
result: result,
|
|
16
|
+
});
|
|
17
|
+
if (!route)
|
|
18
|
+
return null;
|
|
19
|
+
if (typeof route === "string") {
|
|
20
|
+
return { url: route, label };
|
|
21
|
+
}
|
|
22
|
+
return route;
|
|
23
|
+
},
|
|
24
|
+
mcpApp: {
|
|
25
|
+
resource: embedApp({
|
|
26
|
+
title: options.title,
|
|
27
|
+
description: options.description,
|
|
28
|
+
iframeTitle: options.iframeTitle,
|
|
29
|
+
openLabel: options.openLabel,
|
|
30
|
+
embedByDefault: options.embedByDefault,
|
|
31
|
+
startToolName: options.startToolName,
|
|
32
|
+
frameDomains: options.frameDomains,
|
|
33
|
+
height: options.height,
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=embed-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embed-route.js","sourceRoot":"","sources":["../../src/mcp/embed-route.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAwB,MAAM,gBAAgB,CAAC;AAwChE;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAGxB,OAA0C;IAC1C,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC;IAEhC,OAAO;QACL,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;YACzB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC;gBACzB,IAAI,EAAE,IAAa;gBACnB,MAAM,EAAE,MAAiB;aAC1B,CAAC,CAAC;YACH,IAAI,CAAC,KAAK;gBAAE,OAAO,IAAI,CAAC;YACxB,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC9B,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;YAC/B,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,EAAE;YACN,QAAQ,EAAE,QAAQ,CAAC;gBACjB,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,cAAc,EAAE,OAAO,CAAC,cAAc;gBACtC,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,YAAY,EAAE,OAAO,CAAC,YAAY;gBAClC,MAAM,EAAE,OAAO,CAAC,MAAM;aACvB,CAAC;SACH;KACF,CAAC;AACJ,CAAC","sourcesContent":["import type {\n ActionDeepLink,\n ActionLinkBuilder,\n ActionMcpAppConfig,\n} from \"../action.js\";\nimport { embedApp, type EmbedAppOptions } from \"./embed-app.js\";\n\nexport interface EmbedRouteContext<\n TArgs extends Record<string, any> = Record<string, any>,\n TResult = any,\n> {\n args: TArgs;\n result: TResult;\n}\n\nexport type EmbedRoutePathBuilder<\n TArgs extends Record<string, any> = Record<string, any>,\n TResult = any,\n> = (\n ctx: EmbedRouteContext<TArgs, TResult>,\n) => string | ActionDeepLink | null | undefined;\n\nexport interface EmbedRouteOptions<\n TArgs extends Record<string, any> = Record<string, any>,\n TResult = any,\n> extends Pick<\n EmbedAppOptions,\n | \"description\"\n | \"iframeTitle\"\n | \"embedByDefault\"\n | \"startToolName\"\n | \"frameDomains\"\n | \"height\"\n> {\n title: string;\n openLabel: string;\n /** Build the app route or full deep-link surfaced after an action completes. */\n path: EmbedRoutePathBuilder<TArgs, TResult>;\n}\n\nexport interface EmbedRouteResult {\n link: ActionLinkBuilder;\n mcpApp: ActionMcpAppConfig;\n}\n\n/**\n * Create matching action `link` and `mcpApp` metadata for an embeddable route.\n *\n * The `path` builder stays pure and synchronous, just like action link\n * builders. Return an app-relative path string for the common case, or an\n * `ActionDeepLink` when you need a custom label/view.\n */\nexport function embedRoute<\n TArgs extends Record<string, any> = Record<string, any>,\n TResult = any,\n>(options: EmbedRouteOptions<TArgs, TResult>): EmbedRouteResult {\n const label = options.openLabel;\n\n return {\n link: ({ args, result }) => {\n const route = options.path({\n args: args as TArgs,\n result: result as TResult,\n });\n if (!route) return null;\n if (typeof route === \"string\") {\n return { url: route, label };\n }\n return route;\n },\n mcpApp: {\n resource: embedApp({\n title: options.title,\n description: options.description,\n iframeTitle: options.iframeTitle,\n openLabel: options.openLabel,\n embedByDefault: options.embedByDefault,\n startToolName: options.startToolName,\n frameDomains: options.frameDomains,\n height: options.height,\n }),\n },\n };\n}\n"]}
|
package/dist/mcp/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { runMCPStdio } from "./stdio.js";
|
|
|
6
6
|
export type { RunMCPStdioOptions } from "./stdio.js";
|
|
7
7
|
export { getBuiltinCrossAppTools } from "./builtin-tools.js";
|
|
8
8
|
export { embedApp, MCP_APP_REQUEST_ORIGIN_CSP_SOURCE, type EmbedAppOptions, } from "./embed-app.js";
|
|
9
|
+
export { embedRoute, type EmbedRouteContext, type EmbedRouteOptions, type EmbedRoutePathBuilder, type EmbedRouteResult, } from "./embed-route.js";
|
|
9
10
|
export { resolveWorkspace, resolveLocalAppOrigin, findWorkspaceRoot, } from "./workspace-resolve.js";
|
|
10
11
|
export type { ResolvedApp, ResolvedWorkspace } from "./workspace-resolve.js";
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/mcp/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,QAAQ,EACR,iCAAiC,EACjC,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAG7C,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG3E,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzC,YAAY,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,QAAQ,EACR,iCAAiC,EACjC,KAAK,eAAe,GACrB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,UAAU,EACV,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,EAC1B,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/mcp/index.js
CHANGED
|
@@ -6,6 +6,7 @@ export { runMCPStdio } from "./stdio.js";
|
|
|
6
6
|
// Generic cross-app builtin tools (merged into the registry, template wins).
|
|
7
7
|
export { getBuiltinCrossAppTools } from "./builtin-tools.js";
|
|
8
8
|
export { embedApp, MCP_APP_REQUEST_ORIGIN_CSP_SOURCE, } from "./embed-app.js";
|
|
9
|
+
export { embedRoute, } from "./embed-route.js";
|
|
9
10
|
// Workspace / app resolution helpers (Node-only).
|
|
10
11
|
export { resolveWorkspace, resolveLocalAppOrigin, findWorkspaceRoot, } from "./workspace-resolve.js";
|
|
11
12
|
//# sourceMappingURL=index.js.map
|
package/dist/mcp/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,iFAAiF;AACjF,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAG3B,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,6EAA6E;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,QAAQ,EACR,iCAAiC,GAElC,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAGvC,iFAAiF;AACjF,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,mBAAmB,CAAC;AAG3B,4DAA4D;AAC5D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGzC,6EAA6E;AAC7E,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EACL,QAAQ,EACR,iCAAiC,GAElC,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,UAAU,GAKX,MAAM,kBAAkB,CAAC;AAE1B,kDAAkD;AAClD,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,wBAAwB,CAAC","sourcesContent":["export { mountMCP } from \"./server.js\";\nexport type { MCPConfig } from \"./server.js\";\n\n// Shared MCP server builder (also re-exported from ./server.js for back-compat).\nexport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n} from \"./build-server.js\";\nexport type { MCPCallerIdentity, MCPRequestMeta } from \"./build-server.js\";\n\n// stdio transport for `agent-native mcp serve` (Node-only).\nexport { runMCPStdio } from \"./stdio.js\";\nexport type { RunMCPStdioOptions } from \"./stdio.js\";\n\n// Generic cross-app builtin tools (merged into the registry, template wins).\nexport { getBuiltinCrossAppTools } from \"./builtin-tools.js\";\nexport {\n embedApp,\n MCP_APP_REQUEST_ORIGIN_CSP_SOURCE,\n type EmbedAppOptions,\n} from \"./embed-app.js\";\nexport {\n embedRoute,\n type EmbedRouteContext,\n type EmbedRouteOptions,\n type EmbedRoutePathBuilder,\n type EmbedRouteResult,\n} from \"./embed-route.js\";\n\n// Workspace / app resolution helpers (Node-only).\nexport {\n resolveWorkspace,\n resolveLocalAppOrigin,\n findWorkspaceRoot,\n} from \"./workspace-resolve.js\";\nexport type { ResolvedApp, ResolvedWorkspace } from \"./workspace-resolve.js\";\n"]}
|
package/dist/mcp/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAWlC,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,CAAC;AACF,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAWlC,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,SAAS,EACd,KAAK,iBAAiB,EACtB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAM3B,OAAO,EACL,yBAAyB,EACzB,UAAU,EACV,eAAe,EACf,sBAAsB,EACtB,kBAAkB,GACnB,CAAC;AACF,YAAY,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC;AA2H7D;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,SAAS,GAChB,OAAO,CAAC,QAAQ,GAAG,MAAM,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CA4H5D;AAMD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,QAAQ,CACtB,QAAQ,EAAE,GAAG,EACb,MAAM,EAAE,SAAS,EACjB,WAAW,SAAmB,GAC7B,IAAI,CAYN"}
|
package/dist/mcp/server.js
CHANGED
|
@@ -44,6 +44,21 @@ function deriveRequestMeta(event) {
|
|
|
44
44
|
: undefined;
|
|
45
45
|
return { origin, target };
|
|
46
46
|
}
|
|
47
|
+
function isLoopbackOrigin(origin) {
|
|
48
|
+
if (!origin)
|
|
49
|
+
return false;
|
|
50
|
+
try {
|
|
51
|
+
const hostname = new URL(origin).hostname;
|
|
52
|
+
return (hostname === "localhost" ||
|
|
53
|
+
hostname === "127.0.0.1" ||
|
|
54
|
+
hostname === "::1" ||
|
|
55
|
+
hostname === "[::1]" ||
|
|
56
|
+
hostname.startsWith("127."));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
47
62
|
/**
|
|
48
63
|
* Reconstruct a Web Standard `Request` for the web-standard MCP transport.
|
|
49
64
|
*
|
|
@@ -149,7 +164,7 @@ export async function handleMcpRequest(event, config) {
|
|
|
149
164
|
// `fullSurface` would otherwise escalate to the full mutating surface.
|
|
150
165
|
const requestMeta = deriveRequestMeta(event);
|
|
151
166
|
const authResult = await verifyAuth(authHeader, ownerEmailHeader, {
|
|
152
|
-
allowDevOpen: isLoopbackRequest(event),
|
|
167
|
+
allowDevOpen: isLoopbackRequest(event) && isLoopbackOrigin(requestMeta.origin),
|
|
153
168
|
resourceUrl: getMcpOAuthResource(event),
|
|
154
169
|
});
|
|
155
170
|
if (!authResult.authed) {
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { isLoopbackRequest } from \"../server/auth.js\";\nimport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n type MCPConfig,\n type MCPCallerIdentity,\n type MCPRequestMeta,\n} from \"./build-server.js\";\nimport { buildMcpOAuthChallenge, getMcpOAuthResource } from \"./oauth-route.js\";\n\n// Re-export the shared MCP server builder + types so the stdio transport and\n// any (future) external importer of `@agent-native/core/mcp` keep resolving\n// against `./server.js` exactly as before this refactor.\nexport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n};\nexport type { MCPConfig, MCPCallerIdentity, MCPRequestMeta };\n\n// ---------------------------------------------------------------------------\n// Runtime detection — Node fast-path vs. web-standard fallback\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the underlying Node `http` req/res pair if (and only if) we're\n * running on a real Node HTTP server (local dev, `node` Nitro preset). On the\n * web-standard runtime (Nitro 3 / Netlify web runtime, Cloudflare, Deno, Bun)\n * BOTH of these are undefined — that's the signal to take the web fallback\n * instead of returning 501.\n */\nfunction getNodeReqRes(event: H3Event): {\n nodeReq: any | undefined;\n nodeRes: any | undefined;\n} {\n const e = event as any;\n const nodeReq = e.node?.req ?? e.req?.runtime?.node?.req;\n const nodeRes = e.node?.res ?? e.req?.runtime?.node?.res;\n return { nodeReq, nodeRes };\n}\n\n/**\n * Derive the request origin + the markdown deep-link target from the inbound\n * headers. Identical logic for both the Node and web paths so the absolute\n * deep-link URLs in tool results are computed the same way regardless of\n * runtime.\n */\nfunction deriveRequestMeta(event: H3Event): MCPRequestMeta {\n const forwardedProto = getRequestHeader(event, \"x-forwarded-proto\");\n const host = getRequestHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const origin = host ? `${proto}://${host}` : undefined;\n const targetHeader = getRequestHeader(\n event,\n \"x-agent-native-open-target\",\n )?.toLowerCase();\n const target =\n targetHeader === \"desktop\" ||\n targetHeader === \"terminal\" ||\n targetHeader === \"browser\"\n ? (targetHeader as MCPRequestMeta[\"target\"])\n : undefined;\n return { origin, target };\n}\n\n/**\n * Reconstruct a Web Standard `Request` for the web-standard MCP transport.\n *\n * On the web runtime h3 v2 exposes the real web `Request` as `event.req`; we\n * prefer it (its `method` / `headers` are exactly what the client sent). But\n * the framework middleware rewrites `event.req.url` when it strips a mount\n * prefix, and the transport reads `req.method` + `req.headers` (never the\n * body — we pass that via `parsedBody`), so we always synthesize a clean\n * `Request` with the verified method + a fresh `Headers` copy. The URL is\n * cosmetic for the SDK (it only does `new URL(req.url)` for `requestInfo`),\n * so a best-effort absolute URL derived from the inbound host is sufficient\n * and never throws.\n */\nfunction buildWebRequest(event: H3Event, method: string): Request {\n const src = (event as any).req as Request | undefined;\n\n const headers = new Headers();\n if (src?.headers && typeof src.headers.forEach === \"function\") {\n src.headers.forEach((value, key) => headers.set(key, value));\n } else {\n const rawHeaders = (event as any).node?.req?.headers as\n | Record<string, string | string[] | undefined>\n | undefined;\n if (rawHeaders) {\n for (const [key, value] of Object.entries(rawHeaders)) {\n if (value == null) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n }\n }\n\n // The SDK requires Accept + Content-Type to advertise both JSON and SSE on\n // a POST. Real MCP clients (Claude Code, `agent-native connect`) always\n // send these; we never inject/alter them — if they're absent the SDK\n // returns its spec-mandated 406/415, identical to the Node path.\n\n const host = headers.get(\"host\") || \"localhost\";\n const forwardedProto = headers.get(\"x-forwarded-proto\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (/^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n let url = `${proto}://${host}/_agent-native/mcp`;\n try {\n if (src?.url) url = new URL(src.url).href;\n } catch {\n // keep the synthesized URL\n }\n\n // No body here on purpose: the JSON-RPC payload is forwarded via the\n // transport's `parsedBody` option (the same mechanism the Node transport\n // uses), so the request stream is never read twice.\n return new Request(url, { method, headers });\n}\n\n// ---------------------------------------------------------------------------\n// handleMcpRequest — runtime-agnostic MCP request handler\n// ---------------------------------------------------------------------------\n\n/**\n * Handle a single `{routePrefix}/mcp` request on either runtime.\n *\n * - **Node fast-path** (real Node HTTP server): unchanged — delegate to the\n * SDK's `StreamableHTTPServerTransport.handleRequest(nodeReq, nodeRes,\n * body)`, which writes directly to the Node response (full protocol incl.\n * SSE).\n * - **Web-standard fallback** (Nitro 3 / Netlify web runtime, Cloudflare,\n * Deno, Bun — where there is no Node req/res): build the SAME MCP `Server`\n * from the SAME config + identity, drive it through the SDK's\n * `WebStandardStreamableHTTPServerTransport` (which the Node transport is\n * itself just a thin wrapper around), and return the resulting Web\n * `Response` as a normal h3 return value.\n *\n * Auth, the `runWithRequestContext` identity wrap, the deep-link `_meta` /\n * markdown append, `requestMeta` origin/target derivation and the stateless\n * semantics are IDENTICAL on both paths because both build the same server\n * via `createMCPServerForRequest` and both transports funnel into the same\n * `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n * parsedBody })` with the same options.\n *\n * Returns:\n * - `undefined` when the request targets a sub-route (so management/status\n * routes mounted under `/_agent-native/mcp/*` handle it themselves) — the\n * h3 mount falls through to the next handler.\n * - a Web `Response` (web fallback) or a string/object (Node path /\n * auth-error path) otherwise. The Node path also sets `_handled` so h3\n * doesn't double-write.\n */\nexport async function handleMcpRequest(\n event: H3Event,\n config: MCPConfig,\n): Promise<Response | string | { error: string } | undefined> {\n const pathname = event.url?.pathname || \"/\";\n const subpath = pathname.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (subpath) {\n // Let management/status routes mounted under /_agent-native/mcp/* handle\n // their own requests instead of treating them as MCP protocol traffic.\n return undefined;\n }\n\n const method = getMethod(event);\n\n // Auth check — extracts the caller's identity from the JWT (`sub`), or, on\n // the static-token / dev-open path, from the forwarded\n // `X-Agent-Native-Owner-Email` hint the stdio proxy sends (the\n // `agent-native mcp install` flow). Without this the install flow would run\n // every tool unscoped (userEmail === undefined).\n const authHeader = getRequestHeader(event, \"authorization\");\n const ownerEmailHeader = getRequestHeader(\n event,\n \"x-agent-native-owner-email\",\n );\n // Gate header-only dev-open on the REAL socket peer, never a parsed\n // `Host` header (client-controlled — an attacker could send\n // `Host: localhost`). A deployed app missing A2A_SECRET / ACCESS_TOKEN\n // must fail closed rather than trust a spoofable owner-email header that\n // `fullSurface` would otherwise escalate to the full mutating surface.\n const requestMeta = deriveRequestMeta(event);\n const authResult = await verifyAuth(authHeader, ownerEmailHeader, {\n allowDevOpen: isLoopbackRequest(event),\n resourceUrl: getMcpOAuthResource(event),\n });\n if (!authResult.authed) {\n setResponseStatus(event, 401);\n setResponseHeader(event, \"WWW-Authenticate\", buildMcpOAuthChallenge(event));\n return { error: \"Unauthorized\" };\n }\n\n // Stateless mode: only POST is meaningful\n if (method === \"DELETE\") {\n setResponseStatus(event, 204);\n return \"\";\n }\n\n if (method !== \"POST\" && method !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // Read body for POST (GET has no body). Read it via the h3 helper exactly\n // once; both transports accept it as a pre-parsed body so the request\n // stream is never consumed twice.\n const body = method === \"POST\" ? await readBody(event) : undefined;\n\n // Per-request stateless transport + server. Both runtimes build the SAME\n // server from the SAME config + verified identity + request meta, so\n // tools/list, tools/call, and the deep-link `_meta` are identical. A\n // connected real caller (connect-minted token / `mcp install` /\n // ACCESS_TOKEN / production) gets the full action surface even in local\n // dev; unauthenticated dev probes stay sparse. See `external-agents` skill.\n const server = await createMCPServerForRequest(config, authResult.identity, {\n ...requestMeta,\n fullSurface: authResult.fullSurface === true,\n });\n\n const { nodeReq, nodeRes } = getNodeReqRes(event);\n\n if (nodeReq && nodeRes) {\n // ---- Node fast-path (UNCHANGED behavior) --------------------------------\n const { StreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/streamableHttp.js\");\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless\n });\n await server.connect(transport);\n try {\n // The SDK transport writes directly to the Node response. Node-only by\n // construction; we only reach here when real Node req/res exist.\n await transport.handleRequest(nodeReq, nodeRes, body);\n } catch (err: any) {\n // The SDK transport writes directly to the Node response. If the socket\n // is already closed/ended (client disconnected, or the host stream\n // layer also flushed), Node throws ERR_STREAM_WRITE_AFTER_END *after*\n // the MCP payload was already delivered correctly. Swallow that benign\n // post-flush write so an external agent disconnecting mid-stream can\n // never take down the server process; rethrow anything else.\n if (err?.code !== \"ERR_STREAM_WRITE_AFTER_END\") throw err;\n if (process.env.DEBUG)\n console.log(\n \"[mcp] ignored post-flush ERR_STREAM_WRITE_AFTER_END (client disconnected)\",\n );\n }\n // Prevent H3 from double-writing the response\n (event as any)._handled = true;\n return undefined;\n }\n\n // ---- Web-standard fallback (Nitro 3 / Netlify web runtime, CF, Deno,\n // Bun) ---------------------------------------------------------------------\n //\n // `StreamableHTTPServerTransport` is itself just a thin wrapper that\n // converts the Node req/res to a web Request/Response and delegates to\n // `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n // parsedBody })`. Using the web transport directly with the SAME options +\n // the same pre-read `parsedBody` produces byte-identical protocol output\n // (including the deep-link `_meta` built inside createMCPServerForRequest),\n // and works on every web runtime because it returns a Web `Response`\n // (JSON for request/response, or an SSE `ReadableStream` body which h3\n // streams natively).\n const { WebStandardStreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\");\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless — same as the Node path\n });\n await server.connect(transport);\n const webRequest = buildWebRequest(event, method);\n // `parsedBody: undefined` would make the SDK try to read `req.json()`; our\n // synthesized request has no body, so only pass the option for POST (where\n // we actually have a parsed body). For GET the transport reads no body.\n const response = await transport.handleRequest(\n webRequest,\n method === \"POST\" ? { parsedBody: body } : undefined,\n );\n return response;\n}\n\n// ---------------------------------------------------------------------------\n// mountMCP — register MCP Streamable HTTP endpoint on H3/Nitro\n// ---------------------------------------------------------------------------\n\n/**\n * Mount an MCP remote server on an H3/Nitro app.\n *\n * Endpoint: `{routePrefix}/mcp` (default `/_agent-native/mcp`)\n *\n * Uses stateless Streamable HTTP transport — no in-memory sessions,\n * compatible with serverless deployments. Runtime-agnostic: a real Node\n * server uses the SDK's Node transport; the web-standard runtime (Nitro 3 /\n * Netlify web runtime, Cloudflare, Deno, Bun) uses the SDK's web-standard\n * transport. Both build the same server and produce identical JSON-RPC\n * output.\n *\n * Auth: Bearer token matching ACCESS_TOKEN/ACCESS_TOKENS or JWT via A2A_SECRET.\n * No auth required when neither is configured (dev mode).\n */\nexport function mountMCP(\n nitroApp: any,\n config: MCPConfig,\n routePrefix = \"/_agent-native\",\n): void {\n getH3App(nitroApp).use(\n `${routePrefix}/mcp`,\n defineEventHandler(async (event) => {\n return handleMcpRequest(event as H3Event, config);\n }),\n );\n\n if (process.env.DEBUG)\n console.log(\n `[mcp] Mounted MCP server at ${routePrefix}/mcp (${Object.keys(config.actions).length} tools${config.askAgent ? \" + ask-agent\" : \"\"})`,\n );\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/mcp/server.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getH3App } from \"../server/framework-request-handler.js\";\nimport {\n defineEventHandler,\n setResponseStatus,\n setResponseHeader,\n getMethod,\n getRequestHeader,\n} from \"h3\";\nimport { readBody } from \"../server/h3-helpers.js\";\nimport { isLoopbackRequest } from \"../server/auth.js\";\nimport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n type MCPConfig,\n type MCPCallerIdentity,\n type MCPRequestMeta,\n} from \"./build-server.js\";\nimport { buildMcpOAuthChallenge, getMcpOAuthResource } from \"./oauth-route.js\";\n\n// Re-export the shared MCP server builder + types so the stdio transport and\n// any (future) external importer of `@agent-native/core/mcp` keep resolving\n// against `./server.js` exactly as before this refactor.\nexport {\n createMCPServerForRequest,\n verifyAuth,\n getAccessTokens,\n resolveOrgIdFromDomain,\n buildLinkArtifacts,\n};\nexport type { MCPConfig, MCPCallerIdentity, MCPRequestMeta };\n\n// ---------------------------------------------------------------------------\n// Runtime detection — Node fast-path vs. web-standard fallback\n// ---------------------------------------------------------------------------\n\n/**\n * Resolve the underlying Node `http` req/res pair if (and only if) we're\n * running on a real Node HTTP server (local dev, `node` Nitro preset). On the\n * web-standard runtime (Nitro 3 / Netlify web runtime, Cloudflare, Deno, Bun)\n * BOTH of these are undefined — that's the signal to take the web fallback\n * instead of returning 501.\n */\nfunction getNodeReqRes(event: H3Event): {\n nodeReq: any | undefined;\n nodeRes: any | undefined;\n} {\n const e = event as any;\n const nodeReq = e.node?.req ?? e.req?.runtime?.node?.req;\n const nodeRes = e.node?.res ?? e.req?.runtime?.node?.res;\n return { nodeReq, nodeRes };\n}\n\n/**\n * Derive the request origin + the markdown deep-link target from the inbound\n * headers. Identical logic for both the Node and web paths so the absolute\n * deep-link URLs in tool results are computed the same way regardless of\n * runtime.\n */\nfunction deriveRequestMeta(event: H3Event): MCPRequestMeta {\n const forwardedProto = getRequestHeader(event, \"x-forwarded-proto\");\n const host = getRequestHeader(event, \"host\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (host && /^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n const origin = host ? `${proto}://${host}` : undefined;\n const targetHeader = getRequestHeader(\n event,\n \"x-agent-native-open-target\",\n )?.toLowerCase();\n const target =\n targetHeader === \"desktop\" ||\n targetHeader === \"terminal\" ||\n targetHeader === \"browser\"\n ? (targetHeader as MCPRequestMeta[\"target\"])\n : undefined;\n return { origin, target };\n}\n\nfunction isLoopbackOrigin(origin: string | undefined): boolean {\n if (!origin) return false;\n try {\n const hostname = new URL(origin).hostname;\n return (\n hostname === \"localhost\" ||\n hostname === \"127.0.0.1\" ||\n hostname === \"::1\" ||\n hostname === \"[::1]\" ||\n hostname.startsWith(\"127.\")\n );\n } catch {\n return false;\n }\n}\n\n/**\n * Reconstruct a Web Standard `Request` for the web-standard MCP transport.\n *\n * On the web runtime h3 v2 exposes the real web `Request` as `event.req`; we\n * prefer it (its `method` / `headers` are exactly what the client sent). But\n * the framework middleware rewrites `event.req.url` when it strips a mount\n * prefix, and the transport reads `req.method` + `req.headers` (never the\n * body — we pass that via `parsedBody`), so we always synthesize a clean\n * `Request` with the verified method + a fresh `Headers` copy. The URL is\n * cosmetic for the SDK (it only does `new URL(req.url)` for `requestInfo`),\n * so a best-effort absolute URL derived from the inbound host is sufficient\n * and never throws.\n */\nfunction buildWebRequest(event: H3Event, method: string): Request {\n const src = (event as any).req as Request | undefined;\n\n const headers = new Headers();\n if (src?.headers && typeof src.headers.forEach === \"function\") {\n src.headers.forEach((value, key) => headers.set(key, value));\n } else {\n const rawHeaders = (event as any).node?.req?.headers as\n | Record<string, string | string[] | undefined>\n | undefined;\n if (rawHeaders) {\n for (const [key, value] of Object.entries(rawHeaders)) {\n if (value == null) continue;\n headers.set(key, Array.isArray(value) ? value.join(\", \") : value);\n }\n }\n }\n\n // The SDK requires Accept + Content-Type to advertise both JSON and SSE on\n // a POST. Real MCP clients (Claude Code, `agent-native connect`) always\n // send these; we never inject/alter them — if they're absent the SDK\n // returns its spec-mandated 406/415, identical to the Node path.\n\n const host = headers.get(\"host\") || \"localhost\";\n const forwardedProto = headers.get(\"x-forwarded-proto\");\n const proto =\n forwardedProto?.split(\",\")[0]?.trim() ||\n (/^(localhost|127\\.0\\.0\\.1)(:|$)/.test(host) ? \"http\" : \"https\");\n let url = `${proto}://${host}/_agent-native/mcp`;\n try {\n if (src?.url) url = new URL(src.url).href;\n } catch {\n // keep the synthesized URL\n }\n\n // No body here on purpose: the JSON-RPC payload is forwarded via the\n // transport's `parsedBody` option (the same mechanism the Node transport\n // uses), so the request stream is never read twice.\n return new Request(url, { method, headers });\n}\n\n// ---------------------------------------------------------------------------\n// handleMcpRequest — runtime-agnostic MCP request handler\n// ---------------------------------------------------------------------------\n\n/**\n * Handle a single `{routePrefix}/mcp` request on either runtime.\n *\n * - **Node fast-path** (real Node HTTP server): unchanged — delegate to the\n * SDK's `StreamableHTTPServerTransport.handleRequest(nodeReq, nodeRes,\n * body)`, which writes directly to the Node response (full protocol incl.\n * SSE).\n * - **Web-standard fallback** (Nitro 3 / Netlify web runtime, Cloudflare,\n * Deno, Bun — where there is no Node req/res): build the SAME MCP `Server`\n * from the SAME config + identity, drive it through the SDK's\n * `WebStandardStreamableHTTPServerTransport` (which the Node transport is\n * itself just a thin wrapper around), and return the resulting Web\n * `Response` as a normal h3 return value.\n *\n * Auth, the `runWithRequestContext` identity wrap, the deep-link `_meta` /\n * markdown append, `requestMeta` origin/target derivation and the stateless\n * semantics are IDENTICAL on both paths because both build the same server\n * via `createMCPServerForRequest` and both transports funnel into the same\n * `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n * parsedBody })` with the same options.\n *\n * Returns:\n * - `undefined` when the request targets a sub-route (so management/status\n * routes mounted under `/_agent-native/mcp/*` handle it themselves) — the\n * h3 mount falls through to the next handler.\n * - a Web `Response` (web fallback) or a string/object (Node path /\n * auth-error path) otherwise. The Node path also sets `_handled` so h3\n * doesn't double-write.\n */\nexport async function handleMcpRequest(\n event: H3Event,\n config: MCPConfig,\n): Promise<Response | string | { error: string } | undefined> {\n const pathname = event.url?.pathname || \"/\";\n const subpath = pathname.replace(/^\\/+/, \"\").replace(/\\/+$/, \"\");\n if (subpath) {\n // Let management/status routes mounted under /_agent-native/mcp/* handle\n // their own requests instead of treating them as MCP protocol traffic.\n return undefined;\n }\n\n const method = getMethod(event);\n\n // Auth check — extracts the caller's identity from the JWT (`sub`), or, on\n // the static-token / dev-open path, from the forwarded\n // `X-Agent-Native-Owner-Email` hint the stdio proxy sends (the\n // `agent-native mcp install` flow). Without this the install flow would run\n // every tool unscoped (userEmail === undefined).\n const authHeader = getRequestHeader(event, \"authorization\");\n const ownerEmailHeader = getRequestHeader(\n event,\n \"x-agent-native-owner-email\",\n );\n // Gate header-only dev-open on the REAL socket peer, never a parsed\n // `Host` header (client-controlled — an attacker could send\n // `Host: localhost`). A deployed app missing A2A_SECRET / ACCESS_TOKEN\n // must fail closed rather than trust a spoofable owner-email header that\n // `fullSurface` would otherwise escalate to the full mutating surface.\n const requestMeta = deriveRequestMeta(event);\n const authResult = await verifyAuth(authHeader, ownerEmailHeader, {\n allowDevOpen:\n isLoopbackRequest(event) && isLoopbackOrigin(requestMeta.origin),\n resourceUrl: getMcpOAuthResource(event),\n });\n if (!authResult.authed) {\n setResponseStatus(event, 401);\n setResponseHeader(event, \"WWW-Authenticate\", buildMcpOAuthChallenge(event));\n return { error: \"Unauthorized\" };\n }\n\n // Stateless mode: only POST is meaningful\n if (method === \"DELETE\") {\n setResponseStatus(event, 204);\n return \"\";\n }\n\n if (method !== \"POST\" && method !== \"GET\") {\n setResponseStatus(event, 405);\n return { error: \"Method not allowed\" };\n }\n\n // Read body for POST (GET has no body). Read it via the h3 helper exactly\n // once; both transports accept it as a pre-parsed body so the request\n // stream is never consumed twice.\n const body = method === \"POST\" ? await readBody(event) : undefined;\n\n // Per-request stateless transport + server. Both runtimes build the SAME\n // server from the SAME config + verified identity + request meta, so\n // tools/list, tools/call, and the deep-link `_meta` are identical. A\n // connected real caller (connect-minted token / `mcp install` /\n // ACCESS_TOKEN / production) gets the full action surface even in local\n // dev; unauthenticated dev probes stay sparse. See `external-agents` skill.\n const server = await createMCPServerForRequest(config, authResult.identity, {\n ...requestMeta,\n fullSurface: authResult.fullSurface === true,\n });\n\n const { nodeReq, nodeRes } = getNodeReqRes(event);\n\n if (nodeReq && nodeRes) {\n // ---- Node fast-path (UNCHANGED behavior) --------------------------------\n const { StreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/streamableHttp.js\");\n const transport = new StreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless\n });\n await server.connect(transport);\n try {\n // The SDK transport writes directly to the Node response. Node-only by\n // construction; we only reach here when real Node req/res exist.\n await transport.handleRequest(nodeReq, nodeRes, body);\n } catch (err: any) {\n // The SDK transport writes directly to the Node response. If the socket\n // is already closed/ended (client disconnected, or the host stream\n // layer also flushed), Node throws ERR_STREAM_WRITE_AFTER_END *after*\n // the MCP payload was already delivered correctly. Swallow that benign\n // post-flush write so an external agent disconnecting mid-stream can\n // never take down the server process; rethrow anything else.\n if (err?.code !== \"ERR_STREAM_WRITE_AFTER_END\") throw err;\n if (process.env.DEBUG)\n console.log(\n \"[mcp] ignored post-flush ERR_STREAM_WRITE_AFTER_END (client disconnected)\",\n );\n }\n // Prevent H3 from double-writing the response\n (event as any)._handled = true;\n return undefined;\n }\n\n // ---- Web-standard fallback (Nitro 3 / Netlify web runtime, CF, Deno,\n // Bun) ---------------------------------------------------------------------\n //\n // `StreamableHTTPServerTransport` is itself just a thin wrapper that\n // converts the Node req/res to a web Request/Response and delegates to\n // `WebStandardStreamableHTTPServerTransport.handleRequest(webRequest, {\n // parsedBody })`. Using the web transport directly with the SAME options +\n // the same pre-read `parsedBody` produces byte-identical protocol output\n // (including the deep-link `_meta` built inside createMCPServerForRequest),\n // and works on every web runtime because it returns a Web `Response`\n // (JSON for request/response, or an SSE `ReadableStream` body which h3\n // streams natively).\n const { WebStandardStreamableHTTPServerTransport } =\n await import(\"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js\");\n const transport = new WebStandardStreamableHTTPServerTransport({\n sessionIdGenerator: undefined, // stateless — same as the Node path\n });\n await server.connect(transport);\n const webRequest = buildWebRequest(event, method);\n // `parsedBody: undefined` would make the SDK try to read `req.json()`; our\n // synthesized request has no body, so only pass the option for POST (where\n // we actually have a parsed body). For GET the transport reads no body.\n const response = await transport.handleRequest(\n webRequest,\n method === \"POST\" ? { parsedBody: body } : undefined,\n );\n return response;\n}\n\n// ---------------------------------------------------------------------------\n// mountMCP — register MCP Streamable HTTP endpoint on H3/Nitro\n// ---------------------------------------------------------------------------\n\n/**\n * Mount an MCP remote server on an H3/Nitro app.\n *\n * Endpoint: `{routePrefix}/mcp` (default `/_agent-native/mcp`)\n *\n * Uses stateless Streamable HTTP transport — no in-memory sessions,\n * compatible with serverless deployments. Runtime-agnostic: a real Node\n * server uses the SDK's Node transport; the web-standard runtime (Nitro 3 /\n * Netlify web runtime, Cloudflare, Deno, Bun) uses the SDK's web-standard\n * transport. Both build the same server and produce identical JSON-RPC\n * output.\n *\n * Auth: Bearer token matching ACCESS_TOKEN/ACCESS_TOKENS or JWT via A2A_SECRET.\n * No auth required when neither is configured (dev mode).\n */\nexport function mountMCP(\n nitroApp: any,\n config: MCPConfig,\n routePrefix = \"/_agent-native\",\n): void {\n getH3App(nitroApp).use(\n `${routePrefix}/mcp`,\n defineEventHandler(async (event) => {\n return handleMcpRequest(event as H3Event, config);\n }),\n );\n\n if (process.env.DEBUG)\n console.log(\n `[mcp] Mounted MCP server at ${routePrefix}/mcp (${Object.keys(config.actions).length} tools${config.askAgent ? \" + ask-agent\" : \"\"})`,\n );\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-agent-engines.d.ts","sourceRoot":"","sources":["../../../src/scripts/agent-engines/list-agent-engines.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAcvD,eAAO,MAAM,IAAI,EAAE,UAQlB,CAAC;AAEF,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"list-agent-engines.d.ts","sourceRoot":"","sources":["../../../src/scripts/agent-engines/list-agent-engines.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAcvD,eAAO,MAAM,IAAI,EAAE,UAQlB,CAAC;AAEF,wBAAsB,GAAG,CAAC,IAAI,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAyE5E"}
|
|
@@ -37,15 +37,19 @@ export async function run(args = {}) {
|
|
|
37
37
|
!!appDefaultEntry &&
|
|
38
38
|
(await isStoredEngineUsableForRequest(appDefault, appDefaultEntry));
|
|
39
39
|
const detectedFromUser = await detectEngineFromUserSecrets();
|
|
40
|
-
const
|
|
40
|
+
const envEntry = process.env.AGENT_ENGINE
|
|
41
41
|
? getAgentEngineEntry(process.env.AGENT_ENGINE)
|
|
42
|
-
: undefined
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
42
|
+
: undefined;
|
|
43
|
+
const envUnavailable = !!envEntry && !isAgentEnginePackageInstalled(envEntry);
|
|
44
|
+
const currentEntry = envUnavailable
|
|
45
|
+
? undefined
|
|
46
|
+
: (envEntry ??
|
|
47
|
+
(appDefaultUsable ? appDefaultEntry : undefined) ??
|
|
48
|
+
(detectedFromUser?.name === "builder" ? detectedFromUser : undefined) ??
|
|
49
|
+
(storedUsable ? storedEntry : undefined) ??
|
|
50
|
+
detectedFromUser ??
|
|
51
|
+
detectEngineFromEnv() ??
|
|
52
|
+
undefined);
|
|
49
53
|
const currentModel = appDefaultUsable && currentEntry?.name === appDefault?.engine
|
|
50
54
|
? appDefault?.model
|
|
51
55
|
: storedUsable && currentEntry?.name === current?.engine
|
|
@@ -64,10 +68,12 @@ export async function run(args = {}) {
|
|
|
64
68
|
installPackage: e.installPackage,
|
|
65
69
|
packageInstalled: isAgentEnginePackageInstalled(e),
|
|
66
70
|
})),
|
|
67
|
-
current:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
current: envUnavailable
|
|
72
|
+
? null
|
|
73
|
+
: {
|
|
74
|
+
engine: currentEngineName,
|
|
75
|
+
model: currentModel ?? currentEntry?.defaultModel ?? DEFAULT_MODEL,
|
|
76
|
+
},
|
|
71
77
|
};
|
|
72
78
|
return JSON.stringify(result, null, 2);
|
|
73
79
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-agent-engines.js","sourceRoot":"","sources":["../../../src/scripts/agent-engines/list-agent-engines.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EACL,gBAAgB,EAChB,sBAAsB,EACtB,mBAAmB,EACnB,2BAA2B,EAC3B,mBAAmB,EACnB,6BAA6B,EAC7B,8BAA8B,GAC/B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,wCAAwC,EAAE,MAAM,mCAAmC,CAAC;AAC7F,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD,MAAM,CAAC,MAAM,IAAI,GAAe;IAC9B,WAAW,EACT,mNAAmN;IACrN,UAAU,EAAE;QACV,IAAI,EAAE,QAAQ;QACd,UAAU,EAAE,EAAE;QACd,QAAQ,EAAE,EAAE;KACb;CACF,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,OAA+B,EAAE;IACzD,sBAAsB,EAAE,CAAC;IAEzB,MAAM,OAAO,GAAG,gBAAgB,EAAE,CAAC;IACnC,MAAM,cAAc,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC,CAAC;IACxD,MAAM,OAAO,GAAG,cAAc;QAC5B,CAAC,CAAE,cAAsD;QACzD,CAAC,CAAC,IAAI,CAAC;IAET,yEAAyE;IACzE,wEAAwE;IACxE,wEAAwE;IACxE,yEAAyE;IACzE,MAAM,WAAW,GACf,OAAO,OAAO,EAAE,MAAM,KAAK,QAAQ;QACjC,CAAC,CAAC,mBAAmB,CAAC,OAAO,CAAC,MAAM,CAAC;QACrC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,YAAY,GAChB,CAAC,CAAC,WAAW;QACb,CAAC,MAAM,8BAA8B,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC;IAC/D,MAAM,UAAU,GAAG,MAAM,wCAAwC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9E,MAAM,eAAe,GACnB,OAAO,UAAU,EAAE,MAAM,KAAK,QAAQ;QACpC,CAAC,CAAC,mBAAmB,CAAC,UAAU,CAAC,MAAM,CAAC;QACxC,CAAC,CAAC,SAAS,CAAC;IAChB,MAAM,gBAAgB,GACpB,CAAC,CAAC,UAAU;QACZ,CAAC,CAAC,eAAe;QACjB,CAAC,MAAM,8BAA8B,CAAC,UAAU,EAAE,eAAe,CAAC,CAAC,CAAC;IACtE,MAAM,gBAAgB,GAAG,MAAM,2BAA2B,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"list-agent-engines.js","sourceRoot":"","sources":["../../../src/scripts/agent-engines/list-agent-engines.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * list-agent-engines — returns the registered engine registry and current selection.\n */\n\nimport type { ActionTool } from \"../../agent/types.js\";\nimport {\n listAgentEngines,\n registerBuiltinEngines,\n detectEngineFromEnv,\n detectEngineFromUserSecrets,\n getAgentEngineEntry,\n isAgentEnginePackageInstalled,\n isStoredEngineUsableForRequest,\n} from \"../../agent/engine/index.js\";\nimport { DEFAULT_MODEL } from \"../../agent/default-model.js\";\nimport { getAgentAppModelDefaultForCurrentRequest } from \"../../agent/app-model-defaults.js\";\nimport { getSetting } from \"../../settings/index.js\";\n\nexport const tool: ActionTool = {\n description:\n 'List all available AI agent engines (Anthropic, OpenAI, Gemini, Groq, etc.) and the currently selected engine. Use this to check what engines are available before calling manage-agent-engine with action=\"set\".',\n parameters: {\n type: \"object\",\n properties: {},\n required: [],\n },\n};\n\nexport async function run(args: Record<string, string> = {}): Promise<string> {\n registerBuiltinEngines();\n\n const engines = listAgentEngines();\n const currentSetting = await getSetting(\"agent-engine\");\n const current = currentSetting\n ? (currentSetting as { engine?: string; model?: string })\n : null;\n\n // Same priority chain resolveEngine uses after explicit request options:\n // AGENT_ENGINE → app default → Builder app_secrets → stored (if usable)\n // → user BYOK app_secrets → env → anthropic. Gating stored/app defaults\n // on the request-aware helper keeps the picker in step with the runtime.\n const storedEntry =\n typeof current?.engine === \"string\"\n ? getAgentEngineEntry(current.engine)\n : undefined;\n const storedUsable =\n !!storedEntry &&\n (await isStoredEngineUsableForRequest(current, storedEntry));\n const appDefault = await getAgentAppModelDefaultForCurrentRequest(args.appId);\n const appDefaultEntry =\n typeof appDefault?.engine === \"string\"\n ? getAgentEngineEntry(appDefault.engine)\n : undefined;\n const appDefaultUsable =\n !!appDefault &&\n !!appDefaultEntry &&\n (await isStoredEngineUsableForRequest(appDefault, appDefaultEntry));\n const detectedFromUser = await detectEngineFromUserSecrets();\n const envEntry = process.env.AGENT_ENGINE\n ? getAgentEngineEntry(process.env.AGENT_ENGINE)\n : undefined;\n const envUnavailable = !!envEntry && !isAgentEnginePackageInstalled(envEntry);\n\n const currentEntry = envUnavailable\n ? undefined\n : (envEntry ??\n (appDefaultUsable ? appDefaultEntry : undefined) ??\n (detectedFromUser?.name === \"builder\" ? detectedFromUser : undefined) ??\n (storedUsable ? storedEntry : undefined) ??\n detectedFromUser ??\n detectEngineFromEnv() ??\n undefined);\n const currentModel =\n appDefaultUsable && currentEntry?.name === appDefault?.engine\n ? appDefault?.model\n : storedUsable && currentEntry?.name === current?.engine\n ? current?.model\n : undefined;\n const currentEngineName = currentEntry?.name ?? \"anthropic\";\n\n const result = {\n engines: engines.map((e) => ({\n name: e.name,\n label: e.label,\n description: e.description,\n defaultModel: e.defaultModel,\n supportedModels: e.supportedModels,\n capabilities: e.capabilities,\n requiredEnvVars: e.requiredEnvVars,\n installPackage: e.installPackage,\n packageInstalled: isAgentEnginePackageInstalled(e),\n })),\n current: envUnavailable\n ? null\n : {\n engine: currentEngineName,\n model: currentModel ?? currentEntry?.defaultModel ?? DEFAULT_MODEL,\n },\n };\n\n return JSON.stringify(result, null, 2);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"better-auth-instance.d.ts","sourceRoot":"","sources":["../../src/server/better-auth-instance.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"better-auth-instance.d.ts","sourceRoot":"","sources":["../../src/server/better-auth-instance.ts"],"names":[],"mappings":"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"}
|
|
@@ -21,7 +21,7 @@ import { saveOAuthTokens } from "../oauth-tokens/store.js";
|
|
|
21
21
|
import { identify, track } from "../tracking/index.js";
|
|
22
22
|
import { resolveAuthCookieNamespace } from "./cookie-namespace.js";
|
|
23
23
|
import { getWorkspaceA2ADerivedSecret } from "./derived-secret.js";
|
|
24
|
-
import { getDialect, getDatabaseUrl, getDatabaseAuthToken, pgPoolOptions, neonPoolMax, } from "../db/client.js";
|
|
24
|
+
import { getDialect, getDatabaseUrl, getDatabaseAuthToken, pgPoolOptions, neonPoolMax, attachNeonPoolErrorLogger, } from "../db/client.js";
|
|
25
25
|
import { pgTable, text as pgText, timestamp as pgTimestamp, boolean as pgBoolean, } from "drizzle-orm/pg-core";
|
|
26
26
|
import { sqliteTable, text as sqliteText, integer as sqliteInteger, } from "drizzle-orm/sqlite-core";
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
@@ -739,6 +739,7 @@ async function buildDatabaseConfig(dialect) {
|
|
|
739
739
|
connectionString: url,
|
|
740
740
|
max: neonPoolMax(),
|
|
741
741
|
});
|
|
742
|
+
attachNeonPoolErrorLogger(_neonAuthPool, "db/neon-auth");
|
|
742
743
|
const { drizzle } = await import("drizzle-orm/neon-serverless");
|
|
743
744
|
const db = drizzle(_neonAuthPool, { schema: pgAuthSchema });
|
|
744
745
|
const { drizzleAdapter } = await import("better-auth/adapters/drizzle");
|