@agent-native/core 0.104.0 → 0.106.0

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 (152) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/core/CHANGELOG.md +64 -0
  3. package/corpus/core/package.json +1 -1
  4. package/corpus/core/src/client/AgentPanel.tsx +1 -1
  5. package/corpus/core/src/client/AssistantChat.tsx +4 -0
  6. package/corpus/core/src/client/MultiTabAssistantChat.tsx +5 -1
  7. package/corpus/core/src/client/composer/PromptComposer.tsx +8 -0
  8. package/corpus/core/src/client/composer/TiptapComposer.tsx +38 -1
  9. package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +107 -32
  10. package/corpus/core/src/client/resources/mcp-integration-catalog.ts +33 -0
  11. package/corpus/core/src/client/resources/use-mcp-servers.ts +1 -0
  12. package/corpus/core/src/client/use-chat-models.ts +10 -2
  13. package/corpus/core/src/connections/catalog.ts +107 -6
  14. package/corpus/core/src/deploy/build.ts +23 -0
  15. package/corpus/core/src/localization/default-messages.ts +2 -0
  16. package/corpus/core/src/mcp/actions/call-mcp-tool.ts +18 -0
  17. package/corpus/core/src/mcp/actions/list-mcp-tools.ts +18 -0
  18. package/corpus/core/src/mcp-client/app-api.ts +136 -0
  19. package/corpus/core/src/mcp-client/index.ts +21 -0
  20. package/corpus/core/src/mcp-client/oauth-client.ts +462 -0
  21. package/corpus/core/src/mcp-client/oauth-routes.ts +307 -0
  22. package/corpus/core/src/mcp-client/remote-store.ts +93 -118
  23. package/corpus/core/src/mcp-client/remote-url.ts +97 -0
  24. package/corpus/core/src/mcp-client/routes.ts +11 -0
  25. package/corpus/core/src/oauth-tokens/store.ts +10 -4
  26. package/corpus/core/src/provider-api/index.ts +690 -55
  27. package/corpus/core/src/secrets/register-framework-secrets.ts +30 -0
  28. package/corpus/core/src/server/action-discovery.ts +2 -0
  29. package/corpus/core/src/server/core-routes-plugin.ts +9 -1
  30. package/corpus/core/src/server/workspace-provider-oauth.ts +448 -61
  31. package/corpus/core/src/templates/default/AGENTS.md +9 -7
  32. package/corpus/core/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
  33. package/corpus/templates/analytics/app/lib/data-source-status.ts +2 -0
  34. package/corpus/templates/analytics/app/pages/DataSources.tsx +61 -0
  35. package/corpus/templates/analytics/server/handlers/jira.ts +7 -0
  36. package/corpus/templates/analytics/server/lib/jira.ts +14 -42
  37. package/corpus/templates/analytics/server/routes/api/test-connection.post.ts +11 -0
  38. package/corpus/templates/clips/app/routes.ts +3 -1
  39. package/corpus/templates/dispatch/app/routes/integrations.tsx +57 -4
  40. package/dist/client/AgentPanel.js +1 -1
  41. package/dist/client/AgentPanel.js.map +1 -1
  42. package/dist/client/AssistantChat.d.ts +2 -0
  43. package/dist/client/AssistantChat.d.ts.map +1 -1
  44. package/dist/client/AssistantChat.js +2 -2
  45. package/dist/client/AssistantChat.js.map +1 -1
  46. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  47. package/dist/client/MultiTabAssistantChat.js +5 -2
  48. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  49. package/dist/client/composer/PromptComposer.d.ts +2 -0
  50. package/dist/client/composer/PromptComposer.d.ts.map +1 -1
  51. package/dist/client/composer/PromptComposer.js +5 -2
  52. package/dist/client/composer/PromptComposer.js.map +1 -1
  53. package/dist/client/composer/TiptapComposer.d.ts +4 -1
  54. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  55. package/dist/client/composer/TiptapComposer.js +13 -5
  56. package/dist/client/composer/TiptapComposer.js.map +1 -1
  57. package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
  58. package/dist/client/resources/McpIntegrationDialog.js +58 -14
  59. package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
  60. package/dist/client/resources/mcp-integration-catalog.d.ts +9 -0
  61. package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
  62. package/dist/client/resources/mcp-integration-catalog.js +13 -0
  63. package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
  64. package/dist/client/resources/use-mcp-servers.d.ts +1 -0
  65. package/dist/client/resources/use-mcp-servers.d.ts.map +1 -1
  66. package/dist/client/resources/use-mcp-servers.js.map +1 -1
  67. package/dist/client/use-chat-models.d.ts +1 -0
  68. package/dist/client/use-chat-models.d.ts.map +1 -1
  69. package/dist/client/use-chat-models.js +8 -2
  70. package/dist/client/use-chat-models.js.map +1 -1
  71. package/dist/collab/awareness.d.ts +2 -2
  72. package/dist/collab/awareness.d.ts.map +1 -1
  73. package/dist/collab/routes.d.ts +1 -1
  74. package/dist/connections/catalog.d.ts +78 -7
  75. package/dist/connections/catalog.d.ts.map +1 -1
  76. package/dist/connections/catalog.js +97 -6
  77. package/dist/connections/catalog.js.map +1 -1
  78. package/dist/deploy/build.d.ts.map +1 -1
  79. package/dist/deploy/build.js +17 -0
  80. package/dist/deploy/build.js.map +1 -1
  81. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  82. package/dist/localization/default-messages.d.ts +2 -0
  83. package/dist/localization/default-messages.d.ts.map +1 -1
  84. package/dist/localization/default-messages.js +2 -0
  85. package/dist/localization/default-messages.js.map +1 -1
  86. package/dist/mcp/actions/call-mcp-tool.d.ts +7 -0
  87. package/dist/mcp/actions/call-mcp-tool.d.ts.map +1 -0
  88. package/dist/mcp/actions/call-mcp-tool.js +15 -0
  89. package/dist/mcp/actions/call-mcp-tool.js.map +1 -0
  90. package/dist/mcp/actions/list-mcp-tools.d.ts +5 -0
  91. package/dist/mcp/actions/list-mcp-tools.d.ts.map +1 -0
  92. package/dist/mcp/actions/list-mcp-tools.js +16 -0
  93. package/dist/mcp/actions/list-mcp-tools.js.map +1 -0
  94. package/dist/mcp-client/app-api.d.ts +34 -0
  95. package/dist/mcp-client/app-api.d.ts.map +1 -0
  96. package/dist/mcp-client/app-api.js +94 -0
  97. package/dist/mcp-client/app-api.js.map +1 -0
  98. package/dist/mcp-client/index.d.ts +3 -1
  99. package/dist/mcp-client/index.d.ts.map +1 -1
  100. package/dist/mcp-client/index.js +3 -1
  101. package/dist/mcp-client/index.js.map +1 -1
  102. package/dist/mcp-client/oauth-client.d.ts +113 -0
  103. package/dist/mcp-client/oauth-client.d.ts.map +1 -0
  104. package/dist/mcp-client/oauth-client.js +316 -0
  105. package/dist/mcp-client/oauth-client.js.map +1 -0
  106. package/dist/mcp-client/oauth-routes.d.ts +25 -0
  107. package/dist/mcp-client/oauth-routes.d.ts.map +1 -0
  108. package/dist/mcp-client/oauth-routes.js +218 -0
  109. package/dist/mcp-client/oauth-routes.js.map +1 -0
  110. package/dist/mcp-client/remote-store.d.ts +21 -6
  111. package/dist/mcp-client/remote-store.d.ts.map +1 -1
  112. package/dist/mcp-client/remote-store.js +72 -124
  113. package/dist/mcp-client/remote-store.js.map +1 -1
  114. package/dist/mcp-client/remote-url.d.ts +8 -0
  115. package/dist/mcp-client/remote-url.d.ts.map +1 -0
  116. package/dist/mcp-client/remote-url.js +103 -0
  117. package/dist/mcp-client/remote-url.js.map +1 -0
  118. package/dist/mcp-client/routes.d.ts +1 -0
  119. package/dist/mcp-client/routes.d.ts.map +1 -1
  120. package/dist/mcp-client/routes.js +9 -0
  121. package/dist/mcp-client/routes.js.map +1 -1
  122. package/dist/notifications/routes.d.ts +3 -3
  123. package/dist/oauth-tokens/store.d.ts +2 -2
  124. package/dist/oauth-tokens/store.d.ts.map +1 -1
  125. package/dist/oauth-tokens/store.js +10 -6
  126. package/dist/oauth-tokens/store.js.map +1 -1
  127. package/dist/observability/routes.d.ts +5 -5
  128. package/dist/progress/routes.d.ts +1 -1
  129. package/dist/provider-api/index.d.ts +14 -0
  130. package/dist/provider-api/index.d.ts.map +1 -1
  131. package/dist/provider-api/index.js +499 -61
  132. package/dist/provider-api/index.js.map +1 -1
  133. package/dist/resources/handlers.d.ts +1 -1
  134. package/dist/secrets/register-framework-secrets.d.ts.map +1 -1
  135. package/dist/secrets/register-framework-secrets.js +28 -0
  136. package/dist/secrets/register-framework-secrets.js.map +1 -1
  137. package/dist/secrets/routes.d.ts +9 -9
  138. package/dist/server/action-discovery.d.ts.map +1 -1
  139. package/dist/server/action-discovery.js +2 -0
  140. package/dist/server/action-discovery.js.map +1 -1
  141. package/dist/server/core-routes-plugin.d.ts.map +1 -1
  142. package/dist/server/core-routes-plugin.js +9 -1
  143. package/dist/server/core-routes-plugin.js.map +1 -1
  144. package/dist/server/workspace-provider-oauth.d.ts +10 -3
  145. package/dist/server/workspace-provider-oauth.d.ts.map +1 -1
  146. package/dist/server/workspace-provider-oauth.js +325 -43
  147. package/dist/server/workspace-provider-oauth.js.map +1 -1
  148. package/dist/templates/default/AGENTS.md +9 -7
  149. package/dist/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
  150. package/package.json +2 -2
  151. package/src/templates/default/AGENTS.md +9 -7
  152. package/src/templates/workspace-core/.agents/skills/external-agents/SKILL.md +46 -0
