@onyxsecurity/mcp-gateway 2.1.44 → 2.1.45

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 (33) hide show
  1. package/dist/bin/mcp-gateway.js +2 -2
  2. package/dist/{cli-NNfNCI3t.js → cli-CNtgMMkg.js} +2 -2
  3. package/dist/{cli-NNfNCI3t.js.map → cli-CNtgMMkg.js.map} +1 -1
  4. package/dist/env-BDKldJJk.js +2 -0
  5. package/dist/env-BDKldJJk.js.map +1 -0
  6. package/dist/env-CgxPliUz.js +1 -0
  7. package/dist/{helpers-C3qmAIsg.js → helpers-DOLqaEj0.js} +2 -2
  8. package/dist/{helpers-C3qmAIsg.js.map → helpers-DOLqaEj0.js.map} +1 -1
  9. package/dist/index.d.ts +21 -0
  10. package/dist/index.js +1 -1
  11. package/dist/{logger-BJmPceiq.js → logger-CilZJgRr.js} +2 -2
  12. package/dist/{logger-BJmPceiq.js.map → logger-CilZJgRr.js.map} +1 -1
  13. package/dist/{logger-CfkToI34.js → logger-e6I79GjO.js} +1 -1
  14. package/dist/main-BFGMEBYS.js +6 -0
  15. package/dist/main-BFGMEBYS.js.map +1 -0
  16. package/dist/{oauthProvidersClient-CSnODh7t.js → oauthProvidersClient-CbHTOMq_.js} +2 -2
  17. package/dist/{oauthProvidersClient-CSnODh7t.js.map → oauthProvidersClient-CbHTOMq_.js.map} +1 -1
  18. package/dist/oauthProvidersClient-gES4TS6R.js +1 -0
  19. package/dist/{providers-B7LF2ET-.js → providers-DdC7BWQI.js} +2 -2
  20. package/dist/{providers-B7LF2ET-.js.map → providers-DdC7BWQI.js.map} +1 -1
  21. package/dist/{proxyFetch-DUPV_sLF.js → proxyFetch-C1EVTHaR.js} +2 -2
  22. package/dist/{proxyFetch-DUPV_sLF.js.map → proxyFetch-C1EVTHaR.js.map} +1 -1
  23. package/dist/{transportDetection-BGZCMulo.js → transportDetection-Dw8flZ7W.js} +2 -2
  24. package/dist/{transportDetection-BGZCMulo.js.map → transportDetection-Dw8flZ7W.js.map} +1 -1
  25. package/dist/{upstreamNegotiation-Bi4iOCfw.js → upstreamNegotiation-CRw30abB.js} +3 -3
  26. package/dist/{upstreamNegotiation-Bi4iOCfw.js.map → upstreamNegotiation-CRw30abB.js.map} +1 -1
  27. package/package.json +1 -1
  28. package/dist/env-6Gzgb9sf.js +0 -2
  29. package/dist/env-6Gzgb9sf.js.map +0 -1
  30. package/dist/env-DqLcmxAB.js +0 -1
  31. package/dist/main-CCeZBO84.js +0 -6
  32. package/dist/main-CCeZBO84.js.map +0 -1
  33. package/dist/oauthProvidersClient-C5aYP-7X.js +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onyxsecurity/mcp-gateway",
3
- "version": "2.1.44",
3
+ "version": "2.1.45",
4
4
  "packageManager": "bun@1.3.14",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {
@@ -1,2 +0,0 @@
1
- import{randomUUID as e}from"crypto";import t from"env-var";import{homedir as n}from"node:os";import{join as r}from"node:path";import"dotenv/config";const i={APP_VERSION:`2.1.44`},a=t.get,o=i.APP_VERSION,s=e=>{let t={};if(e){let n=e.split(`,`);for(let e of n){let[n,...r]=e.split(`:`);n&&r.length>0&&(t[n.trim()]=r.join(`:`).trim())}}return t},c=e=>{try{let t=new URL(e),n=t.pathname.split(`/`).filter(Boolean)[0]===`ingest`?`/ingest`:``;return`${t.protocol}//${t.host}${n}/endpoint-logs`}catch{return null}},l=/\/guard\/evaluate\/v1(\/?)$/,u=e=>{try{let t=new URL(e),n=t.pathname.replace(l,`/access-control/authorize$1`);return n===t.pathname?(console.warn(`[mcp-gateway] Warning: SCANNER_URL does not contain expected path "/guard/evaluate/v1". Access control URL derivation skipped. Current path: "${t.pathname}". Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null):(t.pathname=n,t.toString())}catch(e){return console.warn(`[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${e instanceof Error?e.message:String(e)}. Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`),null}},d=e(),f=a(`MCP_GATEWAY_DEBUG`).default(`false`).asBool(),p=a(`ONYX_MCP_GATEWAY_SUPPORT_NEW_MCP_PROTOCOL`).default(`true`).asBool(),m=a(`MCP_GATEWAY_SCANNER_URL`).default(``).asString()||null,h=a(`MCP_GATEWAY_SCANNER_API_KEY`).default(``).asString()||void 0,g=a(`MCP_GATEWAY_MIRROR_URL`).default(``).asString()||null,_=(()=>{let e=a(`MCP_GATEWAY_SCANNER_HEADERS`).required(!1).asString();return e?s(e):{}})(),v=a(`MCP_GATEWAY_SCANNER_TIMEOUT_MS`).default(`20000`).asIntPositive(),y=a(`MCP_GATEWAY_TOOL_TIMEOUT_MS`).default(`60000`).asIntPositive(),b=a(`MCP_GATEWAY_TOOL_MAX_TOTAL_TIMEOUT_MS`).default(`0`).asInt(),x=a(`MCP_GATEWAY_TOOL_RESET_TIMEOUT_ON_PROGRESS`).default(`true`).asBool(),S=a(`MCP_GATEWAY_UPSTREAM_CONNECT_MAX_RETRIES`).default(`3`).asInt(),C=a(`MCP_GATEWAY_UPSTREAM_CONNECT_INITIAL_DELAY_MS`).default(`500`).asIntPositive(),w=a(`MCP_GATEWAY_UPSTREAM_CONNECT_MAX_DELAY_MS`).default(`4000`).asIntPositive(),T=a(`MCP_GATEWAY_UPSTREAM_CONNECT_MAX_ELAPSED_MS`).default(`10000`).asInt(),E=a(`MCP_GATEWAY_UPSTREAM_RECONNECT_ENABLED`).default(`true`).asBool(),D=a(`MCP_GATEWAY_UPSTREAM_RECONNECT_ENABLED_FOR_STDIO`).default(`false`).asBool(),O=a(`MCP_GATEWAY_UPSTREAM_RECONNECT_COOLDOWN_MS`).default(`1000`).asIntPositive(),k=a(`MCP_GATEWAY_SCANNER_FAIL_OPEN`).default(`true`).asBool(),A=a(`MCP_GATEWAY_COMMAND`).default(`mcp-gateway`).asString(),j=a(`CLIENT_APP_NAME`).default(``).asString(),M=a(`MCP_GATEWAY_LOG_DIR`).default(r(n(),`.onyx`,`mcp-gateway`,`logs`)).asString(),N=a(`MCP_GATEWAY_OAUTH_DIR`).default(r(n(),`.onyx`,`mcp-gateway`,`oauth`)).asString(),P=(()=>a(`MCP_GATEWAY_ACCESS_CONTROL_URL`).default(``).asString()||(m?u(m):null))(),F=(()=>{let e=a(`MCP_GATEWAY_ACCESS_CONTROL_HEADERS`).required(!1).asString();return e?s(e):{}})(),I=a(`MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS`).default(`3000`).asIntPositive(),L=a(`MCP_GATEWAY_OAUTH_PROVIDERS_URL`).default(``).asString()||null,R=a(`MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS`).default(`5000`).asIntPositive(),z=a(`MCP_GATEWAY_LOG_INGEST_ENABLED`).default(`true`).asBool(),B=a(`MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS`).default(`5000`).asIntPositive(),V=(()=>a(`MCP_GATEWAY_LOG_INGEST_URL`).default(``).asString()||(g?c(g):m?c(m):null))(),H={accessControl:{enabled:!!(P&&h),headers:F,timeoutMs:I,url:P},appVersion:o,clientAppName:j,debug:f,logDir:M,logIngest:{apiKey:h,enabled:z&&!!(V&&h),timeoutMs:B,url:V},oauthDir:N,oauthProviders:{apiKey:h,enabled:!!(L&&h),timeoutMs:R,url:L},proxyCommand:A,scanner:{apiKey:h,enabled:!!m,failOpen:k,headers:_,timeoutMs:v,url:m},supportNewMcpProtocol:p,toolCall:{maxTotalTimeoutMs:b,resetTimeoutOnProgress:x,timeoutMs:y},upstream:{connect:{initialDelayMs:C,maxDelayMs:w,maxElapsedMs:T,maxRetries:S},reconnect:{cooldownMs:O,enabled:E,enabledForStdio:D}}};export{F as ACCESS_CONTROL_HEADERS,I as ACCESS_CONTROL_TIMEOUT_MS,P as ACCESS_CONTROL_URL,o as APP_VERSION,j as CLIENT_APP_NAME,f as DEBUG_MODE,M as LOG_DIR,z as LOG_INGEST_ENABLED,B as LOG_INGEST_TIMEOUT_MS,V as LOG_INGEST_URL,g as MIRROR_URL,N as OAUTH_DIR,R as OAUTH_PROVIDERS_TIMEOUT_MS,L as OAUTH_PROVIDERS_URL,A as PROXY_COMMAND,h as SCANNER_API_KEY,k as SCANNER_FAIL_OPEN,_ as SCANNER_HEADERS,v as SCANNER_TIMEOUT_MS,m as SCANNER_URL,d as SESSION_ID,p as SUPPORT_NEW_MCP_PROTOCOL,b as TOOL_CALL_MAX_TOTAL_TIMEOUT_MS,x as TOOL_CALL_RESET_TIMEOUT_ON_PROGRESS,y as TOOL_CALL_TIMEOUT_MS,C as UPSTREAM_CONNECT_INITIAL_DELAY_MS,w as UPSTREAM_CONNECT_MAX_DELAY_MS,T as UPSTREAM_CONNECT_MAX_ELAPSED_MS,S as UPSTREAM_CONNECT_MAX_RETRIES,O as UPSTREAM_RECONNECT_COOLDOWN_MS,E as UPSTREAM_RECONNECT_ENABLED,D as UPSTREAM_RECONNECT_ENABLED_FOR_STDIO,H as config,u as deriveAccessControlUrl,c as deriveLogIngestUrl};
2
- //# sourceMappingURL=env-6Gzgb9sf.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-6Gzgb9sf.js","names":["BUILD_TIME_CONFIG: BuildTimeConfig","headers: Record<string, string>"],"sources":["../src/config/config.generated.ts","../src/config/env.ts"],"sourcesContent":["// THIS FILE IS AUTO-GENERATED - DO NOT EDIT MANUALLY\n// Generated at build time from package.json\n\nimport type { BuildTimeConfig } from \"./config.js\";\n\nexport const BUILD_TIME_CONFIG: BuildTimeConfig = {\n \"APP_VERSION\": \"2.1.44\"\n};\n","import { randomUUID } from \"crypto\";\nimport envVar from \"env-var\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport \"dotenv/config\";\n\nconst env = envVar.get;\n\nimport { BUILD_TIME_CONFIG } from \"./config.generated.js\";\n\nexport const APP_VERSION = BUILD_TIME_CONFIG.APP_VERSION;\n\n// Helper function to parse headers from environment variable\nconst parseHeaders = (headerString: string): Record<string, string> => {\n const headers: Record<string, string> = {};\n if (headerString) {\n const headerPairs = headerString.split(\",\");\n for (const pair of headerPairs) {\n const [key, ...valueParts] = pair.split(\":\");\n if (key && valueParts.length > 0) {\n headers[key.trim()] = valueParts.join(\":\").trim();\n }\n }\n }\n return headers;\n};\n\n// Helper function to derive log ingest URL from scanner URL\n// Extracts scheme and host, appends /endpoint-logs path\n// Preserves /ingest prefix if present (needed for local setups)\n// Exported for testing\nexport const deriveLogIngestUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n // Check if first path segment is /ingest - preserve it for local setups\n const pathParts = url.pathname.split(\"/\").filter(Boolean);\n const basePath = pathParts[0] === \"ingest\" ? \"/ingest\" : \"\";\n return `${url.protocol}//${url.host}${basePath}/endpoint-logs`;\n } catch {\n return null;\n }\n};\n\n// Helper function to derive access control URL from scanner URL.\n//\n// SCANNER_URL and ACCESS_CONTROL_URL share the same host in production\n// (https://ai-guard.<tenant>/...), so when ACCESS_CONTROL_URL isn't set\n// explicitly we can swap the scanner path suffix for /access-control/authorize.\n//\n// Uses an anchored regex so a SCANNER_URL whose path is /guard/evaluate/v1-extra\n// or /guard/evaluate/v10 is treated as a non-match (returns null) rather than\n// producing a malformed URL.\n//\n// Note: this same-host assumption does NOT hold for the OAuth providers\n// endpoint, which lives on a different host (api.<tenant>) than the scanner.\n// MCP_GATEWAY_OAUTH_PROVIDERS_URL must be set explicitly — it is wired\n// through CI distribute-scanner.yaml and the install-script ONYX_ENV_VARS\n// pipeline, so it always arrives as a concrete URL in production.\n//\n// Exported for testing.\nconst accessControlPathRegex = /\\/guard\\/evaluate\\/v1(\\/?)$/;\n\nexport const deriveAccessControlUrl = (scannerUrl: string): null | string => {\n try {\n const url = new URL(scannerUrl);\n const expectedPath = \"/guard/evaluate/v1\";\n const replaced = url.pathname.replace(\n accessControlPathRegex,\n \"/access-control/authorize$1\"\n );\n\n if (replaced === url.pathname) {\n // Warn about non-standard format (can't use logger due to circular dependency)\n console.warn(\n `[mcp-gateway] Warning: SCANNER_URL does not contain expected path \"${expectedPath}\". ` +\n `Access control URL derivation skipped. Current path: \"${url.pathname}\". ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n\n url.pathname = replaced;\n return url.toString();\n } catch (error) {\n // Invalid URL format\n console.warn(\n `[mcp-gateway] Warning: Failed to parse SCANNER_URL as valid URL: ${error instanceof Error ? error.message : String(error)}. ` +\n `Please set MCP_GATEWAY_ACCESS_CONTROL_URL explicitly.`\n );\n return null;\n }\n};\n\nexport const SESSION_ID = randomUUID();\n\nexport const DEBUG_MODE = env(\"MCP_GATEWAY_DEBUG\").default(\"false\").asBool();\n\n// Kill switch for the modern (stateless) MCP protocol era.\n// Default on: the gateway advertises and serves client-facing **stdio** peers in\n// both the handshake era (the classic `initialize` handshake, revisions through\n// 2025-11-25) and the modern era (no `initialize`; `server/discover` plus a\n// per-request `_meta` envelope), AND its upstream client negotiates the era\n// with the wrapped server (`versionNegotiation: 'auto'` — see\n// lib/upstreamNegotiation.ts), so upstreams of either era can be wrapped. Set\n// to false to pin the gateway to handshake-only on both legs — the exact\n// behaviour before dual-era support — which is the escape hatch if a\n// modern-era peer interaction misbehaves in the field.\n// Scope, deliberately asymmetric: dual-era SERVING is stdio only. The `--port`\n// HTTP serving lane stays handshake-era in either state, because it only builds\n// a transport for a session-id-bearing or `initialize` request and answers a\n// modern opening with 400 / -32000 (see the comment at that branch in\n// bin/main.ts). The UPSTREAM leg negotiates in both modes, so in `--port` mode\n// this flag governs the upstream leg alone.\n// Note the ONYX_ prefix: this is a product-level protocol toggle, not one of the\n// tenant-injected MCP_GATEWAY_* transport knobs.\nexport const SUPPORT_NEW_MCP_PROTOCOL = env(\"ONYX_MCP_GATEWAY_SUPPORT_NEW_MCP_PROTOCOL\").default(\"true\").asBool();\n\nexport const SCANNER_URL = env(\"MCP_GATEWAY_SCANNER_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_API_KEY = env(\"MCP_GATEWAY_SCANNER_API_KEY\").default(\"\").asString() || undefined;\n\nexport const MIRROR_URL = env(\"MCP_GATEWAY_MIRROR_URL\").default(\"\").asString() || null;\n\nexport const SCANNER_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_SCANNER_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const SCANNER_TIMEOUT_MS = env(\"MCP_GATEWAY_SCANNER_TIMEOUT_MS\").default(\"20000\").asIntPositive();\n\n// Forwarded tool-call timeout knobs.\n//\n// The MCP SDK defaults every forwarded request to a 60s timeout\n// (DEFAULT_REQUEST_TIMEOUT_MSEC) with no progress-based reset, and the gateway\n// previously forwarded no RequestOptions at all. That capped long-running\n// upstream tools (e.g. slow DB queries) at 60s regardless of the client's own\n// timeout. These knobs raise the per-request ceiling and opt into resetting it\n// on upstream progress. See src/proxyServer.ts.\nexport const TOOL_CALL_TIMEOUT_MS = env(\"MCP_GATEWAY_TOOL_TIMEOUT_MS\").default(\"60000\").asIntPositive();\n\n// Absolute ceiling across progress resets. 0 (default) disables the cap, which\n// matches the SDK semantics of an undefined maxTotalTimeout.\nexport const TOOL_CALL_MAX_TOTAL_TIMEOUT_MS = env(\"MCP_GATEWAY_TOOL_MAX_TOTAL_TIMEOUT_MS\").default(\"0\").asInt();\n\n// When true (default), each upstream progress notification resets the\n// per-request timeout, and progress is forwarded on to the client. Only has an\n// effect for upstream servers that actually emit progress notifications.\nexport const TOOL_CALL_RESET_TIMEOUT_ON_PROGRESS = env(\"MCP_GATEWAY_TOOL_RESET_TIMEOUT_ON_PROGRESS\").default(\"true\").asBool();\n\n// Upstream connect-time resilience knobs.\n//\n// The gateway connects to the upstream MCP server once at startup and treats a\n// failure as fatal (\"MCP server failed to start\"). Upstream reachability can\n// flap (DNS/VPN blips, brief outages) and self-recover within seconds, so a\n// bounded retry-with-backoff at connect time turns most transient failures into\n// a successful start instead of a dead session. The whole budget must stay\n// under the MCP client's own server-startup timeout, hence the wall-clock cap.\n// See src/lib/connectWithRetry.ts.\nexport const UPSTREAM_CONNECT_MAX_RETRIES = env(\"MCP_GATEWAY_UPSTREAM_CONNECT_MAX_RETRIES\").default(\"3\").asInt();\n\nexport const UPSTREAM_CONNECT_INITIAL_DELAY_MS = env(\"MCP_GATEWAY_UPSTREAM_CONNECT_INITIAL_DELAY_MS\").default(\"500\").asIntPositive();\n\nexport const UPSTREAM_CONNECT_MAX_DELAY_MS = env(\"MCP_GATEWAY_UPSTREAM_CONNECT_MAX_DELAY_MS\").default(\"4000\").asIntPositive();\n\n// Hard wall-clock cap across all connect attempts. 0 disables the cap.\nexport const UPSTREAM_CONNECT_MAX_ELAPSED_MS = env(\"MCP_GATEWAY_UPSTREAM_CONNECT_MAX_ELAPSED_MS\").default(\"10000\").asInt();\n\n// Mid-session reconnect knobs.\n//\n// Once connected, the upstream can still drop mid-session (the same reachability\n// flap, or a terminated/expired session). Rather than leaving the session dead\n// until the user restarts the client, the gateway rebuilds the upstream\n// connection on a recoverable failure and retries the call. Scoped to REMOTE\n// upstreams by default: a stdio \"reconnect\" respawns the child and loses its\n// in-memory state, so it's opt-in. Reconnect is driven by traffic (one attempt\n// per failing call, deduped) with a cooldown to collapse bursts — no background\n// loop. See src/lib/reconnectingClient.ts.\nexport const UPSTREAM_RECONNECT_ENABLED = env(\"MCP_GATEWAY_UPSTREAM_RECONNECT_ENABLED\").default(\"true\").asBool();\n\nexport const UPSTREAM_RECONNECT_ENABLED_FOR_STDIO = env(\"MCP_GATEWAY_UPSTREAM_RECONNECT_ENABLED_FOR_STDIO\").default(\"false\").asBool();\n\n// Minimum gap between reconnect attempts, so a burst of concurrent failed calls\n// triggers at most one reconnect per window.\nexport const UPSTREAM_RECONNECT_COOLDOWN_MS = env(\"MCP_GATEWAY_UPSTREAM_RECONNECT_COOLDOWN_MS\").default(\"1000\").asIntPositive();\n\nexport const SCANNER_FAIL_OPEN = env(\"MCP_GATEWAY_SCANNER_FAIL_OPEN\").default(\"true\").asBool();\n\nexport const PROXY_COMMAND = env(\"MCP_GATEWAY_COMMAND\").default(\"mcp-gateway\").asString();\n\nexport const CLIENT_APP_NAME = env(\"CLIENT_APP_NAME\").default(\"\").asString();\n\nexport const LOG_DIR = env(\"MCP_GATEWAY_LOG_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"logs\"))\n .asString();\n\nexport const OAUTH_DIR = env(\"MCP_GATEWAY_OAUTH_DIR\")\n .default(join(homedir(), \".onyx\", \"mcp-gateway\", \"oauth\"))\n .asString();\n\nexport const ACCESS_CONTROL_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_ACCESS_CONTROL_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // If not explicitly set, derive from scanner URL\n if (SCANNER_URL) {\n return deriveAccessControlUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const ACCESS_CONTROL_HEADERS = (() => {\n const runtimeHeaders = env(\"MCP_GATEWAY_ACCESS_CONTROL_HEADERS\").required(false).asString();\n if (runtimeHeaders) {\n return parseHeaders(runtimeHeaders);\n }\n return {};\n})();\n\nexport const ACCESS_CONTROL_TIMEOUT_MS = env(\"MCP_GATEWAY_ACCESS_CONTROL_TIMEOUT_MS\").default(\"3000\").asIntPositive();\n\n// OAuth providers configuration (fetched from web extension service at startup).\n//\n// Set explicitly per-tenant via MCP_GATEWAY_OAUTH_PROVIDERS_URL or the\n// --oauth-providers-url CLI flag. Unlike SCANNER_URL/ACCESS_CONTROL_URL, the\n// OAuth providers endpoint lives on a different host (api.<tenant>) than the\n// scanner (ai-guard.<tenant>) — so we cannot derive it from SCANNER_URL and\n// must rely on the install pipeline to inject the concrete URL.\nexport const OAUTH_PROVIDERS_URL =\n env(\"MCP_GATEWAY_OAUTH_PROVIDERS_URL\").default(\"\").asString() || null;\n\nexport const OAUTH_PROVIDERS_TIMEOUT_MS = env(\"MCP_GATEWAY_OAUTH_PROVIDERS_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\n// Log ingest configuration (for Groundcover logging)\nexport const LOG_INGEST_ENABLED = env(\"MCP_GATEWAY_LOG_INGEST_ENABLED\").default(\"true\").asBool();\n\nexport const LOG_INGEST_TIMEOUT_MS = env(\"MCP_GATEWAY_LOG_INGEST_TIMEOUT_MS\").default(\"5000\").asIntPositive();\n\nexport const LOG_INGEST_URL = (() => {\n const explicitUrl = env(\"MCP_GATEWAY_LOG_INGEST_URL\").default(\"\").asString();\n if (explicitUrl) {\n return explicitUrl;\n }\n // Derive from mirror URL (on ingest.* host) since SCANNER_URL points to\n // ai-guard.* which doesn't have an /endpoint-logs route\n if (MIRROR_URL) {\n return deriveLogIngestUrl(MIRROR_URL);\n }\n if (SCANNER_URL) {\n return deriveLogIngestUrl(SCANNER_URL);\n }\n return null;\n})();\n\nexport const config = {\n accessControl: {\n enabled: Boolean(ACCESS_CONTROL_URL && SCANNER_API_KEY),\n headers: ACCESS_CONTROL_HEADERS,\n timeoutMs: ACCESS_CONTROL_TIMEOUT_MS,\n url: ACCESS_CONTROL_URL,\n },\n appVersion: APP_VERSION,\n clientAppName: CLIENT_APP_NAME,\n debug: DEBUG_MODE,\n logDir: LOG_DIR,\n logIngest: {\n apiKey: SCANNER_API_KEY,\n enabled: LOG_INGEST_ENABLED && Boolean(LOG_INGEST_URL && SCANNER_API_KEY),\n timeoutMs: LOG_INGEST_TIMEOUT_MS,\n url: LOG_INGEST_URL,\n },\n oauthDir: OAUTH_DIR,\n oauthProviders: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(OAUTH_PROVIDERS_URL && SCANNER_API_KEY),\n timeoutMs: OAUTH_PROVIDERS_TIMEOUT_MS,\n url: OAUTH_PROVIDERS_URL,\n },\n proxyCommand: PROXY_COMMAND,\n scanner: {\n apiKey: SCANNER_API_KEY,\n enabled: Boolean(SCANNER_URL),\n failOpen: SCANNER_FAIL_OPEN,\n headers: SCANNER_HEADERS,\n timeoutMs: SCANNER_TIMEOUT_MS,\n url: SCANNER_URL,\n },\n supportNewMcpProtocol: SUPPORT_NEW_MCP_PROTOCOL,\n toolCall: {\n maxTotalTimeoutMs: TOOL_CALL_MAX_TOTAL_TIMEOUT_MS,\n resetTimeoutOnProgress: TOOL_CALL_RESET_TIMEOUT_ON_PROGRESS,\n timeoutMs: TOOL_CALL_TIMEOUT_MS,\n },\n upstream: {\n connect: {\n initialDelayMs: UPSTREAM_CONNECT_INITIAL_DELAY_MS,\n maxDelayMs: UPSTREAM_CONNECT_MAX_DELAY_MS,\n maxElapsedMs: UPSTREAM_CONNECT_MAX_ELAPSED_MS,\n maxRetries: UPSTREAM_CONNECT_MAX_RETRIES,\n },\n reconnect: {\n cooldownMs: UPSTREAM_RECONNECT_COOLDOWN_MS,\n enabled: UPSTREAM_RECONNECT_ENABLED,\n enabledForStdio: UPSTREAM_RECONNECT_ENABLED_FOR_STDIO,\n },\n },\n} as const;\n\n// Note: Don't use the logger here to avoid circular dependency issues\n// The logger hasn't been initialized yet when this config file is imported\n// Configuration is logged to file by the logger once initialized\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- import{ACCESS_CONTROL_HEADERS as e,ACCESS_CONTROL_TIMEOUT_MS as t,ACCESS_CONTROL_URL as n,APP_VERSION as r,CLIENT_APP_NAME as i,DEBUG_MODE as a,LOG_DIR as o,LOG_INGEST_ENABLED as s,LOG_INGEST_TIMEOUT_MS as c,LOG_INGEST_URL as l,MIRROR_URL as u,OAUTH_DIR as d,OAUTH_PROVIDERS_TIMEOUT_MS as f,OAUTH_PROVIDERS_URL as p,PROXY_COMMAND as m,SCANNER_API_KEY as h,SCANNER_FAIL_OPEN as g,SCANNER_HEADERS as _,SCANNER_TIMEOUT_MS as v,SCANNER_URL as y,SESSION_ID as b,SUPPORT_NEW_MCP_PROTOCOL as x,TOOL_CALL_MAX_TOTAL_TIMEOUT_MS as S,TOOL_CALL_RESET_TIMEOUT_ON_PROGRESS as C,TOOL_CALL_TIMEOUT_MS as w,UPSTREAM_CONNECT_INITIAL_DELAY_MS as T,UPSTREAM_CONNECT_MAX_DELAY_MS as E,UPSTREAM_CONNECT_MAX_ELAPSED_MS as D,UPSTREAM_CONNECT_MAX_RETRIES as O,UPSTREAM_RECONNECT_COOLDOWN_MS as k,UPSTREAM_RECONNECT_ENABLED as A,UPSTREAM_RECONNECT_ENABLED_FOR_STDIO as j,config as M,deriveAccessControlUrl as N,deriveLogIngestUrl as P}from"./env-6Gzgb9sf.js";export{M as config};
@@ -1,6 +0,0 @@
1
- import{proxiedFetch as e}from"./proxyFetch-DUPV_sLF.js";import{AccessControlBlockError as t,ConfigurationError as n,ProtocolEraMismatchError as r,ProxyConnectionError as i,Server as a,StdioServerTransport as o,compressClientInfo as s,getSessionData as c,initializeTrafficMirror as l,logRequestCounts as u,proxyServer as d,redactCliArgs as f,serveStdio as ee,startHTTPServer as te,upstreamVersionNegotiation as p}from"./upstreamNegotiation-Bi4iOCfw.js";import{config as m}from"./env-6Gzgb9sf.js";import{chownToRealUser as h,extractTraceIdFromHeaders as ne,flushLogs as re,logger as g}from"./logger-BJmPceiq.js";import{Client as ie,ProtocolError as _,ReadBuffer as v,UnauthorizedError as y,createParser as b,normalizeUrl as x,serializeMessage as S}from"./normalizeUrl-DUUGubD4.js";import{emitKeychainOutcomeLog as ae,emitProxySetupLog as oe,hideBin as se,probeOperatorProxyForChild as ce,restoreOperatorProxyEnv as le,yargs_default as ue}from"./helpers-C3qmAIsg.js";import"./providers-B7LF2ET-.js";import{initializeOAuthProviders as de}from"./oauthProvidersClient-CSnODh7t.js";import"./pkce-DUsFn3Kw.js";import{connectWithTransportFallback as fe,discoverAuthServer as pe,performOAuthFlow as me,tryRefreshCachedToken as he}from"./transportDetection-BGZCMulo.js";import{join as ge}from"node:path";import{createHash as _e}from"node:crypto";import{chmod as ve,mkdir as ye,readFile as C,rm as be,writeFile as xe}from"node:fs/promises";import{execFileSync as Se,spawn as Ce,spawnSync as we}from"node:child_process";import{StringDecoder as Te}from"node:string_decoder";import{clearInterval as Ee,setInterval as De,setTimeout as Oe}from"node:timers";import w from"node:util";import{createInterface as T}from"node:readline";import{PassThrough as E,Transform as ke}from"node:stream";var D=class extends Event{constructor(e,t){super(e),this.code=t?.code??void 0,this.message=t?.message??void 0}[Symbol.for(`nodejs.util.inspect.custom`)](e,t,n){return n(k(this),t)}[Symbol.for(`Deno.customInspect`)](e,t){return e(k(this),t)}};function Ae(e){let t=globalThis.DOMException;return typeof t==`function`?new t(e,`SyntaxError`):SyntaxError(e)}function O(e){return e instanceof Error?`errors`in e&&Array.isArray(e.errors)?e.errors.map(O).join(`, `):`cause`in e&&e.cause instanceof Error?`${e}: ${O(e.cause)}`:e.message:`${e}`}function k(e){return{type:e.type,message:e.message,code:e.code,defaultPrevented:e.defaultPrevented,cancelable:e.cancelable,timeStamp:e.timeStamp}}var A=e=>{throw TypeError(e)},j=(e,t,n)=>t.has(e)||A(`Cannot `+n),M=(e,t,n)=>(j(e,t,`read from private field`),n?n.call(e):t.get(e)),N=(e,t,n)=>t.has(e)?A(`Cannot add the same private member more than once`):t instanceof WeakSet?t.add(e):t.set(e,n),P=(e,t,n,r)=>(j(e,t,`write to private field`),t.set(e,n),n),F=(e,t,n)=>(j(e,t,`access private method`),n),I,L,R,je,Me,z,B,V,H,U,W,G,K,q,Ne,Pe,Fe,Ie,Le,Re,J,ze,Be,Y=class extends EventTarget{constructor(e,t){super(),N(this,q),this.CONNECTING=0,this.OPEN=1,this.CLOSED=2,N(this,I),N(this,L),N(this,R),N(this,je),N(this,Me),N(this,z),N(this,B),N(this,V,null),N(this,H),N(this,U),N(this,W,null),N(this,G,null),N(this,K,null),N(this,Pe,async e=>{var t;M(this,U).reset();let{body:n,redirected:r,status:i,headers:a}=e;if(i===204){F(this,q,J).call(this,`Server sent HTTP 204, not reconnecting`,204),this.close();return}if(r?P(this,R,new URL(e.url)):P(this,R,void 0),i!==200){F(this,q,J).call(this,`Non-200 status code (${i})`,i);return}if(!(a.get(`content-type`)||``).startsWith(`text/event-stream`)){F(this,q,J).call(this,`Invalid content type, expected "text/event-stream"`,i);return}if(M(this,I)===this.CLOSED)return;P(this,I,this.OPEN);let o=new Event(`open`);if((t=M(this,K))==null||t.call(this,o),this.dispatchEvent(o),typeof n!=`object`||!n||!(`getReader`in n)){F(this,q,J).call(this,`Invalid response body, expected a web ReadableStream`,i),this.close();return}let s=new TextDecoder,c=n.getReader(),l=!0;do{let{done:e,value:t}=await c.read();t&&M(this,U).feed(s.decode(t,{stream:!e})),e&&(l=!1,M(this,U).reset(),F(this,q,ze).call(this))}while(l)}),N(this,Fe,e=>{P(this,H,void 0),!(e.name===`AbortError`||e.type===`aborted`)&&F(this,q,ze).call(this,O(e))}),N(this,Le,e=>{typeof e.id==`string`&&P(this,V,e.id);let t=new MessageEvent(e.event||`message`,{data:e.data,origin:M(this,R)?M(this,R).origin:M(this,L).origin,lastEventId:e.id||``});M(this,G)&&(!e.event||e.event===`message`)&&M(this,G).call(this,t),this.dispatchEvent(t)}),N(this,Re,e=>{P(this,z,e)}),N(this,Be,()=>{P(this,B,void 0),M(this,I)===this.CONNECTING&&F(this,q,Ne).call(this)});try{if(e instanceof URL)P(this,L,e);else if(typeof e==`string`)P(this,L,new URL(e,Ve()));else throw Error(`Invalid URL`)}catch{throw Ae(`An invalid or illegal string was specified`)}P(this,U,b({onEvent:M(this,Le),onRetry:M(this,Re)})),P(this,I,this.CONNECTING),P(this,z,3e3),P(this,Me,t?.fetch??globalThis.fetch),P(this,je,t?.withCredentials??!1),F(this,q,Ne).call(this)}get readyState(){return M(this,I)}get url(){return M(this,L).href}get withCredentials(){return M(this,je)}get onerror(){return M(this,W)}set onerror(e){P(this,W,e)}get onmessage(){return M(this,G)}set onmessage(e){P(this,G,e)}get onopen(){return M(this,K)}set onopen(e){P(this,K,e)}addEventListener(e,t,n){let r=t;super.addEventListener(e,r,n)}removeEventListener(e,t,n){let r=t;super.removeEventListener(e,r,n)}close(){M(this,B)&&clearTimeout(M(this,B)),M(this,I)!==this.CLOSED&&(M(this,H)&&M(this,H).abort(),P(this,I,this.CLOSED),P(this,H,void 0))}};I=new WeakMap,L=new WeakMap,R=new WeakMap,je=new WeakMap,Me=new WeakMap,z=new WeakMap,B=new WeakMap,V=new WeakMap,H=new WeakMap,U=new WeakMap,W=new WeakMap,G=new WeakMap,K=new WeakMap,q=new WeakSet,Ne=function(){P(this,I,this.CONNECTING),P(this,H,new AbortController),M(this,Me)(M(this,L),F(this,q,Ie).call(this)).then(M(this,Pe)).catch(M(this,Fe))},Pe=new WeakMap,Fe=new WeakMap,Ie=function(){let e={mode:`cors`,redirect:`follow`,headers:{Accept:`text/event-stream`,...M(this,V)?{"Last-Event-ID":M(this,V)}:void 0},cache:`no-store`,signal:M(this,H)?.signal};return`window`in globalThis&&(e.credentials=this.withCredentials?`include`:`same-origin`),e},Le=new WeakMap,Re=new WeakMap,J=function(e,t){var n;M(this,I)!==this.CLOSED&&P(this,I,this.CLOSED);let r=new D(`error`,{code:t,message:e});(n=M(this,W))==null||n.call(this,r),this.dispatchEvent(r)},ze=function(e,t){var n;if(M(this,I)===this.CLOSED)return;P(this,I,this.CONNECTING);let r=new D(`error`,{code:t,message:e});(n=M(this,W))==null||n.call(this,r),this.dispatchEvent(r),P(this,B,setTimeout(M(this,Be),M(this,z)))},Be=new WeakMap,Y.CONNECTING=0,Y.OPEN=1,Y.CLOSED=2;function Ve(){let e=`document`in globalThis?globalThis.document:void 0;return e&&typeof e==`object`&&`baseURI`in e&&typeof e.baseURI==`string`?e.baseURI:void 0}var He=class{client;enabled;lastBlockReason;serverName;constructor(e){this.enabled=e.enabled,this.client=e.client,this.serverName=e.serverName,g.info(`AccessControlAuthorizer initialized`,{enabled:this.enabled,hasClient:!!this.client,serverName:this.serverName})}getBlockReason(){return this.lastBlockReason?this.lastBlockReason:`MCP server${this.serverName?` '${this.serverName}'`:``} is not authorized for use in your organization and has been blocked by Onyx.`}async isAllowed(){if(!this.enabled)return!0;if(this.client)try{let e=await this.client.authorize();return e.action===`block`?(e.reason?this.lastBlockReason=e.reason:this.lastBlockReason=`MCP server${this.serverName?` '${this.serverName}'`:``} is not authorized for use in your organization and has been blocked by Onyx.`,!1):!0}catch(e){return g.error(`Access control authorization failed with unexpected error`,{error:String(e)}),!0}return g.warn(`No access control client configured, allowing by default`),!0}},Ue=class{clientInfoBase64;config;constructor(e){this.config=e,this.clientInfoBase64=this.getClientInfoBase64(),g.info(`AccessControlClient initialized`,{timeoutMs:e.timeoutMs,url:e.url})}async authorize(){try{let e=await this.sendAuthorizeRequest();return g.debug(`Access control check successful`,{action:e.action}),e}catch(e){return g.warn(`Access control check failed, failing open (allowing by default)`,{error:String(e)}),{action:`allow`}}}getClientInfoBase64(){return s(this.config.sessionData)}async sendAuthorizeRequest(){let t=new AbortController,n=setTimeout(()=>t.abort(),this.config.timeoutMs);try{let n=`${this.config.url}/${this.config.apiKey}/mcp/${this.clientInfoBase64}`,r=await e(n,{headers:{...this.config.headers},method:`POST`,signal:t.signal});if(!r.ok)throw Error(`Access control service returned ${r.status}: ${r.statusText}`);let i=await r.json();if(!i.action||![`allow`,`block`].includes(i.action))throw Error(`Invalid access control response format: action="${i.action}"`);return i}catch(e){throw e instanceof Error&&e.name===`AbortError`?Error(`Access control check timed out after ${this.config.timeoutMs}ms`):e}finally{clearTimeout(n)}}},We=class{storageDir;constructor(e){this.storageDir=e.storageDir}async delete(e){let t=x(e),n=this.getFilePath(t);try{await be(n),g.debug(`Deleted stored credentials`,{filePath:n,serverUrl:t})}catch(e){e.code!==`ENOENT`&&g.warn(`Failed to delete stored credentials`,{error:String(e),filePath:n,serverUrl:t})}}hasRefreshToken(e){return!!e.tokens?.refresh_token}hasValidAccessToken(e){return!!e.tokens?.access_token&&!this.isAccessTokenExpired(e)}isAccessTokenExpired(e){if(!e.tokens||!e.tokensObtainedAt)return!0;let{expires_in:t}=e.tokens;if(!t)return!1;let n=new Date(e.tokensObtainedAt).getTime()+t*1e3,r=Date.now(),i=r>=n-3e4;return g.debug(`Checked access token expiration`,{expiresAt:new Date(n).toISOString(),expiresIn:t,isExpired:i,now:new Date(r).toISOString(),obtainedAt:e.tokensObtainedAt}),i}async load(e){let t=x(e),n=this.getFilePath(t);try{let e=await C(n,`utf-8`),r=JSON.parse(e);if(x(r.serverUrl)!==t){g.warn(`Credential file server URL mismatch`,{expected:t,filePath:n,found:r.serverUrl});return}return g.debug(`Loaded stored credentials`,{clientId:r.clientInfo?.client_id,hasRefreshToken:!!r.tokens?.refresh_token,hasTokens:!!r.tokens,serverUrl:t}),r}catch(e){if(e.code===`ENOENT`){g.debug(`No stored credentials found`,{serverUrl:t});return}g.warn(`Failed to load stored credentials`,{error:String(e),filePath:n,serverUrl:t});return}}async save(e){await this.ensureStorageDir();let t=this.getFilePath(e.serverUrl),n=JSON.stringify(e,null,2);try{await xe(t,n,{encoding:`utf-8`,mode:384}),await ve(t,384),g.debug(`Saved credentials to disk`,{clientId:e.clientInfo?.client_id,filePath:t,hasTokens:!!e.tokens,serverUrl:e.serverUrl})}catch(n){throw g.error(`Failed to save credentials`,{error:String(n),filePath:t,serverUrl:e.serverUrl}),n}}async update(e,t){let n=x(e),r=await this.load(n),i=new Date().toISOString(),a=r?{...r,...t,serverUrl:n,updatedAt:i}:{createdAt:i,serverUrl:n,updatedAt:i,...t};return await this.save(a),a}async ensureStorageDir(){try{await ye(this.storageDir,{mode:448,recursive:!0})}catch(e){if(e.code!==`EEXIST`)throw e}try{await h(this.storageDir)}catch(e){g.warn(`Failed to fix OAuth storage directory ownership`,{error:String(e),storageDir:this.storageDir})}}generateKey(e){return _e(`sha256`).update(e).digest(`hex`).substring(0,16)}getFilePath(e){let t=this.generateKey(e);return ge(this.storageDir,`${t}.json`)}};function Ge(t,n=e){return async(e,r)=>{let i=new Headers(r?.headers).has(`Authorization`),a=e=>{let t=new Headers(r?.headers);return e?t.set(`Authorization`,`Bearer ${e}`):i||t.delete(`Authorization`),{...r,headers:t}},o=t.getCurrentBearer(),s=await n(e,a(o));if(!s.ok){let t=``;try{t=(await s.clone().text()).slice(0,500)}catch{}let n={bodySnippet:t,contentType:s.headers.get(`content-type`)??void 0,eventType:`mcp_upstream_non_2xx`,method:String(r?.method??`GET`).toUpperCase(),requestAccept:new Headers(r?.headers).get(`accept`)??void 0,requestHadAuth:!!o||i,status:s.status,url:qe(e),wwwAuthenticate:s.headers.get(`www-authenticate`)??void 0};s.status===401?g.info(`Upstream returned non-2xx (auth challenge)`,n):g.warn(`Upstream returned non-2xx`,n)}if(s.status===401&&o){g.info(`Upstream returned 401; attempting mid-session silent refresh`,{eventType:`mcp_auth_mid_session_refresh_attempt`});let r=await t.refreshIfPossible(o);r&&r!==o?(g.info(`Silent refresh succeeded mid-session; retrying request`,{eventType:`mcp_auth_mid_session_refresh_succeeded`}),s=await n(e,a(r))):g.warn(`Silent refresh produced no new bearer; passing 401 through`,{eventType:`mcp_auth_mid_session_refresh_failed`})}return s}}function Ke(e,t,n){let r=n,i=null;return{getCurrentBearer:()=>r,refreshIfPossible:n=>i||(i=(async()=>{try{let i=(await t.load(e))?.tokens?.access_token;if(i&&i!==n)return g.info(`Adopting newer access_token from disk (other process refreshed)`,{eventType:`mcp_auth_disk_bearer_adopted`,serverUrl:e}),r=i,i;let a=await he(e,t);return a?.tokens.access_token?(r=a.tokens.access_token,r):void 0}finally{i=null}})(),i),setBearer:e=>{r=e}}}function qe(e){try{let t=typeof e==`string`?e:String(e),n=new URL(t);return`${n.origin}${n.pathname}`}catch{return`[unparseable-url]`}}function Je(e){if(typeof e!=`object`||!e)return;let t=e.code;return typeof t==`number`?t:void 0}function X(e){return e instanceof Error?e.message??``:typeof e==`string`?e:e&&typeof e==`object`&&`message`in e?String(e.message??``):``}const Z=[`2024-11-05`,`2025-03-26`,`2025-06-18`,`2025-11-25`],Ye=-32601,Xe=new Set([-32004,-32022]),Ze=/\binitialize\b/i,Qe=/method not found[^\w]*\binitialize\b|\binitialize\b[^\w]*method not found/,$e=/unsupported protocol version|protocol version is not supported/,et=e=>RegExp(`${Qe.source}|${$e.source}`,`i`).test(e);function tt(e,t){let n=`this gateway speaks the handshake era (${Z[0]} … ${Z[Z.length-1]})`;return t===void 0||nt(t)?`the MCP server at ${e} does not implement the \`initialize\` handshake, which means it speaks only protocol revision 2026-07-28 or later (the stateless "modern era" removed \`initialize\`), while ${n}`:`the MCP server at ${e} rejected the protocol revision this gateway offered (${X(t)||`no detail given`}); ${n}`}function Q(e){let t=X(e),n=Je(e);return n!==void 0&&Xe.has(n)||n===Ye&&Ze.test(t)?!0:t.length>0&&et(t)}function nt(e){let t=X(e);return Je(e)===Ye&&Ze.test(t)?!0:new RegExp(Qe.source,`i`).test(t)}const rt=/^(ctx7sk|tvly|sk|pat|gh[posu]|github_pat|glpat|xox[abprs]|AKIA|Bearer)[-_]/i,it=e=>e.length>=12||rt.test(e),at=e=>{try{return decodeURIComponent(e)}catch{return``}},ot=e=>{try{return encodeURIComponent(e)}catch{return``}},st=e=>{try{return new URL(e).origin}catch{return e}},ct=e=>{let t;try{t=new URL(e)}catch{return[e]}let n=new Set([e]);t.username&&n.add(t.username),t.password&&n.add(t.password);let r=e=>{for(let t of[e,at(e),ot(e)])t&&it(t)&&n.add(t)};if(t.search){let e=t.search.replace(/^\?/,``);n.add(e);for(let t of e.split(`&`)){let e=t.indexOf(`=`);e>=0&&r(t.slice(e+1))}for(let e of t.searchParams.values())r(e)}if(t.pathname&&t.pathname!==`/`){n.add(`${t.pathname}${t.search}`),n.add(t.pathname);for(let e of t.pathname.split(`/`))e&&r(e)}return[...n].filter(e=>e.length>0).sort((e,t)=>t.length-e.length)},lt=(e,t)=>{if(!t)return e;let n=st(t),r=`\0onyx-origin\0`,i=n?e.split(n).join(r):e;for(let e of ct(t)){if(e===n)continue;i=i.split(e).join(`[REDACTED]`)}return i.split(r).join(n)};async function ut(e,t={}){let n=t.code??-32603,r=t.timeoutMs??4e3,i=t.input??process.stdin,a=t.output??process.stdout;return i.isTTY?!1:new Promise(t=>{let o=!1,s=!1,c=!1,l=T({input:i}),u=()=>{o||(o=!0,clearTimeout(d),l.removeAllListeners(`line`),l.close(),t(s))},d=setTimeout(u,r);d.unref?.(),l.on(`line`,t=>{if(c)return;let r=t.trim();if(!r)return;let i;try{i=JSON.parse(r)}catch{return}i&&i.id!==void 0&&i.id!==null&&(c=!0,s=!0,l.removeAllListeners(`line`),a.write(`${JSON.stringify({error:{code:n,message:e},id:i.id,jsonrpc:`2.0`})}\n`,()=>{u()}))}),i.once(`end`,u),i.once(`error`,u)})}const dt=new Set([`EAI_AGAIN`,`ECONNABORTED`,`ECONNREFUSED`,`ECONNRESET`,`EHOSTDOWN`,`EHOSTUNREACH`,`ENETDOWN`,`ENETUNREACH`,`ENOTFOUND`,`EPIPE`,`EPROTO`,`ETIMEDOUT`,`UND_ERR_BODY_TIMEOUT`,`UND_ERR_CONNECT_TIMEOUT`,`UND_ERR_HEADERS_TIMEOUT`,`UND_ERR_SOCKET`]),ft=new Set([`EAI_AGAIN`,`ECONNREFUSED`,`EHOSTDOWN`,`EHOSTUNREACH`,`ENETDOWN`,`ENETUNREACH`,`ENOTFOUND`,`UND_ERR_CONNECT_TIMEOUT`]),pt=/\bfetch failed\b|socket hang up|other side closed|\bterminated\b|network (?:error|is unreachable)|econnrefused|econnreset|econnaborted|etimedout|enotfound|eai_again|enetunreach|ehostunreach|und_err|not connected|transport (?:is )?closed|connection closed/i,mt=/\bnot connected\b|transport (?:is )?closed/i,ht=/session (?:not found|expired|has expired|is invalid|invalid|mismatch|does not|no longer)|no valid session|unknown session|mcp-session-id/i,gt=/no valid session|unknown session|mcp-session-id|session not found/i;function $(e){return St(e,new WeakSet)}function _t(e){return Ct(e,new WeakSet)}function vt(e){if(e instanceof y)return!0;if(e&&typeof e==`object`){let t=e.status,n=e.code,r=e.message;if(t===401||n===401||r&&/\bunauthorized\b|\b(?:http|status)(?:\s+(?:status|code))?\s*[:=]?\s*401\b/i.test(String(r)))return!0}return!1}function yt(e){if(e instanceof _)return!1;let t=$(e);return t&&ft.has(t)||xt(e)?!0:mt.test(X(e))}function bt(e){if(e instanceof t||e instanceof r||Q(e)||vt(e))return!1;let n=$(e);if(n&&dt.has(n)||xt(e))return!0;let i=_t(e);if(i!==void 0&&i>=500)return!0;let a=X(e);return!!(a.length>0&&pt.test(a))}function xt(e){let t=X(e);if(e instanceof _)return gt.test(t);let n=_t(e);return n===404||n===400&&ht.test(t)?!0:ht.test(t)}function St(e,t){if(typeof e!=`object`||!e||t.has(e))return;t.add(e);let n=e.code;if(typeof n==`string`&&/^[A-Z][A-Z0-9_]*$/.test(n))return n;for(let n of[`cause`,`response`,`data`,`body`]){let r=St(e[n],t);if(r)return r}}function Ct(e,t){if(typeof e!=`object`||!e||t.has(e))return;t.add(e);let n=e instanceof _?[`status`,`statusCode`]:[`status`,`statusCode`,`code`];for(let t of n){let n=e[t];if(typeof n==`number`&&n>=100&&n<=599)return n}for(let n of[`cause`,`response`,`data`,`body`]){let r=Ct(e[n],t);if(r!==void 0)return r}}const wt=e=>new Promise(t=>setTimeout(t,e));async function Tt(e,t,n={}){let r=n.isRetryable??bt,i=n.sleep??wt,a=n.now??Date.now,o=a(),s=0;for(;;)try{return await e()}catch(e){if(s+=1,s>t.maxRetries||!r(e))throw e;let c=Et(s,t);if(t.maxElapsedMs>0){let n=t.maxElapsedMs-(a()-o);if(n<=0)throw e;c=Math.min(c,n)}n.onRetry?.({attempt:s,delayMs:c,error:e}),await i(c)}}function Et(e,t){let n=Math.min(t.initialDelayMs*2**(e-1),t.maxDelayMs),r=n*.2*(Math.random()*2-1);return Math.max(0,Math.round(n+r))}function Dt(e){let t=e.now??Date.now,n=e.initial,r=0,i=-1/0,a=null,o=!1,s=!1,c=[],l=async()=>{g.info(`Upstream connection lost mid-session; reconnecting`,{eventType:`mcp_upstream_reconnect_attempt`}),s&&g.warn(`Reconnecting with resource subscriptions active; they will not survive the new session`,{eventType:`mcp_upstream_reconnect_subscriptions_dropped`});try{let t=await e.reconnect();if(o)return await Promise.resolve().then(()=>t.close()).catch(()=>{}),!1;for(let e of c)t.setNotificationHandler(...e);let i=n;return n=t,r+=1,Promise.resolve().then(()=>i.close()).catch(()=>{}),g.info(`Upstream reconnected`,{eventType:`mcp_upstream_reconnect_succeeded`}),!0}catch(e){return g.warn(`Upstream reconnect failed`,{errno:$(e),error:e instanceof Error?e.message:String(e),eventType:`mcp_upstream_reconnect_failed`}),!1}},u=n=>r>n?Promise.resolve(!0):a||(t()-i<e.cooldownMs?Promise.resolve(!1):(i=t(),a=l().finally(()=>{a=null}),a)),d=async(e,t)=>{let i=r;try{return await t(n)}catch(a){if(o||!(r>i)&&!bt(a))throw a;if(await u(i)&&(e||yt(a)))return await t(n);throw a}};return{callTool:(...e)=>d(!1,t=>t.callTool(...e)),close:(...e)=>(o=!0,n.close(...e)),complete:(...e)=>d(!0,t=>t.complete(...e)),getPrompt:(...e)=>d(!0,t=>t.getPrompt(...e)),listPrompts:(...e)=>d(!0,t=>t.listPrompts(...e)),listResources:(...e)=>d(!0,t=>t.listResources(...e)),listResourceTemplates:(...e)=>d(!0,t=>t.listResourceTemplates(...e)),listTools:(...e)=>d(!0,t=>t.listTools(...e)),notification:(...e)=>d(!1,t=>t.notification(...e)),readResource:(...e)=>d(!0,t=>t.readResource(...e)),setNotificationHandler:(...e)=>(c.push(e),n.setNotificationHandler(...e)),subscribeResource:(...e)=>(s=!0,d(!0,t=>t.subscribeResource(...e))),unsubscribeResource:(...e)=>d(!0,t=>t.unsubscribeResource(...e))}}var Ot=class extends ke{buffer=``;droppedLinesLogged=0;constructor(){super({objectMode:!1})}_flush(e){this.buffer.trim().startsWith(`{`)?e(null,Buffer.from(this.buffer)):(this.buffer.trim().length>0&&this.logDroppedLine(this.buffer),e(null,null))}_transform(e,t,n){this.buffer+=e.toString();let r=this.buffer.split(`
2
- `);this.buffer=r.pop()||``;let i=[];for(let e of r)e.trim().startsWith(`{`)?i.push(e):e.trim().length>0&&this.logDroppedLine(e);if(i.length>0){let e=`${i.join(`
3
- `)}\n`;n(null,Buffer.from(e))}else n(null,null)}logDroppedLine(e){if(!(this.droppedLinesLogged>50)){if(this.droppedLinesLogged===50){this.droppedLinesLogged+=1,g.info(`Suppressing further non-JSON stdout lines`,{eventType:`mcp_server_stdout_dropped_suppressed`,loggedSoFar:50});return}this.droppedLinesLogged+=1,g.info(`MCP server stdout (non-JSON, dropped)`,{eventType:`mcp_server_stdout_dropped`,line:e.length>1024?`${e.slice(0,1024)}…`:e})}}},kt=class{onclose;onerror;onmessage;get pid(){return this._process?.pid??null}get spawnedServerPid(){return this._spawnedPid}get spawnedServerStartedAt(){return this._spawnedAt}get stderr(){return this._stderrStream?this._stderrStream:this._process?.stderr??null}_abortController=new AbortController;_process;_readBuffer=new v;_serverParams;_spawnedAt;_spawnedPid;_stderrStream=null;onEvent;constructor(e){this._serverParams=e,(e.stderr===`pipe`||e.stderr===`overlapped`)&&(this._stderrStream=new E),this.onEvent=e.onEvent}async close(){if(this.onEvent?.({type:`close`}),this._process?.pid)try{if(process.platform===`win32`){let e=we(`taskkill`,[`/PID`,String(this._process.pid),`/T`,`/F`],{stdio:`ignore`});if(e.error)throw e.error;if(e.status!==0)throw Error(`taskkill exited with status ${e.status}`)}else process.kill(-this._process.pid,`SIGTERM`)}catch(e){g.debug(`Process tree cleanup failed (process may already be dead)`,{error:e.message,pid:this._process.pid})}this._abortController.abort(),this._process=void 0,this._readBuffer.clear()}send(e){return new Promise(t=>{if(!this._process?.stdin)throw Error(`Not connected`);let n=S(e);this._process.stdin.write(n)?t():this._process.stdin.once(`drain`,t)})}async start(){if(this._process)throw Error(`StdioClientTransport already started! If using Client class, note that connect() calls start() automatically.`);return new Promise((e,t)=>{let n=this._serverParams.shell??!1,r=n&&process.platform===`win32`,i=r?At(this._serverParams.command):this._serverParams.command,a=r?(this._serverParams.args??[]).map(At):this._serverParams.args??[];this._process=Ce(i,a,{cwd:this._serverParams.cwd,detached:process.platform!==`win32`,env:this._serverParams.env,shell:n,signal:this._abortController.signal,stdio:[`pipe`,`pipe`,this._serverParams.stderr??`inherit`]}),this._process.on(`error`,e=>{if(e.name===`AbortError`){this.onclose?.();return}g.error(`Process spawn error`,{args:this._serverParams.args?f(this._serverParams.args):void 0,command:this._serverParams.command,cwd:this._serverParams.cwd,error:e.message,errorCode:e.code,errorErrno:e.errno,errorSyscall:e.syscall,operation:`spawn`,shell:this._serverParams.shell,transportType:`stdio`}),t(e),this.onerror?.(e)});let o,s;this._process.on(`spawn`,()=>{o=Date.now(),s=this._process?.pid,this._spawnedAt=o,this._spawnedPid=s,g.info(`MCP server process spawned`,{argCount:this._serverParams.args?.length,command:this._serverParams.command,eventType:`mcp_server_process_spawned`,pid:s}),e()}),this._process.on(`close`,(e,t)=>{let n=o===void 0?void 0:Date.now()-o;g[e===0&&t===null?`info`:`warn`](`MCP server process closed`,{argCount:this._serverParams.args?.length,code:e,command:this._serverParams.command,eventType:`mcp_server_process_closed`,pid:s,signal:t,uptimeMs:n}),this.onEvent?.({type:`close`}),this._process=void 0,this.onclose?.()}),this._process.stdin?.on(`error`,e=>{g.error(`Stdin error`,{command:this._serverParams.command,error:e.message,operation:`write`,pid:this._process?.pid,transportType:`stdio`}),this.onEvent?.({error:e,type:`error`}),this.onerror?.(e)});let c=new Ot;this._process.stdout?.pipe(c),c.on(`data`,e=>{this.onEvent?.({chunk:e.toString(),type:`data`}),this._readBuffer.append(e),this.processReadBuffer()}),c.on(`error`,e=>{g.error(`JSON filter error`,{command:this._serverParams.command,error:e.message,operation:`parse`,pid:this._process?.pid,transportType:`stdio`}),this.onEvent?.({error:e,type:`error`}),this.onerror?.(e)}),this._stderrStream&&this._process.stderr&&this._process.stderr.pipe(this._stderrStream)})}processReadBuffer(){for(;;)try{let e=this._readBuffer.readMessage();if(e===null)break;this.onEvent?.({message:e,type:`message`}),this.onmessage?.(e)}catch(e){let t=`unknown`;try{let e=this._readBuffer.readMessage();e&&(t=typeof e)}catch{}g.error(`Message processing error`,{command:this._serverParams.command,error:e.message,messageType:t,operation:`process`,pid:this._process?.pid,transportType:`stdio`}),this.onEvent?.({error:e,type:`error`}),this.onerror?.(e)}}};function At(e){return e.length===0||!/[\s"&|<>^()]/.test(e)?e:`"${e.replace(/"/g,`""`).replace(/(\\+)$/,`$1$1`)}"`}const jt=[`$`,"`",`;`,`|`,`&`,`>`,`<`,`(`,`)`,`{`,`}`,`'`,`"`,`\\`,`!`,`*`,`?`,`~`,`#`],Mt=`[a-z0-9]+`,Nt=`${Mt}(?:(?:[._]|__|-+)${Mt})*`,Pt=`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`,Ft=`(?:${`(?:${`${Pt}(?:\\.${Pt})*`}|\\[[a-fA-F0-9:]+\\])(?::[0-9]+)?`}/)?${Nt}(?:/${Nt})*`,It=RegExp(`^${Ft}(?::[A-Za-z0-9_][A-Za-z0-9_.-]{0,127})?(?:@[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[0-9a-fA-F]{32,})?$`);function Lt(e){return typeof e!=`string`||e.trim()===``?{reason:`empty image reference`,valid:!1}:e.length>512?{reason:`image reference longer than 512 characters`,valid:!1}:It.test(e)?{valid:!0}:{reason:Rt(e),valid:!1}}function Rt(e){if(/[\u0000-\u001f\u007f]/.test(e))return`contains a control character`;if(/\s/.test(e))return`contains whitespace`;let t=jt.find(t=>e.includes(t));return t?`contains the shell metacharacter ${t}`:e.startsWith(`-`)?`starts with '-' and would be parsed as a runtime option`:`does not match the OCI image-reference grammar`}function zt(e){let t=e.toLowerCase().split(/[/\\]/).pop()||``;return t===`docker`||t===`docker.exe`?`docker`:t===`podman`||t===`podman.exe`?`podman`:t===`nerdctl`||t===`nerdctl.exe`?`nerdctl`:t===`finch`||t===`finch.exe`?`finch`:`unknown`}function Bt(e){let t=e.indexOf(`run`);if(t===-1)return;let n=e.slice(t+1),r=new Set(`--add-host.--annotation.--arch.--attach.--blkio-weight.--blkio-weight-device.--cap-add.--cap-drop.--cgroup-parent.--cgroupns.--cidfile.--cosign-key.--cpu-period.--cpu-quota.--cpu-rt-period.--cpu-rt-runtime.--cpu-shares.--cpus.--cpuset-cpus.--cpuset-mems.--decryption-key.--device.--device-cgroup-rule.--device-read-bps.--device-read-iops.--device-write-bps.--device-write-iops.--dns.--dns-option.--dns-search.--domainname.--entrypoint.--env.--env-file.--env-host.--expose.--gidmap.--gpus.--group-add.--health-cmd.--health-interval.--health-retries.--health-start-period.--health-timeout.--hostname.--image-volume.--ip.--ip6.--ipc.--isolation.--kernel-memory.--label.--label-file.--link.--link-local-ip.--log-driver.--log-opt.--mac-address.--memory.--memory-reservation.--memory-swap.--memory-swappiness.--mount.--name.--network.--network-alias.--oom-kill-disable.--oom-score-adj.--os.--pid.--pidfile.--pids-limit.--platform.--pod.--privileged.--publish.--publish-all.--pull.--requires.--restart.--rootfs.--runtime.--secret.--security-opt.--shm-size.--stop-signal.--stop-timeout.--storage-opt.--subgidname.--subuidname.--sysctl.--systemd.--timeout.--tmpfs.--tz.--uidmap.--ulimit.--user.--userns.--uts.--variant.--volume.--volume-driver.--volumes-from.--workdir.-a.-c.-e.-h.-l.-m.-p.-P.-u.-v.-w`.split(`.`)),i=0;for(;i<n.length;){let e=n[i];if(e.startsWith(`-`)){if(e.includes(`=`)){i++;continue}if(r.has(e)){i+=2;continue}i++;continue}return e}}function Vt(e,t){let n=zt(e);if(n===`unknown`)return{imageName:``,isContainerMCP:!1,runtime:`unknown`};if(!t||!t.includes(`run`))return{imageName:``,isContainerMCP:!1,runtime:n};let r=Bt(t);return r?{imageName:r,isContainerMCP:!0,runtime:n}:(g.debug(`Container command detected but could not extract image name`,{args:t,command:e,runtime:n}),{imageName:``,isContainerMCP:!0,runtime:n})}function Ht(e,t){let n=t===`unknown`?`docker`:t,r=Lt(e);if(!r.valid)return g.warn(`Rejected container image reference; skipping digest lookup`,{eventType:`mcp_container_image_ref_rejected`,imageName:e,reason:r.reason,runtime:n}),[];let i;try{i=Se(n,[`image`,`inspect`,`--format`,`{{json .RepoDigests}}`,e],{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:5e3})}catch(t){return g.warn(`Container image digest lookup failed`,{error:t instanceof Error?t.message:String(t),eventType:`mcp_container_image_digest_lookup_failed`,imageName:e,runtime:n}),[]}let a=i.trim(),o;try{o=JSON.parse(a)}catch{return g.warn(`Could not parse RepoDigests JSON`,{eventType:`mcp_container_image_digest_lookup_failed`,imageName:e,result:a,runtime:n}),[]}if(!Array.isArray(o))return g.warn(`RepoDigests was not a JSON array`,{eventType:`mcp_container_image_digest_lookup_failed`,imageName:e,result:a,runtime:n}),[];let s=o,c=[];for(let e of s){if(typeof e!=`string`)continue;let t=e.match(/sha256:[a-f0-9]{64}/i);t&&c.push(t[0])}return c.length>0?(g.info(`Container image digests resolved`,{digests:c,eventType:`mcp_container_image_digests_resolved`,imageName:e,runtime:n}),c):(g.info(`No container image digests available (image may be locally built)`,{eventType:`mcp_container_image_digests_empty`,imageName:e,runtime:n}),[])}let Ut;const Wt=()=>({pid:Ut?.spawnedServerPid,startedAtMs:Ut?.spawnedServerStartedAt});w.inspect.defaultOptions.depth=8,`EventSource`in global||(global.EventSource=Y);const Gt=async e=>{g.error(e.logMessage,e.meta),await new Promise(t=>{process.stderr.write(`${e.stderrLine}\n`,()=>t())}),e.respondToClient&&await ut(e.reason);let t=De(()=>{},50);try{await re(2e3)}catch{}finally{Ee(t)}process.exit(e.exitCode)},Kt=e=>{let t=e.header?`HTTP header "${e.header}"`:`the bearer token`,n=`Onyx MCP gateway: required auth env var "${e.envVar}" for ${t} is empty or unset. Export the source value your agent config references (e.g. the {env:...} / \${...} token) in the launch environment.`;return Gt({exitCode:78,logMessage:e.logMessage,meta:{envVar:e.envVar,eventType:e.eventType,...e.header?{header:e.header}:{}},reason:n,respondToClient:e.respondToClient,stderrLine:`[mcp-gateway] FATAL: ${n}`})},qt=e=>{let t=X(e.error),n=st(e.subject),i=t=>lt(t,e.url),a=i(t),o=Object.fromEntries(Object.entries(e.extra??{}).map(([e,t])=>[e,typeof t==`string`?i(st(t)):t]));throw g.error(e.logMessage,{eventType:`mcp_protocol_era_mismatch`,originalError:a,supportedEra:`${Z[0]}..${Z[Z.length-1]}`,...o}),new r(i(tt(n,e.error)),e.url,{originalError:a,...o})},Jt=async()=>{oe(g),ae(g);let e=await ue(se(process.argv)).scriptName(`mcp-gateway`).command(`stdio [command] [args...]`,`Run a local command with stdio transport (default)`,e=>e.positional(`command`,{describe:`The command to run`,type:`string`}).positional(`args`,{array:!0,describe:`The arguments to pass to the command`,type:`string`})).command(`remote`,`Connect to a remote MCP server`,e=>e.options({"bearer-token-env":{describe:`Environment variable name containing a bearer token for remote authentication`,type:`string`},"env-http-headers":{describe:`HTTP headers resolved from environment variables (format: HeaderName:ENV_VAR_NAME)`,string:!0,type:`array`},headers:{deprecated:`Use --env-http-headers with env var names instead. --headers exposes values in process listings.`,describe:`Legacy: headers with literal values (format: key:value)`,string:!0,type:`array`},"remote-transport":{choices:[`sse`,`stream`],deprecated:`Transport is now auto-detected per MCP spec. This option is ignored.`,describe:`(Deprecated) The transport type - now auto-detected`,type:`string`},url:{demandOption:!0,describe:`The URL of the remote MCP server`,type:`string`}})).command(`$0 [command] [args...]`,`Run a command with MCP arguments (backward compatible)`,e=>e.positional(`command`,{describe:`The command to run`,type:`string`}).positional(`args`,{array:!0,describe:`The arguments to pass to the command`,type:`string`})).env(`MCP_GATEWAY`).parserConfiguration({"populate--":!0,"unknown-options-as-args":!0}).options({"access-control-url":{describe:`URL of the access control service (overrides MCP_GATEWAY_ACCESS_CONTROL_URL)`,type:`string`},debug:{default:!1,describe:`Enable debug logging`,type:`boolean`},env:{describe:`Environment variables to pass to the command (format: KEY=value)`,string:!0,type:`array`},gracefulShutdownTimeout:{default:5e3,describe:`The timeout (in milliseconds) for graceful shutdown`,type:`number`},"oauth-providers-url":{describe:`URL of the OAuth providers config endpoint (overrides MCP_GATEWAY_OAUTH_PROVIDERS_URL)`,type:`string`},port:{describe:`Run as HTTP server on the specified port instead of stdio`,type:`number`},"scanner-api-key":{describe:`API key for scanner authentication (overrides MCP_GATEWAY_SCANNER_API_KEY)`,type:`string`},"scanner-fail-open":{describe:`Allow requests when scanner is unavailable (overrides MCP_GATEWAY_SCANNER_FAIL_OPEN)`,type:`boolean`},"scanner-timeout-ms":{describe:`Scanner request timeout in milliseconds (overrides MCP_GATEWAY_SCANNER_TIMEOUT_MS)`,type:`number`},"scanner-url":{describe:`URL of the scanner/evaluator service (overrides MCP_GATEWAY_SCANNER_URL)`,type:`string`},shell:{default:process.platform===`win32`,describe:`Spawn the server via the user's shell (defaults to true on Windows)`,type:`boolean`}}).help().parseAsync();await de(m.oauthProviders);let s,h=!1,_,v,y,b,S={},he={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(he[e.trim()]=n.join(`=`).trim())}let ge=e=>{if(e.includes("${")){let t,n=e.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g,(e,n)=>process.env[n]||(t=n,``));return t?{missingVar:t,resolved:``}:{resolved:n}}let t=process.env[e];return t?{resolved:t}:{missingVar:e,resolved:``}};if(e.headers)for(let t of e.headers){let[e,...n]=t.split(`:`);e&&n.length>0&&(S[e.trim()]=n.join(`:`).trim())}if(e.bearerTokenEnv){let t=e.bearerTokenEnv,{missingVar:n,resolved:r}=ge(t);n&&await Kt({envVar:n,eventType:`mcp_auth_bearer_env_missing`,logMessage:`Bearer token env var specified but not set`,respondToClient:!e.port}),S.Authorization=`Bearer ${r}`,g.info(`Bearer token loaded from environment variable`,{authType:`bearer_token`,envVar:t,eventType:`mcp_auth_bearer_env`,remoteUrl:e.url})}if(e.envHttpHeaders)for(let t of e.envHttpHeaders){let[n,...r]=t.split(`:`),i=r.join(`:`).trim();if(n&&i){let t=n.trim(),{missingVar:r,resolved:a}=ge(i);r&&await Kt({envVar:r,eventType:`mcp_auth_env_header_missing`,header:t,logMessage:`Env var for HTTP header not set`,respondToClient:!e.port}),S[t]=a,g.info(`HTTP header loaded from environment`,{eventType:`mcp_auth_env_header`,header:t,remoteUrl:e.url})}}let _e=ne(S);if(_e&&g.setTraceId(_e),S.Authorization){let t=S.Authorization.startsWith(`Bearer `)?`bearer_token`:S.Authorization.startsWith(`Basic `)?`basic`:`api_key`;g.info(`Authorization header provided`,{authType:t,eventType:`mcp_auth_header_provided`,remoteUrl:e.url})}let ve={...m.scanner.headers};g.debug(`Initializing traffic scanner`,{failOpen:m.scanner.failOpen,hasApiKey:!!m.scanner.apiKey,scannerEnabled:m.scanner.enabled,scannerUrl:m.scanner.url,timeoutMs:m.scanner.timeoutMs});let ye=async a=>{let o=!e.port&&!h,c=y?(()=>{try{return new URL(y).origin}catch{return`[invalid remote URL]`}})():void 0,l=e=>y&&c?e.split(y).join(c):e;if(a instanceof t){let e=a.message||`This MCP server has been blocked by your organization's Onyx access-control policy. Contact your administrator if you believe this is an error.`,t=[``,`❌ ACCESS DENIED`,`━`.repeat(60),e,`Please contact your administrator if you believe this is an error.`,``].join(`
4
- `);return Gt({exitCode:1,logMessage:`MCP server blocked by access control policy`,meta:{error:a.message,eventType:`mcp_access_control_block`,reason:a.reason},reason:e,respondToClient:o,stderrLine:t})}let u=l(a instanceof n?`Onyx MCP gateway: configuration error — ${a.message}`:a instanceof r?`Onyx MCP gateway: unsupported MCP protocol era — ${a.message}`:a instanceof i?`Onyx MCP gateway: cannot reach the upstream MCP server${c?` at ${c}`:``} — ${a.message}`:`Onyx MCP gateway: failed to start — ${a instanceof Error?a.message:String(a)}`);return Gt({exitCode:1,logMessage:`MCP server failed to start`,meta:{args:v?f(v):void 0,command:_,errno:$(a),error:l(`Could not start the proxy: ${a}`),eventType:`mcp_server_start_failed`,proxyType:s,remoteUrl:c,transport:b},reason:u,respondToClient:o,stderrLine:`[mcp-gateway] FATAL: ${u}`})};if(e._[0]===`remote`){s=`remote`,e[`remote-transport`]&&g.warn(`The --remote-transport option is deprecated and will be ignored. Transport is now auto-detected per MCP spec (Streamable HTTP with SSE fallback).`,{providedTransport:e[`remote-transport`]});let t=e.url;t||await ye(new n(`Remote URL is required for remote proxy type`,`url`)),y=x(t),y!==t&&g.debug(`Normalized remote URL`,{normalizedUrl:y,originalUrl:t})}else{if(s=`stdio`,e[`--`]&&e[`--`].length>0){let t=e[`--`];_=t[0],v=t.slice(1).map(String)}else _=e.command,v=(e.args||[]).map(String);_||await ye(new n(`No command specified for stdio proxy`,`command`))}let C;s===`stdio`&&_&&(C=Vt(_,v),C.isContainerMCP&&g.info(`Container MCP detected`,{imageName:C.imageName,runtime:C.runtime}));let be,xe,Se=async()=>{xe??=c(),g.setSessionData({...await xe,proxyType:s})},Ce=async()=>{be!==void 0||!C?.isContainerMCP||!C.imageName||(await Se(),be=Ht(C.imageName,C.runtime))},we=()=>s===`stdio`?{args:v,command:_,dockerImageDigests:be,dockerImageName:C?.imageName,proxyType:s}:{proxyType:s,url:y},Ee;if(m.accessControl.url&&m.scanner.apiKey){let e=we();await Se();let t=await xe,n=e.proxyType===`stdio`?{...t,proxyType:`stdio`,stdioCliArgs:{...e,args:f(e.args)}}:{...t,proxyType:`remote`,remoteCliArgs:e};Ee=new Ue({apiKey:m.scanner.apiKey,headers:m.accessControl.headers,sessionData:n,timeoutMs:m.accessControl.timeoutMs,url:m.accessControl.url})}let De=s===`remote`?y:_,w=new He({client:Ee,enabled:m.accessControl.enabled,serverName:De}),T=new We({storageDir:m.oauthDir}),E=()=>new ie({name:`mcp-gateway`,version:m.appVersion},{capabilities:{},versionNegotiation:p()}),ke=async(n,{allowInteractiveAuth:a=!0}={})=>{if(!await w.isAllowed()){let e=w.getBlockReason();throw g.warn(`MCP server blocked by access control`,{proxyType:s,reason:e}),new t(e,`policy_block`)}if(g.info(`MCP server allowed by access control`),await Ce(),s===`stdio`){let t=await ce(process.env);if(t.proxyHost!==void 0){let e=t.reachability===`unreachable`;g.info(e?`Operator proxy is unreachable; withholding it from the wrapped server so it goes direct instead of hanging`:`Handing the operator proxy to the wrapped server`,{event:`proxy_child_restore`,op:`spawn`,outcome:e?`withheld`:`restored`,platform:process.platform,proxy_host:t.proxyHost,reachability:t.reachability})}let r={...le(process.env,t.reachability),...he},a=new kt({args:v,command:_,env:r,onEvent:t=>{e.debug&&g.debug(`Transport event`,{event:t})},shell:e.shell,stderr:`pipe`});Ut=a;let o=1024;o*8;let c=e=>e.length>o?`${e.slice(0,o)}…`:e,l=``,u=[],d=e=>{let t=c(e);u.push(t),u.length>100&&u.shift(),g.info(`MCP server stderr`,{command:_,eventType:`mcp_server_stderr`,line:t})},f=()=>{l.length!==0&&(d(l),l=``)},ee=new Te(`utf8`),te=!1,p=()=>{if(te)return;te=!0;let e=ee.end();e&&(l+=e),f()};a.stderr?.on(`data`,e=>{process.stderr.write(e),l+=ee.write(e);let t=l.split(`
5
- `);l=t.pop()??``;for(let e of t){if(e.length===0)continue;d(e)}l.length>8192&&f()}),a.stderr?.once(`end`,p),a.stderr?.once(`close`,p);try{return await n.connect(a),n}catch(e){throw p(),g.warn(`Failed original server access`,{command:_,errno:$(e),error:e instanceof Error?e.message:String(e),eventType:`mcp_server_access_failed`,proxyType:s,stderrTail:u.slice(-20)}),await a.close().catch(()=>{}),Q(e)&&qt({error:e,extra:{command:_},logMessage:`Spawned MCP server speaks a different protocol era; cannot negotiate a session`,subject:_??`the spawned MCP server`}),new i(`Failed to connect to stdio process: ${e}`,void 0,`stdio`,{argCount:v?.length,command:_},e)}}else if(s===`remote`){let e=y,t=()=>{let e={...S};return Object.keys(e).length>0?{headers:e}:void 0},n=async()=>{let t=await me(e,{credentialStore:T});return g.info(`Authentication performed`,{authType:`oauth`,eventType:`mcp_auth_performed`,fromCache:t.fromCache,remoteUrl:e}),t.tokens.access_token},o;try{let r=await T.load(e),i=r&&T.hasValidAccessToken(r)?r.tokens?.access_token:void 0,s=Ke(e,T,i),c=Ge(s),l=!1;try{let n=await fe(E,e,t(),c);o=n.client,b=n.transportType,g.info(`Connected to remote server`,{hasAuth:!!i,transport:b})}catch(r){if(Q(r)&&qt({error:r,extra:{remoteUrl:e},logMessage:`Upstream speaks a different MCP protocol era; cannot negotiate a session`,subject:e,url:e}),vt(r)){if(l)throw r;if(s.getCurrentBearer()??i?(g.info(`Cached + refresh both rejected; falling back to full OAuth flow`),await T.update(e,{tokensObtainedAt:void 0})):g.info(`Server requires OAuth, starting authentication flow...`),!a)throw g.info(`Skipping interactive OAuth on reconnect; surfacing 401`,{eventType:`mcp_reconnect_skip_interactive_auth`}),r;let u=await n();s.setBearer(u),l=!0;let d=await fe(E,e,t(),c);o=d.client,b=d.transportType,g.info(`Connected to remote server with OAuth`,{transport:b})}else if(!l&&!(s.getCurrentBearer()??i)&&!new Headers(S).has(`Authorization`)){let i=!1,u;try{let{authMetadata:t}=await pe(new URL(e),{logger:g});i=!!t}catch(e){u=e instanceof Error?e.message:String(e)}if(!i)throw g.warn(`Non-401 failure and no discoverable OAuth metadata; propagating original error`,{discoveryError:u,eventType:`mcp_non401_no_oauth_discovery`,originalError:r instanceof Error?r.message:String(r),remoteUrl:e}),r;if(g.info(`Cold-start non-401 but server advertises OAuth; attempting OAuth flow`,{originalError:r instanceof Error?r.message:String(r)}),!a)throw g.info(`Skipping interactive OAuth on reconnect; surfacing error`,{eventType:`mcp_reconnect_skip_interactive_auth`}),r;let d=await n();s.setBearer(d),l=!0;let f=await fe(E,e,t(),c);o=f.client,b=f.transportType,g.info(`Connected to remote server with OAuth (recovered from non-401)`,{transport:b})}else throw r}return o}catch(t){throw g.warn(`Failed original server access`,{errno:$(t),error:t instanceof Error?t.message:String(t),eventType:`mcp_server_access_failed`,proxyType:s,remoteUrl:e}),t instanceof i||t instanceof r?t:(Q(t)&&qt({error:t,extra:{remoteUrl:e},logMessage:`Upstream speaks a different MCP protocol era; cannot negotiate a session`,subject:e,url:e}),new i(`Failed to connect to remote server: ${t instanceof Error?t.message:String(t)}`,e,b,{headerCount:Object.keys(S).length},t))}}return n},D=()=>Tt(()=>ke(E()),m.upstream.connect,{onRetry:({attempt:e,delayMs:t,error:n})=>{g.warn(`Upstream connect failed; retrying`,{attempt:e,delayMs:t,errno:$(n),error:n instanceof Error?n.message:String(n),eventType:`mcp_upstream_connect_retry`,proxyType:s})}}),Ae=s===`remote`?m.upstream.reconnect.enabled:m.upstream.reconnect.enabledForStdio,O=e=>Ae?Dt({cooldownMs:m.upstream.reconnect.cooldownMs,initial:e,reconnect:()=>ke(E(),{allowInteractiveAuth:!1})}):e,k,A=()=>(k??=l({cliArgs:we(),scanApiKey:m.scanner.apiKey,scanEnabled:m.scanner.enabled,scanFailOpen:m.scanner.failOpen,scanHeaders:ve,scanTimeoutMs:m.scanner.timeoutMs,scanUrl:m.scanner.url||``,spawnedServerInfoProvider:Wt}),k),j=e=>{g.info(`Upstream protocol era negotiated`,{era:e.getProtocolEra(),eventType:`mcp_upstream_era_negotiated`,negotiation:m.supportNewMcpProtocol?`auto`:`legacy`,protocolVersion:e.getNegotiatedProtocolVersion()})},M=async()=>{if(e.port){let t,n=await te({createServer:async()=>{let e=await D();j(e),await A();let n=e.getServerVersion(),r=e.getServerCapabilities();t=O(e);let i=new a(n,{capabilities:r});return d({authorizer:w,client:t,server:i,serverCapabilities:r}),i},onClose:async e=>{t&&await t.close(),await e.close()},port:e.port});return g.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`http`,port:e.port,proxyType:s}),s===`stdio`?g.info(`MCP server configuration`,{args:f(v??[]).join(` `),command:_,eventType:`mcp_server_config`,proxyType:s}):g.info(`MCP server configuration`,{eventType:`mcp_server_config`,proxyType:s,remoteUrl:y}),{close:()=>n.close()}}let t=await D();j(t);let n=t.getServerVersion(),r=t.getServerCapabilities(),i=O(t),c=new a(n,{capabilities:r});d({authorizer:w,client:i,server:c,serverCapabilities:r}),await A();let l=()=>{g.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`stdio`,proxyType:s}),g.info(`MCP server configuration`,{capabilities:Object.keys(r||{}),eventType:`mcp_server_config`,proxyType:s,serverName:n?.name,serverVersion:n?.version,...s===`stdio`?{args:f(v??[]).join(` `),command:_}:{remoteUrl:y,transport:b}})};if(m.supportNewMcpProtocol){let e=ee(()=>c,{legacy:`serve`});return h=!0,l(),{close:async()=>{await e.close(),await i.close()}}}let u=new o;return await c.connect(u),h=!0,l(),{close:()=>i.close()}},N=({server:e,timeout:t})=>{let n=!1,r=async r=>{if(!n){n=!0,g.info(`MCP gateway stopping`,{eventType:`mcp_gateway_stopping`,signal:r});try{await e.close(),u(),await re(2e3),process.exit(0)}catch(e){let n=`Error during shutdown: ${e}`;g.error(`Error during shutdown`,{error:n,eventType:`mcp_gateway_stopped`,shutdownTimeout:t}),await re(2e3),process.exit(1)}}},i=e=>async()=>{Oe(()=>{g.error(`Graceful shutdown timeout exceeded, forcing exit`),process.exit(1)},t).unref(),await r(e)};return process.once(`SIGTERM`,i(`SIGTERM`)),process.once(`SIGINT`,i(`SIGINT`)),process.stdin.once(`end`,i(`stdin-end`)),()=>e.close()};g.info(`MCP gateway starting`,{command:_,eventType:`mcp_gateway_starting`,proxyType:s,transport:s===`remote`?`auto-detect`:`stdio`,url:y});try{let t=await M();N({server:t,timeout:e.gracefulShutdownTimeout})}catch(e){await ye(e)}};export{Jt as main};
6
- //# sourceMappingURL=main-CCeZBO84.js.map