@@ -1 +1 @@
1
- {"version":3,"file":"remote-store.js","sourceRoot":"","sources":["../../src/mcp-client/remote-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent store for user-added remote MCP servers.\n *\n * Servers added through the settings UI live in the framework's `settings`\n * table, keyed by scope:\n * - User scope: `u:<email>:mcp-servers-remote`\n * - Org scope: `o:<orgId>:mcp-servers-remote`\n *\n * Both scopes store the same shape — a list of `StoredRemoteMcpServer`\n * records. The running MCP manager merges this list with the file-based\n * `mcp.config.json` on startup and after every mutation.\n *\n * SECURITY: HTTP MCP servers commonly require a bearer token in the\n * `Authorization` header. Those values are written to the encrypted\n * `app_secrets` table (AES-256-GCM via writeAppSecret). The settings row\n * stores only the secret-key reference (`headerSecretKey`), not the raw\n * value. Callers retrieving headers must call `materializeHeaders` to\n * fetch the cleartext at request time. Legacy rows that wrote headers\n * cleartext into `headers` continue to work read-only — they should be\n * re-saved to migrate.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport type { SecretScope } from \"../secrets/register.js\";\nimport {\n writeAppSecret,\n readAppSecret,\n deleteAppSecret,\n} from \"../secrets/storage.js\";\nimport {\n getOrgSetting,\n putOrgSetting,\n deleteOrgSetting,\n} from \"../settings/org-settings.js\";\nimport {\n getUserSetting,\n putUserSetting,\n deleteUserSetting,\n} from \"../settings/user-settings.js\";\nimport type { McpHttpServerConfig } from \"./config.js\";\n\nconst SETTINGS_KEY = \"mcp-servers-remote\";\n\nexport type RemoteMcpScope = \"user\" | \"org\";\n\nfunction toSecretScope(scope: RemoteMcpScope): SecretScope {\n return scope === \"user\" ? \"user\" : \"workspace\";\n}\n\nexport interface StoredRemoteMcpServer {\n /** Stable unique id — used for removal / URLs. */\n id: string;\n /** Human-readable name. Also used as the MCP server id (prefixed with scope). */\n name: string;\n /** Streamable HTTP MCP server URL. */\n url: string;\n /**\n * Optional non-secret headers to pass to the MCP server. SECURITY: secret\n * material (Authorization, X-Api-Key, …) is moved out of this field at\n * write time and stored encrypted in `app_secrets`; see\n * `headerSecretKey`. Legacy rows may still contain cleartext headers and\n * are honored read-only.\n */\n headers?: Record<string, string>;\n /**\n * Reference to the encrypted secret holding the JSON-stringified secret\n * headers map (e.g. `{\"Authorization\":\"Bearer …\"}`). Resolved at request\n * time via `readAppSecret`. Undefined when no secret-class headers were\n * supplied (or for legacy cleartext rows).\n */\n headerSecretKey?: string;\n /**\n * Trusted first-party Agent-Native app. Only framework-controlled\n * registrations should set this; management routes intentionally do not\n * expose it for arbitrary user-added MCP servers.\n */\n firstParty?: boolean;\n /** Canonical first-party app id from the org directory, e.g. `assets`. */\n firstPartyAppId?: string;\n /** Optional description shown in the UI. */\n description?: string;\n /** ms since epoch. */\n createdAt: number;\n}\n\n/**\n * Header names that are routed through the encrypted-at-rest secrets store\n * instead of being written to the plaintext `settings` row. Match is\n * case-insensitive and substring-based to catch one-off names like\n * `x-zapier-api-key`.\n */\nconst SECRET_HEADER_NAME_PATTERNS = [\n /authorization/i,\n /api[-_]?key/i,\n /token/i,\n /secret/i,\n /bearer/i,\n /x-.*-key/i,\n];\n\nfunction isSecretHeaderName(name: string): boolean {\n return SECRET_HEADER_NAME_PATTERNS.some((re) => re.test(name));\n}\n\n/** Split a headers map into (cleartext, secret) buckets. */\nfunction partitionHeaders(headers: Record<string, string> | undefined): {\n cleartext: Record<string, string> | undefined;\n secret: Record<string, string> | undefined;\n} {\n if (!headers) return { cleartext: undefined, secret: undefined };\n const cleartext: Record<string, string> = {};\n const secret: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n if (typeof v !== \"string\") continue;\n if (isSecretHeaderName(k)) secret[k] = v;\n else cleartext[k] = v;\n }\n return {\n cleartext: Object.keys(cleartext).length > 0 ? cleartext : undefined,\n secret: Object.keys(secret).length > 0 ? secret : undefined,\n };\n}\n\n/** Tiny nanoid — matches the inline helper used elsewhere in this package. */\nfunction shortId(): string {\n const rand =\n globalThis.crypto?.randomUUID?.().replace(/-/g, \"\") ??\n Math.random().toString(36).slice(2) + Date.now().toString(36);\n return rand.slice(0, 16);\n}\n\n/**\n * Validate a candidate MCP server name — used as a key in the merged config\n * and as part of the prefixed tool name (`mcp__<merged-key>__<tool>`).\n *\n * Allowed: letters, digits, hyphen; 1–40 chars. Lowercased. Underscores are\n * excluded on purpose — the merged-key format uses `_` as a separator between\n * `<scope>`, `<owner>`, and `<name>`, so allowing `_` in names would make the\n * parse ambiguous.\n */\nexport function normalizeServerName(input: string): string {\n return input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .slice(0, 40);\n}\n\n/**\n * Short, deterministic, URL-safe hash of an email. Used as the owner\n * discriminator in user-scope merged keys so two users with the same server\n * name don't collide in the global MCP manager.\n */\nexport function hashEmail(email: string): string {\n return createHash(\"sha256\")\n .update(email.toLowerCase().trim())\n .digest(\"hex\")\n .slice(0, 10);\n}\n\n/**\n * Sanitise an org id to the character set allowed in merged keys.\n * Org ids are already nanoid-style alphanumeric, but we normalise defensively.\n */\nfunction sanitiseOrgId(orgId: string): string {\n return orgId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n}\n\n/**\n * Hostname patterns that are always rejected to prevent SSRF via DNS rebinding\n * or well-known internal service names.\n */\nconst BLOCKED_HOSTNAME_PATTERNS: RegExp[] = [\n /^localhost$/i,\n /\\.localhost$/i,\n /\\.local$/i,\n /\\.internal$/i,\n // DNS rebind services\n /\\.nip\\.io$/i,\n /\\.sslip\\.io$/i,\n /\\.xip\\.io$/i,\n /\\.localtest\\.me$/i,\n /\\.lvh\\.me$/i,\n // Cloud metadata hosts\n /^metadata\\.google\\.internal$/i,\n /^instance-data$/i,\n];\n\n/** Literal IPs that are always rejected (cloud metadata endpoints). */\nconst BLOCKED_IPS = new Set([\n \"169.254.169.254\", // AWS/GCP/Azure IMDS\n \"100.100.100.200\", // Alibaba Cloud metadata\n \"::1\",\n]);\n\n/** Parse a dotted-decimal IPv4 string to a 32-bit integer for range checks. */\nfunction ipv4ToInt(ip: string): number | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n let n = 0;\n for (const part of parts) {\n const byte = parseInt(part, 10);\n if (isNaN(byte) || byte < 0 || byte > 255) return null;\n n = (n << 8) | byte;\n }\n return n >>> 0;\n}\n\nfunction isPrivateIpv4(hostname: string): boolean {\n const n = ipv4ToInt(hostname);\n if (n === null) return false;\n // 10.0.0.0/8\n if ((n & 0xff000000) >>> 0 === 0x0a000000) return true;\n // 172.16.0.0/12\n if ((n & 0xfff00000) >>> 0 === 0xac100000) return true;\n // 192.168.0.0/16\n if ((n & 0xffff0000) >>> 0 === 0xc0a80000) return true;\n // 169.254.0.0/16 (link-local, includes AWS/GCP metadata)\n if ((n & 0xffff0000) >>> 0 === 0xa9fe0000) return true;\n // 127.0.0.0/8 (loopback)\n if ((n & 0xff000000) >>> 0 === 0x7f000000) return true;\n return false;\n}\n\nfunction isBlockedHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (BLOCKED_IPS.has(normalized)) return true;\n if (isPrivateIpv4(normalized)) return true;\n // IPv6 ULA (fc00::/7) and link-local (fe80::/10)\n if (normalized === \"::1\") return true;\n if (normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\")) return true;\n if (normalized.startsWith(\"fe80\")) return true;\n if (normalized.startsWith(\"::ffff:\")) {\n const mapped = normalized.slice(\"::ffff:\".length);\n if (isPrivateIpv4(mapped)) return true;\n const hexMatch = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(mapped);\n if (hexMatch) {\n const value =\n (parseInt(hexMatch[1], 16) << 16) | parseInt(hexMatch[2], 16);\n const dotted = [\n (value >>> 24) & 0xff,\n (value >>> 16) & 0xff,\n (value >>> 8) & 0xff,\n value & 0xff,\n ].join(\".\");\n if (isPrivateIpv4(dotted)) return true;\n }\n }\n for (const pattern of BLOCKED_HOSTNAME_PATTERNS) {\n if (pattern.test(normalized)) return true;\n }\n return false;\n}\n\n/** Reject obviously-wrong URLs. Allows http only for localhost. */\nexport function validateRemoteUrl(raw: string): {\n ok: boolean;\n url?: URL;\n error?: string;\n} {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return { ok: false, error: \"Not a valid URL\" };\n }\n if (url.protocol === \"https:\") {\n if (isBlockedHostname(url.hostname)) {\n return {\n ok: false,\n error: `Host \"${url.hostname}\" is not allowed (private/internal address)`,\n };\n }\n return { ok: true, url };\n }\n if (url.protocol === \"http:\") {\n const host = url.hostname;\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return { ok: true, url };\n }\n return { ok: false, error: \"Plain http is only allowed for localhost\" };\n }\n return { ok: false, error: `Unsupported protocol: ${url.protocol}` };\n}\n\nasync function readList(\n scope: RemoteMcpScope,\n scopeId: string,\n): Promise<StoredRemoteMcpServer[]> {\n const raw =\n scope === \"user\"\n ? await getUserSetting(scopeId, SETTINGS_KEY)\n : await getOrgSetting(scopeId, SETTINGS_KEY);\n if (!raw || !Array.isArray((raw as any).servers)) return [];\n return ((raw as any).servers as StoredRemoteMcpServer[]).filter(\n (s) => s && typeof s.id === \"string\" && typeof s.url === \"string\",\n );\n}\n\nasync function writeList(\n scope: RemoteMcpScope,\n scopeId: string,\n servers: StoredRemoteMcpServer[],\n): Promise<void> {\n if (scope === \"user\") {\n await putUserSetting(scopeId, SETTINGS_KEY, { servers });\n } else {\n await putOrgSetting(scopeId, SETTINGS_KEY, { servers });\n }\n}\n\nexport async function listRemoteServers(\n scope: RemoteMcpScope,\n scopeId: string,\n): Promise<StoredRemoteMcpServer[]> {\n return readList(scope, scopeId);\n}\n\nexport async function addRemoteServer(\n scope: RemoteMcpScope,\n scopeId: string,\n input: {\n name: string;\n url: string;\n headers?: Record<string, string>;\n description?: string;\n firstParty?: boolean;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n if (input.firstParty) {\n return {\n ok: false,\n error:\n \"First-party MCP servers must be registered through the trusted first-party registration path\",\n };\n }\n return addRemoteServerInternal(scope, scopeId, input);\n}\n\nexport async function addFirstPartyRemoteServer(\n orgId: string,\n input: {\n appId: string;\n name: string;\n url: string;\n description?: string;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n const trust = await isFirstPartyRemoteEndpointTrusted(\n orgId,\n input.appId,\n input.url,\n );\n if (!trust.ok) return { ok: false, error: trust.error };\n return addRemoteServerInternal(\"org\", orgId, {\n name: input.name,\n url: input.url,\n description: input.description,\n firstParty: true,\n firstPartyAppId: input.appId.trim().toLowerCase(),\n });\n}\n\nasync function addRemoteServerInternal(\n scope: RemoteMcpScope,\n scopeId: string,\n input: {\n name: string;\n url: string;\n headers?: Record<string, string>;\n description?: string;\n firstParty?: boolean;\n firstPartyAppId?: string;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n const name = normalizeServerName(input.name);\n if (!name) return { ok: false, error: \"Name is required\" };\n if (input.firstParty && scope !== \"org\") {\n return { ok: false, error: \"First-party MCP servers must be org-scoped\" };\n }\n const urlCheck = validateRemoteUrl(input.url);\n if (!urlCheck.ok) return { ok: false, error: urlCheck.error ?? \"Bad URL\" };\n\n const existing = await readList(scope, scopeId);\n if (existing.some((s) => s.name === name)) {\n return { ok: false, error: `A server named \"${name}\" already exists` };\n }\n\n const id = `mcps_${shortId()}`;\n const { cleartext, secret } = partitionHeaders(input.headers);\n\n // Persist secret-class headers in the encrypted secrets table; the\n // settings row only references the secret key, never the cleartext.\n let headerSecretKey: string | undefined;\n if (secret) {\n headerSecretKey = `mcp_headers:${id}`;\n try {\n await writeAppSecret({\n key: headerSecretKey,\n value: JSON.stringify(secret),\n scope: toSecretScope(scope),\n scopeId,\n description: `Encrypted MCP headers for ${name}`,\n });\n } catch (err: any) {\n return {\n ok: false,\n error: `Failed to encrypt MCP headers: ${err?.message ?? err}`,\n };\n }\n }\n\n const server: StoredRemoteMcpServer = {\n id,\n name,\n url: urlCheck.url!.toString(),\n headers: cleartext,\n headerSecretKey,\n ...(input.firstParty ? { firstParty: true } : {}),\n ...(input.firstPartyAppId\n ? { firstPartyAppId: input.firstPartyAppId }\n : {}),\n description: input.description?.trim() || undefined,\n createdAt: Date.now(),\n };\n await writeList(scope, scopeId, [...existing, server]);\n return { ok: true, server };\n}\n\nfunction normalizeEndpointPath(pathname: string): string {\n return pathname.replace(/\\/+$/, \"\") || \"/\";\n}\n\nfunction expectedFirstPartyMcpUrls(appUrl: string): URL[] {\n try {\n const base = appUrl.replace(/\\/+$/, \"\");\n return [new URL(`${base}/mcp`), new URL(`${base}/_agent-native/mcp`)];\n } catch {\n return [];\n }\n}\n\nfunction sameFirstPartyMcpEndpoint(endpointUrl: URL, appUrl: string): boolean {\n return expectedFirstPartyMcpUrls(appUrl).some(\n (expected) =>\n endpointUrl.origin === expected.origin &&\n normalizeEndpointPath(endpointUrl.pathname) ===\n normalizeEndpointPath(expected.pathname) &&\n endpointUrl.search === expected.search,\n );\n}\n\nexport async function isFirstPartyRemoteEndpointTrusted(\n orgId: string,\n appId: string,\n endpoint: string,\n): Promise<{ ok: true } | { ok: false; error: string }> {\n const normalizedAppId = appId.trim().toLowerCase();\n if (!orgId.trim()) {\n return { ok: false, error: \"Organization id is required\" };\n }\n if (!normalizedAppId) {\n return { ok: false, error: \"First-party app id is required\" };\n }\n\n let endpointUrl: URL;\n try {\n endpointUrl = new URL(endpoint);\n } catch {\n return { ok: false, error: \"Not a valid URL\" };\n }\n\n try {\n const { getRequestOrgId } = await import(\"../server/request-context.js\");\n const requestOrgId = getRequestOrgId();\n if (requestOrgId && requestOrgId !== orgId) {\n return {\n ok: false,\n error:\n \"First-party MCP server org does not match the active request organization\",\n };\n }\n } catch {\n // No request context helper available: the org-directory lookup below will\n // still fail closed if it cannot authenticate a first-party app list.\n }\n\n const { fetchOrgApps } = await import(\"../mcp/org-directory.js\");\n const apps = await fetchOrgApps({ serviceOrgId: orgId });\n const app = apps.find((candidate) => candidate.id === normalizedAppId);\n if (!app) {\n return {\n ok: false,\n error: \"Could not verify the first-party app in the org directory\",\n };\n }\n if (!sameFirstPartyMcpEndpoint(endpointUrl, app.url)) {\n return {\n ok: false,\n error:\n \"First-party MCP URL does not match the org-directory app endpoint\",\n };\n }\n return { ok: true };\n}\n\nexport async function removeRemoteServer(\n scope: RemoteMcpScope,\n scopeId: string,\n id: string,\n): Promise<boolean> {\n const existing = await readList(scope, scopeId);\n const removed = existing.find((s) => s.id === id);\n const next = existing.filter((s) => s.id !== id);\n if (next.length === existing.length) return false;\n if (next.length === 0) {\n if (scope === \"user\") {\n await deleteUserSetting(scopeId, SETTINGS_KEY);\n } else {\n await deleteOrgSetting(scopeId, SETTINGS_KEY);\n }\n } else {\n await writeList(scope, scopeId, next);\n }\n // Best-effort: drop the encrypted-headers secret too. Errors are logged\n // but don't fail the deletion — the settings row is already gone, so a\n // dangling secret is harmless (it just can't be read back).\n if (removed?.headerSecretKey) {\n try {\n await deleteAppSecret({\n key: removed.headerSecretKey,\n scope: toSecretScope(scope),\n scopeId,\n });\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.warn(\n `[mcp-client] Failed to delete MCP header secret ${removed.headerSecretKey}: ${err?.message ?? err}`,\n );\n }\n }\n return true;\n}\n\n/**\n * Resolve the full headers map (cleartext + decrypted secret headers) for a\n * stored MCP server. Used when projecting the stored record into the\n * runtime `McpHttpServerConfig` shape that `McpClientManager` consumes.\n *\n * For legacy rows that wrote secrets cleartext into `headers`, this\n * returns those cleartext values unchanged — they should be re-saved\n * through `addRemoteServer` to migrate to encrypted storage.\n */\nexport async function materializeHeaders(\n scope: RemoteMcpScope,\n scopeId: string,\n stored: StoredRemoteMcpServer,\n): Promise<Record<string, string> | undefined> {\n const merged: Record<string, string> = { ...(stored.headers ?? {}) };\n if (stored.headerSecretKey) {\n try {\n const secret = await readAppSecret({\n key: stored.headerSecretKey,\n scope: toSecretScope(scope),\n scopeId,\n });\n if (secret) {\n const parsed = JSON.parse(secret.value) as Record<string, string>;\n for (const [k, v] of Object.entries(parsed)) {\n if (typeof v === \"string\") merged[k] = v;\n }\n }\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.warn(\n `[mcp-client] Failed to decrypt MCP headers for ${stored.name}: ${err?.message ?? err}`,\n );\n }\n }\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Project a stored server into the runtime `McpHttpServerConfig` shape that\n * `McpClientManager` consumes. The merged-config key is the scope + name\n * so a user-scope and org-scope server can both share a readable name\n * without clobbering each other.\n *\n * SECURITY: when the stored row references encrypted headers\n * (`headerSecretKey`), callers should use `toHttpServerConfigAsync`\n * instead — this synchronous variant returns ONLY the cleartext headers\n * already present on the row. Returning the row's literal headers without\n * the secret material means the runtime client would call the MCP server\n * without auth (request will fail), but never leaks the encrypted secret.\n */\nexport function toHttpServerConfig(\n stored: StoredRemoteMcpServer,\n): McpHttpServerConfig {\n return {\n type: \"http\",\n url: stored.url,\n headers: stored.headers,\n ...(stored.firstParty ? { firstParty: true } : {}),\n ...(stored.firstPartyAppId\n ? { firstPartyAppId: stored.firstPartyAppId }\n : {}),\n description: stored.description,\n };\n}\n\n/**\n * Async variant of `toHttpServerConfig` that resolves any encrypted\n * `headerSecretKey` reference from `app_secrets` and returns the full\n * cleartext headers map for use at runtime. Use this when actually\n * configuring an MCP client; use the sync variant only when serializing\n * stored data (e.g. for read-only listings that shouldn't disclose\n * secrets).\n */\nexport async function toHttpServerConfigAsync(\n scope: RemoteMcpScope,\n scopeId: string,\n stored: StoredRemoteMcpServer,\n): Promise<McpHttpServerConfig> {\n return {\n type: \"http\",\n url: stored.url,\n headers: await materializeHeaders(scope, scopeId, stored),\n ...(stored.firstParty ? { firstParty: true } : {}),\n ...(stored.firstPartyAppId\n ? { firstPartyAppId: stored.firstPartyAppId }\n : {}),\n ...(stored.firstParty && scope === \"org\"\n ? { firstPartyOrgId: scopeId }\n : {}),\n description: stored.description,\n };\n}\n\n/**\n * Build the merged-config key for a stored server.\n *\n * The key encodes the owning scope + owner identity so two users adding a\n * server called `zapier` produce distinct ids (`user_ab12cd34ef_zapier` vs\n * `user_99aa88bb77_zapier`) and Alice's tool calls never route through Bob's\n * credentials in a shared-process deployment.\n *\n * - User scope: `user_<emailhash>_<name>`\n * - Org scope: `org_<orgId>_<name>`\n *\n * `ownerId` is the raw email for user scope, and the org id for org scope.\n */\nexport function mergedConfigKey(\n scope: RemoteMcpScope,\n stored: StoredRemoteMcpServer,\n ownerId: string,\n): string {\n const owner = scope === \"user\" ? hashEmail(ownerId) : sanitiseOrgId(ownerId);\n return `${scope}_${owner}_${stored.name}`;\n}\n\n/**\n * Parse a merged key (or a full prefixed tool name like\n * `mcp__user_abcd1234ef_zapier__run-task`) back into its scope + owner + name\n * components. Returns null for non-merged keys (e.g. stdio file-config servers\n * like `claude-in-chrome`) so callers can treat them as always-visible.\n *\n * `hub_<orgId>_<name>` entries (pulled from a remote hub via\n * `hub-client.ts`) project to `scope: \"org\"` so they pass through the same\n * per-request visibility gate as locally-stored org servers — the tool is\n * only visible to requests whose active org matches the hub entry's org.\n */\nexport function parseMergedKey(\n keyOrToolName: string,\n): { scope: RemoteMcpScope; owner: string; name: string } | null {\n let key = keyOrToolName;\n if (key.startsWith(\"mcp__\")) {\n const rest = key.slice(\"mcp__\".length);\n const idx = rest.indexOf(\"__\");\n key = idx >= 0 ? rest.slice(0, idx) : rest;\n }\n const m = /^(user|org|hub)_([^_]+)_(.+)$/.exec(key);\n if (!m) return null;\n const prefix = m[1];\n // Hub-sourced servers are scoped to the org they came from — treat them\n // as org-scope for visibility purposes (see isMcpToolAllowedForRequest).\n const scope: RemoteMcpScope = prefix === \"user\" ? \"user\" : \"org\";\n return {\n scope,\n owner: m[2],\n name: m[3],\n };\n}\n"]}
1
+ {"version":3,"file":"remote-store.js","sourceRoot":"","sources":["../../src/mcp-client/remote-store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Persistent store for user-added remote MCP servers.\n *\n * Servers added through the settings UI live in the framework's `settings`\n * table, keyed by scope:\n * - User scope: `u:<email>:mcp-servers-remote`\n * - Org scope: `o:<orgId>:mcp-servers-remote`\n *\n * Both scopes store the same shape — a list of `StoredRemoteMcpServer`\n * records. The running MCP manager merges this list with the file-based\n * `mcp.config.json` on startup and after every mutation.\n *\n * SECURITY: HTTP MCP servers commonly require a bearer token in the\n * `Authorization` header. Those values are written to the encrypted\n * `app_secrets` table (AES-256-GCM via writeAppSecret). The settings row\n * stores only the secret-key reference (`headerSecretKey`), not the raw\n * value. Callers retrieving headers must call `materializeHeaders` to\n * fetch the cleartext at request time. Legacy rows that wrote headers\n * cleartext into `headers` continue to work read-only — they should be\n * re-saved to migrate.\n */\n\nimport { createHash } from \"node:crypto\";\n\nimport type { SecretScope } from \"../secrets/register.js\";\nimport {\n writeAppSecret,\n readAppSecret,\n deleteAppSecret,\n} from \"../secrets/storage.js\";\nimport {\n getOrgSetting,\n putOrgSetting,\n deleteOrgSetting,\n} from \"../settings/org-settings.js\";\nimport {\n getUserSetting,\n putUserSetting,\n deleteUserSetting,\n} from \"../settings/user-settings.js\";\nimport type { McpHttpServerConfig } from \"./config.js\";\nimport {\n deleteMcpOAuthCredentials,\n getMcpOAuthAccessToken,\n saveMcpOAuthCredentials,\n type McpOAuthCredentialBundle,\n} from \"./oauth-client.js\";\nimport { validateRemoteUrl } from \"./remote-url.js\";\n\nexport { validateRemoteUrl } from \"./remote-url.js\";\n\nconst SETTINGS_KEY = \"mcp-servers-remote\";\n\nexport type RemoteMcpScope = \"user\" | \"org\";\n\nfunction toSecretScope(scope: RemoteMcpScope): SecretScope {\n return scope === \"user\" ? \"user\" : \"workspace\";\n}\n\nexport interface StoredRemoteMcpServer {\n /** Stable unique id — used for removal / URLs. */\n id: string;\n /** Human-readable name. Also used as the MCP server id (prefixed with scope). */\n name: string;\n /** Streamable HTTP MCP server URL. */\n url: string;\n /**\n * Optional non-secret headers to pass to the MCP server. SECURITY: secret\n * material (Authorization, X-Api-Key, …) is moved out of this field at\n * write time and stored encrypted in `app_secrets`; see\n * `headerSecretKey`. Legacy rows may still contain cleartext headers and\n * are honored read-only.\n */\n headers?: Record<string, string>;\n /**\n * Reference to the encrypted secret holding the JSON-stringified secret\n * headers map (e.g. `{\"Authorization\":\"Bearer …\"}`). Resolved at request\n * time via `readAppSecret`. Undefined when no secret-class headers were\n * supplied (or for legacy cleartext rows).\n */\n headerSecretKey?: string;\n /** Reference to the encrypted OAuth credential bundle for this server. */\n oauthSecretKey?: string;\n /**\n * Trusted first-party Agent-Native app. Only framework-controlled\n * registrations should set this; management routes intentionally do not\n * expose it for arbitrary user-added MCP servers.\n */\n firstParty?: boolean;\n /** Canonical first-party app id from the org directory, e.g. `assets`. */\n firstPartyAppId?: string;\n /** Optional description shown in the UI. */\n description?: string;\n /** ms since epoch. */\n createdAt: number;\n}\n\n/**\n * Header names that are routed through the encrypted-at-rest secrets store\n * instead of being written to the plaintext `settings` row. Match is\n * case-insensitive and substring-based to catch one-off names like\n * `x-zapier-api-key`.\n */\nconst SECRET_HEADER_NAME_PATTERNS = [\n /authorization/i,\n /api[-_]?key/i,\n /token/i,\n /secret/i,\n /bearer/i,\n /x-.*-key/i,\n];\n\nfunction isSecretHeaderName(name: string): boolean {\n return SECRET_HEADER_NAME_PATTERNS.some((re) => re.test(name));\n}\n\n/** Split a headers map into (cleartext, secret) buckets. */\nfunction partitionHeaders(headers: Record<string, string> | undefined): {\n cleartext: Record<string, string> | undefined;\n secret: Record<string, string> | undefined;\n} {\n if (!headers) return { cleartext: undefined, secret: undefined };\n const cleartext: Record<string, string> = {};\n const secret: Record<string, string> = {};\n for (const [k, v] of Object.entries(headers)) {\n if (typeof v !== \"string\") continue;\n if (isSecretHeaderName(k)) secret[k] = v;\n else cleartext[k] = v;\n }\n return {\n cleartext: Object.keys(cleartext).length > 0 ? cleartext : undefined,\n secret: Object.keys(secret).length > 0 ? secret : undefined,\n };\n}\n\n/** Tiny nanoid — matches the inline helper used elsewhere in this package. */\nfunction shortId(): string {\n const rand =\n globalThis.crypto?.randomUUID?.().replace(/-/g, \"\") ??\n Math.random().toString(36).slice(2) + Date.now().toString(36);\n return rand.slice(0, 16);\n}\n\n/**\n * Validate a candidate MCP server name — used as a key in the merged config\n * and as part of the prefixed tool name (`mcp__<merged-key>__<tool>`).\n *\n * Allowed: letters, digits, hyphen; 1–40 chars. Lowercased. Underscores are\n * excluded on purpose — the merged-key format uses `_` as a separator between\n * `<scope>`, `<owner>`, and `<name>`, so allowing `_` in names would make the\n * parse ambiguous.\n */\nexport function normalizeServerName(input: string): string {\n return input\n .trim()\n .toLowerCase()\n .replace(/[^a-z0-9-]/g, \"-\")\n .slice(0, 40);\n}\n\n/**\n * Short, deterministic, URL-safe hash of an email. Used as the owner\n * discriminator in user-scope merged keys so two users with the same server\n * name don't collide in the global MCP manager.\n */\nexport function hashEmail(email: string): string {\n return createHash(\"sha256\")\n .update(email.toLowerCase().trim())\n .digest(\"hex\")\n .slice(0, 10);\n}\n\n/**\n * Sanitise an org id to the character set allowed in merged keys.\n * Org ids are already nanoid-style alphanumeric, but we normalise defensively.\n */\nfunction sanitiseOrgId(orgId: string): string {\n return orgId.toLowerCase().replace(/[^a-z0-9-]/g, \"-\");\n}\n\nasync function readList(\n scope: RemoteMcpScope,\n scopeId: string,\n): Promise<StoredRemoteMcpServer[]> {\n const raw =\n scope === \"user\"\n ? await getUserSetting(scopeId, SETTINGS_KEY)\n : await getOrgSetting(scopeId, SETTINGS_KEY);\n if (!raw || !Array.isArray((raw as any).servers)) return [];\n return ((raw as any).servers as StoredRemoteMcpServer[]).filter(\n (s) => s && typeof s.id === \"string\" && typeof s.url === \"string\",\n );\n}\n\nasync function writeList(\n scope: RemoteMcpScope,\n scopeId: string,\n servers: StoredRemoteMcpServer[],\n): Promise<void> {\n if (scope === \"user\") {\n await putUserSetting(scopeId, SETTINGS_KEY, { servers });\n } else {\n await putOrgSetting(scopeId, SETTINGS_KEY, { servers });\n }\n}\n\nexport async function listRemoteServers(\n scope: RemoteMcpScope,\n scopeId: string,\n): Promise<StoredRemoteMcpServer[]> {\n return readList(scope, scopeId);\n}\n\nexport async function addRemoteServer(\n scope: RemoteMcpScope,\n scopeId: string,\n input: {\n name: string;\n url: string;\n headers?: Record<string, string>;\n description?: string;\n firstParty?: boolean;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n if (input.firstParty) {\n return {\n ok: false,\n error:\n \"First-party MCP servers must be registered through the trusted first-party registration path\",\n };\n }\n return addRemoteServerInternal(scope, scopeId, input);\n}\n\n/**\n * Persist a remote MCP server whose authorization is managed by the MCP\n * server's OAuth 2.1 metadata and token endpoints. OAuth credentials are\n * stored separately from the settings row and never returned to clients.\n */\nexport async function addOAuthRemoteServer(\n scope: RemoteMcpScope,\n scopeId: string,\n input: {\n name: string;\n url: string;\n description?: string;\n credentials: McpOAuthCredentialBundle;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n const oauthSecretKey = `mcp_oauth:${shortId()}`;\n try {\n await saveMcpOAuthCredentials({\n key: oauthSecretKey,\n scope,\n scopeId,\n credentials: input.credentials,\n });\n const result = await addRemoteServerInternal(scope, scopeId, {\n name: input.name,\n url: input.url,\n description: input.description,\n oauthSecretKey,\n });\n if (!result.ok) {\n await deleteMcpOAuthCredentials({\n key: oauthSecretKey,\n scope,\n scopeId,\n });\n }\n return result;\n } catch (err: any) {\n await deleteMcpOAuthCredentials({\n key: oauthSecretKey,\n scope,\n scopeId,\n }).catch(() => {});\n return {\n ok: false,\n error: `Failed to save MCP OAuth credentials: ${err?.message ?? err}`,\n };\n }\n}\n\nexport async function addFirstPartyRemoteServer(\n orgId: string,\n input: {\n appId: string;\n name: string;\n url: string;\n description?: string;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n const trust = await isFirstPartyRemoteEndpointTrusted(\n orgId,\n input.appId,\n input.url,\n );\n if (!trust.ok) return { ok: false, error: trust.error };\n return addRemoteServerInternal(\"org\", orgId, {\n name: input.name,\n url: input.url,\n description: input.description,\n firstParty: true,\n firstPartyAppId: input.appId.trim().toLowerCase(),\n });\n}\n\nasync function addRemoteServerInternal(\n scope: RemoteMcpScope,\n scopeId: string,\n input: {\n name: string;\n url: string;\n headers?: Record<string, string>;\n description?: string;\n firstParty?: boolean;\n firstPartyAppId?: string;\n oauthSecretKey?: string;\n },\n): Promise<\n { ok: true; server: StoredRemoteMcpServer } | { ok: false; error: string }\n> {\n const name = normalizeServerName(input.name);\n if (!name) return { ok: false, error: \"Name is required\" };\n if (input.firstParty && scope !== \"org\") {\n return { ok: false, error: \"First-party MCP servers must be org-scoped\" };\n }\n const urlCheck = validateRemoteUrl(input.url);\n if (!urlCheck.ok) return { ok: false, error: urlCheck.error ?? \"Bad URL\" };\n\n const existing = await readList(scope, scopeId);\n if (existing.some((s) => s.name === name)) {\n return { ok: false, error: `A server named \"${name}\" already exists` };\n }\n\n const id = `mcps_${shortId()}`;\n const { cleartext, secret } = partitionHeaders(input.headers);\n\n // Persist secret-class headers in the encrypted secrets table; the\n // settings row only references the secret key, never the cleartext.\n let headerSecretKey: string | undefined;\n if (secret) {\n headerSecretKey = `mcp_headers:${id}`;\n try {\n await writeAppSecret({\n key: headerSecretKey,\n value: JSON.stringify(secret),\n scope: toSecretScope(scope),\n scopeId,\n description: `Encrypted MCP headers for ${name}`,\n });\n } catch (err: any) {\n return {\n ok: false,\n error: `Failed to encrypt MCP headers: ${err?.message ?? err}`,\n };\n }\n }\n\n const server: StoredRemoteMcpServer = {\n id,\n name,\n url: urlCheck.url!.toString(),\n headers: cleartext,\n headerSecretKey,\n ...(input.firstParty ? { firstParty: true } : {}),\n ...(input.firstPartyAppId\n ? { firstPartyAppId: input.firstPartyAppId }\n : {}),\n ...(input.oauthSecretKey ? { oauthSecretKey: input.oauthSecretKey } : {}),\n description: input.description?.trim() || undefined,\n createdAt: Date.now(),\n };\n await writeList(scope, scopeId, [...existing, server]);\n return { ok: true, server };\n}\n\nfunction normalizeEndpointPath(pathname: string): string {\n return pathname.replace(/\\/+$/, \"\") || \"/\";\n}\n\nfunction expectedFirstPartyMcpUrls(appUrl: string): URL[] {\n try {\n const base = appUrl.replace(/\\/+$/, \"\");\n return [new URL(`${base}/mcp`), new URL(`${base}/_agent-native/mcp`)];\n } catch {\n return [];\n }\n}\n\nfunction sameFirstPartyMcpEndpoint(endpointUrl: URL, appUrl: string): boolean {\n return expectedFirstPartyMcpUrls(appUrl).some(\n (expected) =>\n endpointUrl.origin === expected.origin &&\n normalizeEndpointPath(endpointUrl.pathname) ===\n normalizeEndpointPath(expected.pathname) &&\n endpointUrl.search === expected.search,\n );\n}\n\nexport async function isFirstPartyRemoteEndpointTrusted(\n orgId: string,\n appId: string,\n endpoint: string,\n): Promise<{ ok: true } | { ok: false; error: string }> {\n const normalizedAppId = appId.trim().toLowerCase();\n if (!orgId.trim()) {\n return { ok: false, error: \"Organization id is required\" };\n }\n if (!normalizedAppId) {\n return { ok: false, error: \"First-party app id is required\" };\n }\n\n let endpointUrl: URL;\n try {\n endpointUrl = new URL(endpoint);\n } catch {\n return { ok: false, error: \"Not a valid URL\" };\n }\n\n try {\n const { getRequestOrgId } = await import(\"../server/request-context.js\");\n const requestOrgId = getRequestOrgId();\n if (requestOrgId && requestOrgId !== orgId) {\n return {\n ok: false,\n error:\n \"First-party MCP server org does not match the active request organization\",\n };\n }\n } catch {\n // No request context helper available: the org-directory lookup below will\n // still fail closed if it cannot authenticate a first-party app list.\n }\n\n const { fetchOrgApps } = await import(\"../mcp/org-directory.js\");\n const apps = await fetchOrgApps({ serviceOrgId: orgId });\n const app = apps.find((candidate) => candidate.id === normalizedAppId);\n if (!app) {\n return {\n ok: false,\n error: \"Could not verify the first-party app in the org directory\",\n };\n }\n if (!sameFirstPartyMcpEndpoint(endpointUrl, app.url)) {\n return {\n ok: false,\n error:\n \"First-party MCP URL does not match the org-directory app endpoint\",\n };\n }\n return { ok: true };\n}\n\nexport async function removeRemoteServer(\n scope: RemoteMcpScope,\n scopeId: string,\n id: string,\n): Promise<boolean> {\n const existing = await readList(scope, scopeId);\n const removed = existing.find((s) => s.id === id);\n const next = existing.filter((s) => s.id !== id);\n if (next.length === existing.length) return false;\n if (next.length === 0) {\n if (scope === \"user\") {\n await deleteUserSetting(scopeId, SETTINGS_KEY);\n } else {\n await deleteOrgSetting(scopeId, SETTINGS_KEY);\n }\n } else {\n await writeList(scope, scopeId, next);\n }\n // Best-effort: drop the encrypted-headers secret too. Errors are logged\n // but don't fail the deletion — the settings row is already gone, so a\n // dangling secret is harmless (it just can't be read back).\n if (removed?.headerSecretKey) {\n try {\n await deleteAppSecret({\n key: removed.headerSecretKey,\n scope: toSecretScope(scope),\n scopeId,\n });\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.warn(\n `[mcp-client] Failed to delete MCP header secret ${removed.headerSecretKey}: ${err?.message ?? err}`,\n );\n }\n }\n if (removed?.oauthSecretKey) {\n try {\n await deleteMcpOAuthCredentials({\n key: removed.oauthSecretKey,\n scope,\n scopeId,\n });\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.warn(\n `[mcp-client] Failed to delete MCP OAuth credentials ${removed.oauthSecretKey}: ${err?.message ?? err}`,\n );\n }\n }\n return true;\n}\n\n/**\n * Resolve the full headers map (cleartext + decrypted secret headers) for a\n * stored MCP server. Used when projecting the stored record into the\n * runtime `McpHttpServerConfig` shape that `McpClientManager` consumes.\n *\n * For legacy rows that wrote secrets cleartext into `headers`, this\n * returns those cleartext values unchanged — they should be re-saved\n * through `addRemoteServer` to migrate to encrypted storage.\n */\nexport async function materializeHeaders(\n scope: RemoteMcpScope,\n scopeId: string,\n stored: StoredRemoteMcpServer,\n): Promise<Record<string, string> | undefined> {\n const merged: Record<string, string> = { ...(stored.headers ?? {}) };\n if (stored.headerSecretKey) {\n try {\n const secret = await readAppSecret({\n key: stored.headerSecretKey,\n scope: toSecretScope(scope),\n scopeId,\n });\n if (secret) {\n const parsed = JSON.parse(secret.value) as Record<string, string>;\n for (const [k, v] of Object.entries(parsed)) {\n if (typeof v === \"string\") merged[k] = v;\n }\n }\n } catch (err: any) {\n // eslint-disable-next-line no-console\n console.warn(\n `[mcp-client] Failed to decrypt MCP headers for ${stored.name}: ${err?.message ?? err}`,\n );\n }\n }\n return Object.keys(merged).length > 0 ? merged : undefined;\n}\n\n/**\n * Project a stored server into the runtime `McpHttpServerConfig` shape that\n * `McpClientManager` consumes. The merged-config key is the scope + name\n * so a user-scope and org-scope server can both share a readable name\n * without clobbering each other.\n *\n * SECURITY: when the stored row references encrypted headers\n * (`headerSecretKey`), callers should use `toHttpServerConfigAsync`\n * instead — this synchronous variant returns ONLY the cleartext headers\n * already present on the row. Returning the row's literal headers without\n * the secret material means the runtime client would call the MCP server\n * without auth (request will fail), but never leaks the encrypted secret.\n */\nexport function toHttpServerConfig(\n stored: StoredRemoteMcpServer,\n): McpHttpServerConfig {\n return {\n type: \"http\",\n url: stored.url,\n headers: stored.headers,\n ...(stored.firstParty ? { firstParty: true } : {}),\n ...(stored.firstPartyAppId\n ? { firstPartyAppId: stored.firstPartyAppId }\n : {}),\n description: stored.description,\n };\n}\n\n/**\n * Async variant of `toHttpServerConfig` that resolves any encrypted\n * `headerSecretKey` reference from `app_secrets` and returns the full\n * cleartext headers map for use at runtime. Use this when actually\n * configuring an MCP client; use the sync variant only when serializing\n * stored data (e.g. for read-only listings that shouldn't disclose\n * secrets).\n */\nexport async function toHttpServerConfigAsync(\n scope: RemoteMcpScope,\n scopeId: string,\n stored: StoredRemoteMcpServer,\n): Promise<McpHttpServerConfig> {\n let headers = await materializeHeaders(scope, scopeId, stored);\n if (stored.oauthSecretKey) {\n const accessToken = await getMcpOAuthAccessToken({\n key: stored.oauthSecretKey,\n scope,\n scopeId,\n serverUrl: stored.url,\n });\n if (accessToken) {\n headers ??= {};\n headers.Authorization = `Bearer ${accessToken}`;\n }\n }\n return {\n type: \"http\",\n url: stored.url,\n headers,\n ...(stored.firstParty ? { firstParty: true } : {}),\n ...(stored.firstPartyAppId\n ? { firstPartyAppId: stored.firstPartyAppId }\n : {}),\n ...(stored.firstParty && scope === \"org\"\n ? { firstPartyOrgId: scopeId }\n : {}),\n description: stored.description,\n };\n}\n\n/**\n * Build the merged-config key for a stored server.\n *\n * The key encodes the owning scope + owner identity so two users adding a\n * server called `zapier` produce distinct ids (`user_ab12cd34ef_zapier` vs\n * `user_99aa88bb77_zapier`) and Alice's tool calls never route through Bob's\n * credentials in a shared-process deployment.\n *\n * - User scope: `user_<emailhash>_<name>`\n * - Org scope: `org_<orgId>_<name>`\n *\n * `ownerId` is the raw email for user scope, and the org id for org scope.\n */\nexport function mergedConfigKey(\n scope: RemoteMcpScope,\n stored: StoredRemoteMcpServer,\n ownerId: string,\n): string {\n const owner = scope === \"user\" ? hashEmail(ownerId) : sanitiseOrgId(ownerId);\n return `${scope}_${owner}_${stored.name}`;\n}\n\n/**\n * Parse a merged key (or a full prefixed tool name like\n * `mcp__user_abcd1234ef_zapier__run-task`) back into its scope + owner + name\n * components. Returns null for non-merged keys (e.g. stdio file-config servers\n * like `claude-in-chrome`) so callers can treat them as always-visible.\n *\n * `hub_<orgId>_<name>` entries (pulled from a remote hub via\n * `hub-client.ts`) project to `scope: \"org\"` so they pass through the same\n * per-request visibility gate as locally-stored org servers — the tool is\n * only visible to requests whose active org matches the hub entry's org.\n */\nexport function parseMergedKey(\n keyOrToolName: string,\n): { scope: RemoteMcpScope; owner: string; name: string } | null {\n let key = keyOrToolName;\n if (key.startsWith(\"mcp__\")) {\n const rest = key.slice(\"mcp__\".length);\n const idx = rest.indexOf(\"__\");\n key = idx >= 0 ? rest.slice(0, idx) : rest;\n }\n const m = /^(user|org|hub)_([^_]+)_(.+)$/.exec(key);\n if (!m) return null;\n const prefix = m[1];\n // Hub-sourced servers are scoped to the org they came from — treat them\n // as org-scope for visibility purposes (see isMcpToolAllowedForRequest).\n const scope: RemoteMcpScope = prefix === \"user\" ? \"user\" : \"org\";\n return {\n scope,\n owner: m[2],\n name: m[3],\n };\n}\n"]}
@@ -0,0 +1,8 @@
1
+ /** URL validation shared by remote MCP storage and OAuth discovery. */
2
+ /** Reject public-resource URLs that could target an internal network. */
3
+ export declare function validateRemoteUrl(raw: string): {
4
+ ok: boolean;
5
+ url?: URL;
6
+ error?: string;
7
+ };
8
+ //# sourceMappingURL=remote-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-url.d.ts","sourceRoot":"","sources":["../../src/mcp-client/remote-url.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAmEvE,yEAAyE;AACzE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG;IAC9C,EAAE,EAAE,OAAO,CAAC;IACZ,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAwBA"}
@@ -0,0 +1,103 @@
1
+ /** URL validation shared by remote MCP storage and OAuth discovery. */
2
+ const BLOCKED_HOSTNAME_PATTERNS = [
3
+ /^localhost$/i,
4
+ /\.localhost$/i,
5
+ /\.local$/i,
6
+ /\.internal$/i,
7
+ /\.nip\.io$/i,
8
+ /\.sslip\.io$/i,
9
+ /\.xip\.io$/i,
10
+ /\.localtest\.me$/i,
11
+ /\.lvh\.me$/i,
12
+ /^metadata\.google\.internal$/i,
13
+ /^instance-data$/i,
14
+ ];
15
+ const BLOCKED_IPS = new Set(["169.254.169.254", "100.100.100.200", "::1"]);
16
+ function ipv4ToInt(ip) {
17
+ const parts = ip.split(".");
18
+ if (parts.length !== 4)
19
+ return null;
20
+ let n = 0;
21
+ for (const part of parts) {
22
+ const byte = parseInt(part, 10);
23
+ if (isNaN(byte) || byte < 0 || byte > 255)
24
+ return null;
25
+ n = (n << 8) | byte;
26
+ }
27
+ return n >>> 0;
28
+ }
29
+ function isPrivateIpv4(hostname) {
30
+ const n = ipv4ToInt(hostname);
31
+ if (n === null)
32
+ return false;
33
+ if ((n & 0xff000000) >>> 0 === 0x0a000000)
34
+ return true;
35
+ if ((n & 0xfff00000) >>> 0 === 0xac100000)
36
+ return true;
37
+ if ((n & 0xffff0000) >>> 0 === 0xc0a80000)
38
+ return true;
39
+ if ((n & 0xffff0000) >>> 0 === 0xa9fe0000)
40
+ return true;
41
+ if ((n & 0xff000000) >>> 0 === 0x7f000000)
42
+ return true;
43
+ return false;
44
+ }
45
+ function isBlockedHostname(hostname) {
46
+ const normalized = hostname.toLowerCase().replace(/^\[|\]$/g, "");
47
+ if (BLOCKED_IPS.has(normalized))
48
+ return true;
49
+ if (isPrivateIpv4(normalized))
50
+ return true;
51
+ if (normalized === "::1")
52
+ return true;
53
+ if (normalized.startsWith("fc") || normalized.startsWith("fd"))
54
+ return true;
55
+ if (normalized.startsWith("fe80"))
56
+ return true;
57
+ if (normalized.startsWith("::ffff:")) {
58
+ const mapped = normalized.slice("::ffff:".length);
59
+ if (isPrivateIpv4(mapped))
60
+ return true;
61
+ const hexMatch = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(mapped);
62
+ if (hexMatch) {
63
+ const value = (parseInt(hexMatch[1], 16) << 16) | parseInt(hexMatch[2], 16);
64
+ const dotted = [
65
+ (value >>> 24) & 0xff,
66
+ (value >>> 16) & 0xff,
67
+ (value >>> 8) & 0xff,
68
+ value & 0xff,
69
+ ].join(".");
70
+ if (isPrivateIpv4(dotted))
71
+ return true;
72
+ }
73
+ }
74
+ return BLOCKED_HOSTNAME_PATTERNS.some((pattern) => pattern.test(normalized));
75
+ }
76
+ /** Reject public-resource URLs that could target an internal network. */
77
+ export function validateRemoteUrl(raw) {
78
+ let url;
79
+ try {
80
+ url = new URL(raw);
81
+ }
82
+ catch {
83
+ return { ok: false, error: "Not a valid URL" };
84
+ }
85
+ if (url.protocol === "https:") {
86
+ if (isBlockedHostname(url.hostname)) {
87
+ return {
88
+ ok: false,
89
+ error: `Host "${url.hostname}" is not allowed (private/internal address)`,
90
+ };
91
+ }
92
+ return { ok: true, url };
93
+ }
94
+ if (url.protocol === "http:") {
95
+ const host = url.hostname;
96
+ if (host === "localhost" || host === "127.0.0.1") {
97
+ return { ok: true, url };
98
+ }
99
+ return { ok: false, error: "Plain http is only allowed for localhost" };
100
+ }
101
+ return { ok: false, error: `Unsupported protocol: ${url.protocol}` };
102
+ }
103
+ //# sourceMappingURL=remote-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"remote-url.js","sourceRoot":"","sources":["../../src/mcp-client/remote-url.ts"],"names":[],"mappings":"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","sourcesContent":["/** URL validation shared by remote MCP storage and OAuth discovery. */\n\nconst BLOCKED_HOSTNAME_PATTERNS: RegExp[] = [\n /^localhost$/i,\n /\\.localhost$/i,\n /\\.local$/i,\n /\\.internal$/i,\n /\\.nip\\.io$/i,\n /\\.sslip\\.io$/i,\n /\\.xip\\.io$/i,\n /\\.localtest\\.me$/i,\n /\\.lvh\\.me$/i,\n /^metadata\\.google\\.internal$/i,\n /^instance-data$/i,\n];\n\nconst BLOCKED_IPS = new Set([\"169.254.169.254\", \"100.100.100.200\", \"::1\"]);\n\nfunction ipv4ToInt(ip: string): number | null {\n const parts = ip.split(\".\");\n if (parts.length !== 4) return null;\n let n = 0;\n for (const part of parts) {\n const byte = parseInt(part, 10);\n if (isNaN(byte) || byte < 0 || byte > 255) return null;\n n = (n << 8) | byte;\n }\n return n >>> 0;\n}\n\nfunction isPrivateIpv4(hostname: string): boolean {\n const n = ipv4ToInt(hostname);\n if (n === null) return false;\n if ((n & 0xff000000) >>> 0 === 0x0a000000) return true;\n if ((n & 0xfff00000) >>> 0 === 0xac100000) return true;\n if ((n & 0xffff0000) >>> 0 === 0xc0a80000) return true;\n if ((n & 0xffff0000) >>> 0 === 0xa9fe0000) return true;\n if ((n & 0xff000000) >>> 0 === 0x7f000000) return true;\n return false;\n}\n\nfunction isBlockedHostname(hostname: string): boolean {\n const normalized = hostname.toLowerCase().replace(/^\\[|\\]$/g, \"\");\n if (BLOCKED_IPS.has(normalized)) return true;\n if (isPrivateIpv4(normalized)) return true;\n if (normalized === \"::1\") return true;\n if (normalized.startsWith(\"fc\") || normalized.startsWith(\"fd\")) return true;\n if (normalized.startsWith(\"fe80\")) return true;\n if (normalized.startsWith(\"::ffff:\")) {\n const mapped = normalized.slice(\"::ffff:\".length);\n if (isPrivateIpv4(mapped)) return true;\n const hexMatch = /^([0-9a-f]{1,4}):([0-9a-f]{1,4})$/i.exec(mapped);\n if (hexMatch) {\n const value =\n (parseInt(hexMatch[1], 16) << 16) | parseInt(hexMatch[2], 16);\n const dotted = [\n (value >>> 24) & 0xff,\n (value >>> 16) & 0xff,\n (value >>> 8) & 0xff,\n value & 0xff,\n ].join(\".\");\n if (isPrivateIpv4(dotted)) return true;\n }\n }\n return BLOCKED_HOSTNAME_PATTERNS.some((pattern) => pattern.test(normalized));\n}\n\n/** Reject public-resource URLs that could target an internal network. */\nexport function validateRemoteUrl(raw: string): {\n ok: boolean;\n url?: URL;\n error?: string;\n} {\n let url: URL;\n try {\n url = new URL(raw);\n } catch {\n return { ok: false, error: \"Not a valid URL\" };\n }\n if (url.protocol === \"https:\") {\n if (isBlockedHostname(url.hostname)) {\n return {\n ok: false,\n error: `Host \"${url.hostname}\" is not allowed (private/internal address)`,\n };\n }\n return { ok: true, url };\n }\n if (url.protocol === \"http:\") {\n const host = url.hostname;\n if (host === \"localhost\" || host === \"127.0.0.1\") {\n return { ok: true, url };\n }\n return { ok: false, error: \"Plain http is only allowed for localhost\" };\n }\n return { ok: false, error: `Unsupported protocol: ${url.protocol}` };\n}\n"]}
@@ -29,6 +29,7 @@ export interface ClientServer {
29
29
  headers?: Record<string, {
30
30
  set: true;
31
31
  }>;
32
+ authMode: "none" | "headers" | "oauth";
32
33
  description?: string;
33
34
  firstParty?: boolean;
34
35
  createdAt: number;
@@ -1 +1 @@
1
- {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/mcp-client/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAkBH,OAAO,EAQL,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,2BAA2B,CAAC;AAOnC,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAI9D,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AACtB,OAAO,EAOL,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAgCpD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACxC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,sBAAsB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACzC,SAAS,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,YAAY,CAAC;QAAC,GAAG,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;CACrD;AAED,KAAK,YAAY,GACb;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AA6BzB,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EACrB,UAAU,EAAE,oBAAoB,EAChC,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAwFnE;AAiBD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,GACxB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CA4BrB;AAmCD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAsGN"}
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../src/mcp-client/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAkBH,OAAO,EAQL,KAAK,oBAAoB,EACzB,KAAK,sBAAsB,EAC5B,MAAM,2BAA2B,CAAC;AAOnC,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;AAI9D,OAAO,EAGL,KAAK,gBAAgB,EAEtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAOL,KAAK,cAAc,EAEpB,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAqCpD,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,cAAc,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,GAAG,EAAE,IAAI,CAAA;KAAE,CAAC,CAAC;IACxC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,YAAY,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,EAAE,EAAE,sBAAsB,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,EAAE;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,GAAG,EAAE,OAAO,CAAA;KAAE,CAAC;IACzC,SAAS,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,YAAY,CAAC;QAAC,GAAG,CAAC,EAAE,YAAY,CAAA;KAAE,CAAC;CACrD;AAED,KAAK,YAAY,GACb;IAAE,KAAK,EAAE,WAAW,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GACzC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,KAAK,EAAE,SAAS,CAAA;CAAE,CAAC;AA6BzB,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,cAAc,EACrB,UAAU,EAAE,oBAAoB,EAChC,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAwFnE;AAiBD,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,GACxB,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CA4BrB;AAmCD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,GAAG,EACb,OAAO,EAAE,gBAAgB,GACxB,IAAI,CA0GN"}
@@ -30,6 +30,7 @@ import { loadMcpConfig, autoDetectMcpConfig } from "./config.js";
30
30
  import { formatMcpConnectError } from "./errors.js";
31
31
  import { fetchHubServers } from "./hub-client.js";
32
32
  import { buildMcpToolName, parseMcpToolName, } from "./manager.js";
33
+ import { mountMcpOAuthRoutes } from "./oauth-routes.js";
33
34
  import { addRemoteServer, listRemoteServers, mergedConfigKey, removeRemoteServer, toHttpServerConfigAsync, validateRemoteUrl, } from "./remote-store.js";
34
35
  import { isMcpToolAllowedForRequest } from "./visibility.js";
35
36
  import { loadWorkspaceMcpServers } from "./workspace-servers.js";
@@ -50,6 +51,11 @@ function projectForClient(stored, scope, ownerId, status) {
50
51
  name: stored.name,
51
52
  url: stored.url,
52
53
  headers: redactHeaders(stored.headers),
54
+ authMode: stored.oauthSecretKey
55
+ ? "oauth"
56
+ : stored.headerSecretKey || stored.headers
57
+ ? "headers"
58
+ : "none",
53
59
  description: stored.description,
54
60
  firstParty: stored.firstParty === true,
55
61
  createdAt: stored.createdAt,
@@ -260,6 +266,9 @@ export function mountMcpServersRoutes(nitroApp, manager) {
260
266
  if (mountedApps.has(nitroApp))
261
267
  return;
262
268
  mountedApps.add(nitroApp);
269
+ mountMcpOAuthRoutes(nitroApp, {
270
+ reconfigure: () => reconfigureManager(manager),
271
+ });
263
272
  try {
264
273
  getH3App(nitroApp).use("/_agent-native/mcp/servers", defineEventHandler(async (event) => {
265
274
  const method = getMethod(event);