@onyxsecurity/mcp-gateway 1.0.59 → 1.0.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/mcp-gateway.js +1 -1
- package/dist/bin/mcp-gateway.js.map +1 -1
- package/dist/cli-BDQGMkyL.js +3 -0
- package/dist/cli-BDQGMkyL.js.map +1 -0
- package/dist/{helpers-Cwd-UJrA.js → helpers-DJo6DVLx.js} +1 -1
- package/dist/{helpers-Cwd-UJrA.js.map → helpers-DJo6DVLx.js.map} +1 -1
- package/dist/index.d.ts +18 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-f8nUbpFM.js +142 -0
- package/dist/main-f8nUbpFM.js.map +1 -0
- package/dist/{normalizeUrl-nUb2udZz.js → normalizeUrl-CYShKr9E.js} +9 -16
- package/dist/normalizeUrl-CYShKr9E.js.map +1 -0
- package/dist/pkce-CAz04Nh9.js +1 -0
- package/dist/{pkce-ANRIC6ce.js → pkce-CbP4rU3z.js} +1 -1
- package/dist/{pkce-ANRIC6ce.js.map → pkce-CbP4rU3z.js.map} +1 -1
- package/dist/streamableHttp-DM0LA7pR.js +9 -0
- package/dist/streamableHttp-DM0LA7pR.js.map +1 -0
- package/dist/transportDetection-DquHtdNu.js +2 -0
- package/dist/transportDetection-DquHtdNu.js.map +1 -0
- package/package.json +1 -1
- package/dist/main-Bn1n-fs1.js +0 -141
- package/dist/main-Bn1n-fs1.js.map +0 -1
- package/dist/normalizeUrl-nUb2udZz.js.map +0 -1
- package/dist/pkce-dymop6yt.js +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { Transport } from "@modelcontextprotocol/sdk/shared/transport.js";
|
|
|
15
15
|
* where a persistent storage solution would be more appropriate.
|
|
16
16
|
*/
|
|
17
17
|
declare class InMemoryEventStore implements EventStore {
|
|
18
|
+
private counter;
|
|
18
19
|
private events;
|
|
19
20
|
/**
|
|
20
21
|
* Replays events that occurred after a specific event ID
|
|
@@ -31,11 +32,26 @@ declare class InMemoryEventStore implements EventStore {
|
|
|
31
32
|
*/
|
|
32
33
|
storeEvent(streamId: string, message: JSONRPCMessage): Promise<string>;
|
|
33
34
|
/**
|
|
34
|
-
* Generates a unique event ID for a given stream ID
|
|
35
|
+
* Generates a unique event ID for a given stream ID.
|
|
36
|
+
*
|
|
37
|
+
* Includes a per-instance monotonic counter so the chronological ordering
|
|
38
|
+
* established by `localeCompare` in `replayEventsAfter` holds even when
|
|
39
|
+
* two events are stored within the same millisecond — `Date.now()` alone
|
|
40
|
+
* is not enough resolution under load (was the source of intermittent
|
|
41
|
+
* test failures under busy CI). Counter is zero-padded so lexicographic
|
|
42
|
+
* comparison of the eventId string yields numeric ordering.
|
|
35
43
|
*/
|
|
36
44
|
private generateEventId;
|
|
37
45
|
/**
|
|
38
|
-
* Extracts the stream ID from an event ID
|
|
46
|
+
* Extracts the stream ID from an event ID.
|
|
47
|
+
*
|
|
48
|
+
* Event ID format from generateEventId: `{streamId}_{timestamp}_{seq}_{random}`.
|
|
49
|
+
* The streamId itself can contain underscores (consumers pass arbitrary
|
|
50
|
+
* strings), so a simple `split("_")[0]` returns only the first segment of
|
|
51
|
+
* a multi-part stream id and replayEventsAfter then silently skips that
|
|
52
|
+
* stream's events. Reconstruct by dropping the LAST 3 segments instead —
|
|
53
|
+
* those are always our own (timestamp, seq, random) appended in
|
|
54
|
+
* generateEventId.
|
|
39
55
|
*/
|
|
40
56
|
private getStreamIdFromEventId;
|
|
41
57
|
}
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{Client as e,InMemoryEventStore as t,
|
|
1
|
+
import{Client as e,InMemoryEventStore as t,Server as n,StdioServerTransport as r,normalizeUrl as i,proxyServer as a,startHTTPServer as o}from"./normalizeUrl-CYShKr9E.js";import{SSEClientTransport as s,StreamableHTTPClientTransport as c,config as l}from"./streamableHttp-DM0LA7pR.js";let u=function(e){return e.HTTPStream=`HTTPStream`,e.SSE=`SSE`,e}({});const d=async({initStdioServer:t,initStreamClient:o,serverType:d,transportOptions:f={},url:p})=>{let m=i(p),h;switch(d){case u.SSE:h=new s(new URL(m),f);break;default:h=new c(new URL(m),f)}let g=o?await o():new e({name:`mcp-gateway`,version:l.appVersion},{capabilities:{}});await g.connect(h);let _=g.getServerVersion(),v=g.getServerCapabilities(),y=t?await t():new n(_,{capabilities:v}),b=new r;return await y.connect(b),await a({authorizer:void 0,client:g,server:y,serverCapabilities:v}),y},f=(e,t)=>{let n=e.close.bind(e),r=e.onclose?.bind(e),i=e.onerror?.bind(e),a=e.onmessage?.bind(e),o=e.send.bind(e),s=e.start.bind(e);return e.close=async()=>(t({type:`close`}),n?.()),e.onclose=async()=>(t({type:`onclose`}),r?.()),e.onerror=async e=>(t({error:e,type:`onerror`}),i?.(e)),e.onmessage=async e=>(t({message:e,type:`onmessage`}),a?.(e)),e.send=async e=>(t({message:e,type:`send`}),o?.(e)),e.start=async()=>(t({type:`start`}),s?.()),e};export{t as InMemoryEventStore,u as ServerType,a as proxyServer,o as startHTTPServer,d as startStdioServer,f as tapTransport};
|
|
2
2
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["transport: SSEClientTransport | StreamableHTTPClientTransport"],"sources":["../src/startStdioServer.ts","../src/tapTransport.ts"],"sourcesContent":["import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n\tSSEClientTransport,\n\ttype SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport {\n\tStreamableHTTPClientTransport,\n\ttype StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { config } from \"./config/env.js\";\nimport { proxyServer } from \"./proxyServer.js\";\nimport { normalizeUrl } from \"./utils/normalizeUrl.js\";\n\nexport enum ServerType {\n\tHTTPStream = \"HTTPStream\",\n\tSSE = \"SSE\",\n}\n\nexport const startStdioServer = async ({\n\tinitStdioServer,\n\tinitStreamClient,\n\tserverType,\n\ttransportOptions = {},\n\turl,\n}: {\n\tinitStdioServer?: () => Promise<Server>;\n\tinitStreamClient?: () => Promise<Client>;\n\tserverType: ServerType;\n\ttransportOptions?:\n\t\t| SSEClientTransportOptions\n\t\t| StreamableHTTPClientTransportOptions;\n\turl: string;\n}): Promise<Server> => {\n\t// Normalize URL to avoid redirect issues on Windows (POST to GET conversion)\n\tconst normalizedUrl = normalizeUrl(url);\n\tlet transport: SSEClientTransport | StreamableHTTPClientTransport;\n\tswitch (serverType) {\n\t\tcase ServerType.SSE:\n\t\t\ttransport = new SSEClientTransport(new URL(normalizedUrl), transportOptions);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttransport = new StreamableHTTPClientTransport(\n\t\t\t\tnew URL(normalizedUrl),\n\t\t\t\ttransportOptions,\n\t\t\t);\n\t}\n\tconst streamClient = initStreamClient\n\t\t? await initStreamClient()\n\t\t: new Client(\n\t\t\t\t{\n\t\t\t\t\tname: \"mcp-gateway\",\n\t\t\t\t\tversion: config.appVersion,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcapabilities: {},\n\t\t\t\t},\n\t\t\t);\n\n\tawait streamClient.connect(transport);\n\n\tconst serverVersion = streamClient.getServerVersion() as {\n\t\tname: string;\n\t\tversion: string;\n\t};\n\n\tconst serverCapabilities = streamClient.getServerCapabilities() as {\n\t\tcapabilities: Record<string, unknown>;\n\t};\n\n\tconst stdioServer = initStdioServer\n\t\t? await initStdioServer()\n\t\t: new Server(serverVersion, {\n\t\t\t\tcapabilities: serverCapabilities,\n\t\t\t});\n\n\tconst stdioTransport = new StdioServerTransport();\n\n\tawait stdioServer.connect(stdioTransport);\n\n\tawait proxyServer({\n\t\tauthorizer: undefined,\n\t\tclient: streamClient,\n\t\tserver: stdioServer,\n\t\tserverCapabilities,\n\t});\n\n\treturn stdioServer;\n};\n","import { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\n\ntype TransportEvent =\n | {\n error: Error;\n type: \"onerror\";\n }\n | {\n message: JSONRPCMessage;\n type: \"onmessage\";\n }\n | {\n message: JSONRPCMessage;\n type: \"send\";\n }\n | {\n type: \"close\";\n }\n | {\n type: \"onclose\";\n }\n | {\n type: \"start\";\n };\n\nexport const tapTransport = (\n transport: Transport,\n eventHandler: (event: TransportEvent) => void,\n): Transport => {\n const originalClose = transport.close.bind(transport);\n const originalOnClose = transport.onclose?.bind(transport);\n const originalOnError = transport.onerror?.bind(transport);\n const originalOnMessage = transport.onmessage?.bind(transport);\n const originalSend = transport.send.bind(transport);\n const originalStart = transport.start.bind(transport);\n\n transport.close = async () => {\n eventHandler({\n type: \"close\",\n });\n\n return originalClose?.();\n };\n\n transport.onclose = async () => {\n eventHandler({\n type: \"onclose\",\n });\n\n return originalOnClose?.();\n };\n\n transport.onerror = async (error: Error) => {\n eventHandler({\n error,\n type: \"onerror\",\n });\n\n return originalOnError?.(error);\n };\n\n transport.onmessage = async (message: JSONRPCMessage) => {\n eventHandler({\n message,\n type: \"onmessage\",\n });\n\n return originalOnMessage?.(message);\n };\n\n transport.send = async (message: JSONRPCMessage) => {\n eventHandler({\n message,\n type: \"send\",\n });\n\n return originalSend?.(message);\n };\n\n transport.start = async () => {\n eventHandler({\n type: \"start\",\n });\n\n return originalStart?.();\n };\n\n return transport;\n};\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","names":["transport: SSEClientTransport | StreamableHTTPClientTransport"],"sources":["../src/startStdioServer.ts","../src/tapTransport.ts"],"sourcesContent":["import { Client } from \"@modelcontextprotocol/sdk/client/index.js\";\nimport {\n\tSSEClientTransport,\n\ttype SSEClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/sse.js\";\nimport {\n\tStreamableHTTPClientTransport,\n\ttype StreamableHTTPClientTransportOptions,\n} from \"@modelcontextprotocol/sdk/client/streamableHttp.js\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\n\nimport { config } from \"./config/env.js\";\nimport { proxyServer } from \"./proxyServer.js\";\nimport { normalizeUrl } from \"./utils/normalizeUrl.js\";\n\nexport enum ServerType {\n\tHTTPStream = \"HTTPStream\",\n\tSSE = \"SSE\",\n}\n\nexport const startStdioServer = async ({\n\tinitStdioServer,\n\tinitStreamClient,\n\tserverType,\n\ttransportOptions = {},\n\turl,\n}: {\n\tinitStdioServer?: () => Promise<Server>;\n\tinitStreamClient?: () => Promise<Client>;\n\tserverType: ServerType;\n\ttransportOptions?:\n\t\t| SSEClientTransportOptions\n\t\t| StreamableHTTPClientTransportOptions;\n\turl: string;\n}): Promise<Server> => {\n\t// Normalize URL to avoid redirect issues on Windows (POST to GET conversion)\n\tconst normalizedUrl = normalizeUrl(url);\n\tlet transport: SSEClientTransport | StreamableHTTPClientTransport;\n\tswitch (serverType) {\n\t\tcase ServerType.SSE:\n\t\t\ttransport = new SSEClientTransport(new URL(normalizedUrl), transportOptions);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\ttransport = new StreamableHTTPClientTransport(\n\t\t\t\tnew URL(normalizedUrl),\n\t\t\t\ttransportOptions,\n\t\t\t);\n\t}\n\tconst streamClient = initStreamClient\n\t\t? await initStreamClient()\n\t\t: new Client(\n\t\t\t\t{\n\t\t\t\t\tname: \"mcp-gateway\",\n\t\t\t\t\tversion: config.appVersion,\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tcapabilities: {},\n\t\t\t\t},\n\t\t\t);\n\n\tawait streamClient.connect(transport);\n\n\tconst serverVersion = streamClient.getServerVersion() as {\n\t\tname: string;\n\t\tversion: string;\n\t};\n\n\tconst serverCapabilities = streamClient.getServerCapabilities() as {\n\t\tcapabilities: Record<string, unknown>;\n\t};\n\n\tconst stdioServer = initStdioServer\n\t\t? await initStdioServer()\n\t\t: new Server(serverVersion, {\n\t\t\t\tcapabilities: serverCapabilities,\n\t\t\t});\n\n\tconst stdioTransport = new StdioServerTransport();\n\n\tawait stdioServer.connect(stdioTransport);\n\n\tawait proxyServer({\n\t\tauthorizer: undefined,\n\t\tclient: streamClient,\n\t\tserver: stdioServer,\n\t\tserverCapabilities,\n\t});\n\n\treturn stdioServer;\n};\n","import { Transport } from \"@modelcontextprotocol/sdk/shared/transport.js\";\nimport { JSONRPCMessage } from \"@modelcontextprotocol/sdk/types.js\";\n\ntype TransportEvent =\n | {\n error: Error;\n type: \"onerror\";\n }\n | {\n message: JSONRPCMessage;\n type: \"onmessage\";\n }\n | {\n message: JSONRPCMessage;\n type: \"send\";\n }\n | {\n type: \"close\";\n }\n | {\n type: \"onclose\";\n }\n | {\n type: \"start\";\n };\n\nexport const tapTransport = (\n transport: Transport,\n eventHandler: (event: TransportEvent) => void,\n): Transport => {\n const originalClose = transport.close.bind(transport);\n const originalOnClose = transport.onclose?.bind(transport);\n const originalOnError = transport.onerror?.bind(transport);\n const originalOnMessage = transport.onmessage?.bind(transport);\n const originalSend = transport.send.bind(transport);\n const originalStart = transport.start.bind(transport);\n\n transport.close = async () => {\n eventHandler({\n type: \"close\",\n });\n\n return originalClose?.();\n };\n\n transport.onclose = async () => {\n eventHandler({\n type: \"onclose\",\n });\n\n return originalOnClose?.();\n };\n\n transport.onerror = async (error: Error) => {\n eventHandler({\n error,\n type: \"onerror\",\n });\n\n return originalOnError?.(error);\n };\n\n transport.onmessage = async (message: JSONRPCMessage) => {\n eventHandler({\n message,\n type: \"onmessage\",\n });\n\n return originalOnMessage?.(message);\n };\n\n transport.send = async (message: JSONRPCMessage) => {\n eventHandler({\n message,\n type: \"send\",\n });\n\n return originalSend?.(message);\n };\n\n transport.start = async () => {\n eventHandler({\n type: \"start\",\n });\n\n return originalStart?.();\n };\n\n return transport;\n};\n"],"mappings":"2RAgBA,IAAY,EAAA,SAAA,EAAL,OACN,GAAA,WAAA,aACA,EAAA,IAAA,aAGD,MAAa,EAAmB,MAAO,CACtC,kBACA,mBACA,aACA,mBAAmB,EAAE,CACrB,SASsB,CAEtB,IAAM,EAAgB,EAAa,EAAI,CACnCA,EACJ,OAAQ,EAAR,CACC,KAAK,EAAW,IACf,EAAY,IAAI,EAAmB,IAAI,IAAI,EAAc,CAAE,EAAiB,CAC5E,MACD,QACC,EAAY,IAAI,EACf,IAAI,IAAI,EAAc,CACtB,EACA,CAEH,IAAM,EAAe,EAClB,MAAM,GAAkB,CACxB,IAAI,EACJ,CACC,KAAM,cACN,QAAS,EAAO,WAChB,CACD,CACC,aAAc,EAAE,CAChB,CACD,CAEH,MAAM,EAAa,QAAQ,EAAU,CAErC,IAAM,EAAgB,EAAa,kBAAkB,CAK/C,EAAqB,EAAa,uBAAuB,CAIzD,EAAc,EACjB,MAAM,GAAiB,CACvB,IAAI,EAAO,EAAe,CAC1B,aAAc,EACd,CAAC,CAEE,EAAiB,IAAI,EAW3B,OATA,MAAM,EAAY,QAAQ,EAAe,CAEzC,MAAM,EAAY,CACjB,WAAY,IAAA,GACZ,OAAQ,EACR,OAAQ,EACR,qBACA,CAAC,CAEK,GC/DK,GACX,EACA,IACc,CACd,IAAM,EAAgB,EAAU,MAAM,KAAK,EAAU,CAC/C,EAAkB,EAAU,SAAS,KAAK,EAAU,CACpD,EAAkB,EAAU,SAAS,KAAK,EAAU,CACpD,EAAoB,EAAU,WAAW,KAAK,EAAU,CACxD,EAAe,EAAU,KAAK,KAAK,EAAU,CAC7C,EAAgB,EAAU,MAAM,KAAK,EAAU,CAqDrD,MAnDA,GAAU,MAAQ,UAChB,EAAa,CACX,KAAM,QACP,CAAC,CAEK,KAAiB,EAG1B,EAAU,QAAU,UAClB,EAAa,CACX,KAAM,UACP,CAAC,CAEK,KAAmB,EAG5B,EAAU,QAAU,KAAO,KACzB,EAAa,CACX,QACA,KAAM,UACP,CAAC,CAEK,IAAkB,EAAM,EAGjC,EAAU,UAAY,KAAO,KAC3B,EAAa,CACX,UACA,KAAM,YACP,CAAC,CAEK,IAAoB,EAAQ,EAGrC,EAAU,KAAO,KAAO,KACtB,EAAa,CACX,UACA,KAAM,OACP,CAAC,CAEK,IAAe,EAAQ,EAGhC,EAAU,MAAQ,UAChB,EAAa,CACX,KAAM,QACP,CAAC,CAEK,KAAiB,EAGnB"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import{AccessControlBlockError as e,Client as t,ConfigurationError as n,ProxyConnectionError as r,ReadBuffer as i,Server as a,StdioServerTransport as o,compressClientInfo as s,getSessionData as c,initializeTrafficMirror as l,logRequestCounts as u,normalizeUrl as d,proxyServer as f,serializeMessage as p,startHTTPServer as m}from"./normalizeUrl-CYShKr9E.js";import{UnauthorizedError as h,chownToRealUser as g,config as _,createParser as v,discoverAuthorizationServerMetadata as y,discoverOAuthProtectedResourceMetadata as b,exchangeAuthorization as ee,extractTraceIdFromHeaders as te,flushLogs as x,logger as S,refreshAuthorization as C,registerClient as w,startAuthorization as ne}from"./streamableHttp-DM0LA7pR.js";import{emitProxySetupLog as re,hideBin as ie,yargs_default as ae}from"./helpers-DJo6DVLx.js";import"./pkce-CbP4rU3z.js";import{AuthServerDiscoveryError as T,connectWithTransportFallback as oe,discoverAuthServer as E,findProviderForUrl as se,setOAuthProviders as D}from"./transportDetection-DquHtdNu.js";import{createHash as O}from"node:crypto";import{join as k}from"node:path";import{platform as A}from"node:os";import{chmod as ce,mkdir as le,readFile as ue,rm as de,writeFile as fe}from"node:fs/promises";import{createServer as pe}from"node:http";import{StringDecoder as me}from"node:string_decoder";import{setTimeout as he}from"node:timers";import ge from"node:util";import{execFile as _e,execSync as ve,spawn as ye,spawnSync as be}from"node:child_process";import{URL as xe}from"node:url";import{PassThrough as Se,Transform as Ce}from"node:stream";var we=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(Ee(this),t)}[Symbol.for(`Deno.customInspect`)](e,t){return e(Ee(this),t)}};function Te(e){let t=globalThis.DOMException;return typeof t==`function`?new t(e,`SyntaxError`):SyntaxError(e)}function j(e){return e instanceof Error?`errors`in e&&Array.isArray(e.errors)?e.errors.map(j).join(`, `):`cause`in e&&e.cause instanceof Error?`${e}: ${j(e.cause)}`:e.message:`${e}`}function Ee(e){return{type:e.type,message:e.message,code:e.code,defaultPrevented:e.defaultPrevented,cancelable:e.cancelable,timeStamp:e.timeStamp}}var De=e=>{throw TypeError(e)},M=(e,t,n)=>t.has(e)||De(`Cannot `+n),N=(e,t,n)=>(M(e,t,`read from private field`),n?n.call(e):t.get(e)),P=(e,t,n)=>t.has(e)?De(`Cannot add the same private member more than once`):t instanceof WeakSet?t.add(e):t.set(e,n),F=(e,t,n,r)=>(M(e,t,`write to private field`),t.set(e,n),n),I=(e,t,n)=>(M(e,t,`access private method`),n),L,R,z,B,V,H,U,W,G,K,q,J,Y,X,Oe,ke,Ae,je,Me,Ne,Z,Pe,Fe,Q=class extends EventTarget{constructor(e,t){super(),P(this,X),this.CONNECTING=0,this.OPEN=1,this.CLOSED=2,P(this,L),P(this,R),P(this,z),P(this,B),P(this,V),P(this,H),P(this,U),P(this,W,null),P(this,G),P(this,K),P(this,q,null),P(this,J,null),P(this,Y,null),P(this,ke,async e=>{var t;N(this,K).reset();let{body:n,redirected:r,status:i,headers:a}=e;if(i===204){I(this,X,Z).call(this,`Server sent HTTP 204, not reconnecting`,204),this.close();return}if(r?F(this,z,new URL(e.url)):F(this,z,void 0),i!==200){I(this,X,Z).call(this,`Non-200 status code (${i})`,i);return}if(!(a.get(`content-type`)||``).startsWith(`text/event-stream`)){I(this,X,Z).call(this,`Invalid content type, expected "text/event-stream"`,i);return}if(N(this,L)===this.CLOSED)return;F(this,L,this.OPEN);let o=new Event(`open`);if((t=N(this,Y))==null||t.call(this,o),this.dispatchEvent(o),typeof n!=`object`||!n||!(`getReader`in n)){I(this,X,Z).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&&N(this,K).feed(s.decode(t,{stream:!e})),e&&(l=!1,N(this,K).reset(),I(this,X,Pe).call(this))}while(l)}),P(this,Ae,e=>{F(this,G,void 0),!(e.name===`AbortError`||e.type===`aborted`)&&I(this,X,Pe).call(this,j(e))}),P(this,Me,e=>{typeof e.id==`string`&&F(this,W,e.id);let t=new MessageEvent(e.event||`message`,{data:e.data,origin:N(this,z)?N(this,z).origin:N(this,R).origin,lastEventId:e.id||``});N(this,J)&&(!e.event||e.event===`message`)&&N(this,J).call(this,t),this.dispatchEvent(t)}),P(this,Ne,e=>{F(this,H,e)}),P(this,Fe,()=>{F(this,U,void 0),N(this,L)===this.CONNECTING&&I(this,X,Oe).call(this)});try{if(e instanceof URL)F(this,R,e);else if(typeof e==`string`)F(this,R,new URL(e,Ie()));else throw Error(`Invalid URL`)}catch{throw Te(`An invalid or illegal string was specified`)}F(this,K,v({onEvent:N(this,Me),onRetry:N(this,Ne)})),F(this,L,this.CONNECTING),F(this,H,3e3),F(this,V,t?.fetch??globalThis.fetch),F(this,B,t?.withCredentials??!1),I(this,X,Oe).call(this)}get readyState(){return N(this,L)}get url(){return N(this,R).href}get withCredentials(){return N(this,B)}get onerror(){return N(this,q)}set onerror(e){F(this,q,e)}get onmessage(){return N(this,J)}set onmessage(e){F(this,J,e)}get onopen(){return N(this,Y)}set onopen(e){F(this,Y,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(){N(this,U)&&clearTimeout(N(this,U)),N(this,L)!==this.CLOSED&&(N(this,G)&&N(this,G).abort(),F(this,L,this.CLOSED),F(this,G,void 0))}};L=new WeakMap,R=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 WeakMap,J=new WeakMap,Y=new WeakMap,X=new WeakSet,Oe=function(){F(this,L,this.CONNECTING),F(this,G,new AbortController),N(this,V)(N(this,R),I(this,X,je).call(this)).then(N(this,ke)).catch(N(this,Ae))},ke=new WeakMap,Ae=new WeakMap,je=function(){let e={mode:`cors`,redirect:`follow`,headers:{Accept:`text/event-stream`,...N(this,W)?{"Last-Event-ID":N(this,W)}:void 0},cache:`no-store`,signal:N(this,G)?.signal};return`window`in globalThis&&(e.credentials=this.withCredentials?`include`:`same-origin`),e},Me=new WeakMap,Ne=new WeakMap,Z=function(e,t){var n;N(this,L)!==this.CLOSED&&F(this,L,this.CLOSED);let r=new we(`error`,{code:t,message:e});(n=N(this,q))==null||n.call(this,r),this.dispatchEvent(r)},Pe=function(e,t){var n;if(N(this,L)===this.CLOSED)return;F(this,L,this.CONNECTING);let r=new we(`error`,{code:t,message:e});(n=N(this,q))==null||n.call(this,r),this.dispatchEvent(r),F(this,U,setTimeout(N(this,Fe),N(this,H)))},Fe=new WeakMap,Q.CONNECTING=0,Q.OPEN=1,Q.CLOSED=2;function Ie(){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 Le=class{client;enabled;lastBlockReason;serverName;constructor(e){this.enabled=e.enabled,this.client=e.client,this.serverName=e.serverName,S.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 S.error(`Access control authorization failed with unexpected error`,{error:String(e)}),!0}return S.warn(`No access control client configured, allowing by default`),!0}},Re=class{clientInfoBase64;config;constructor(e){this.config=e,this.clientInfoBase64=this.getClientInfoBase64(),S.info(`AccessControlClient initialized`,{timeoutMs:e.timeoutMs,url:e.url})}async authorize(){try{let e=await this.sendAuthorizeRequest();return S.debug(`Access control check successful`,{action:e.action}),e}catch(e){return S.warn(`Access control check failed, failing open (allowing by default)`,{error:String(e)}),{action:`allow`}}}getClientInfoBase64(){return s(this.config.sessionData)}async sendAuthorizeRequest(){let e=new AbortController,t=setTimeout(()=>e.abort(),this.config.timeoutMs);try{let t=`${this.config.url}/${this.config.apiKey}/mcp/${this.clientInfoBase64}`,n=await fetch(t,{headers:{...this.config.headers},method:`POST`,signal:e.signal});if(!n.ok)throw Error(`Access control service returned ${n.status}: ${n.statusText}`);let r=await n.json();if(!r.action||![`allow`,`block`].includes(r.action))throw Error(`Invalid access control response format: action="${r.action}"`);return r}catch(e){throw e instanceof Error&&e.name===`AbortError`?Error(`Access control check timed out after ${this.config.timeoutMs}ms`):e}finally{clearTimeout(t)}}};async function ze(e){let t=e.toString(),n=A(),r=Ue(t);return new Promise((e,i)=>{let a,o;if(n===`win32`){let e=`Start-Process ${Ve(t)}`,n=Be(e);a=He(),o=[`-NoProfile`,`-NonInteractive`,`-ExecutionPolicy`,`Bypass`,`-EncodedCommand`,n]}else n===`darwin`?(a=`open`,o=[t]):(a=`xdg-open`,o=[t]);_e(a,o,(t,o,s)=>{if(t){let e={command:a,os:n,stderr:s,url:r};S.warn(`Failed to open browser automatically`,{...e,error:t.message});let o=Error(`Failed to open browser: ${t.message} (command: ${a}, os: ${n}, url: ${r})`);o.cause=t,i(o)}else S.debug(`Browser opened successfully`,{url:r}),e()})})}function Be(e){return Buffer.from(e,`utf16le`).toString(`base64`)}function Ve(e){return`'${e.replaceAll(`'`,`''`)}'`}function He(){return`${process.env.SYSTEMROOT||process.env.windir||`C:\\Windows`}\\System32\\WindowsPowerShell\\v1.0\\powershell.exe`}function Ue(e){try{let t=new URL(e);return t.search?`${t.protocol}//${t.host}${t.pathname}?[REDACTED]`:`${t.protocol}//${t.host}${t.pathname}`}catch{return`[INVALID_URL]`}}const $={CALLBACK_FAILED:`mcp_auth_callback_failed`,DCR_FAILED:`mcp_auth_dcr_failed`,REFRESH_FAILED:`mcp_auth_refresh_failed`,SERVER_METADATA_FAILED:`mcp_auth_server_metadata_failed`,STATE_MISMATCH:`mcp_auth_state_mismatch`,TOKEN_EXCHANGE_FAILED:`mcp_auth_token_exchange_failed`},We=49152;function Ge(){return Math.floor(Math.random()*(65535-We+1))+We}function Ke(e,t){return new Promise((n,r)=>{let i=t=>{e.removeListener(`listening`,a),r(t)},a=()=>{e.removeListener(`error`,i),n()};e.once(`error`,i),e.once(`listening`,a),e.listen(t,`127.0.0.1`)})}async function qe(e={}){let{maxAttempts:t=5,preferredPort:n,serverUrl:r,timeoutMs:i=3e5}=e,a=r?Xe(r):void 0,o,s,c={},l=new Promise((e,t)=>{o=e,s=t}),u,d=pe((e,t)=>{if(e.url===`/favicon.ico`){t.writeHead(404),t.end();return}if(!e.url?.startsWith(`/callback`)){t.writeHead(404),t.end(`Not Found`);return}try{let n=new xe(e.url,`http://localhost:${u}`),r=n.searchParams.get(`code`),i=n.searchParams.get(`error`),l=n.searchParams.get(`error_description`),f=n.searchParams.get(`state`);if(i){S.error(`OAuth authorization error`,{error:i,errorDescription:l,eventType:$.CALLBACK_FAILED,...a?{serverUrl:a}:{}}),t.writeHead(400,{"Content-Type":`text/html`}),t.end(Ye(i,l||void 0)),clearTimeout(c.id),s(Error(`OAuth authorization failed: ${i}${l?` - ${l}`:``}`));return}if(!r){S.error(`OAuth callback missing authorization code`,{eventType:$.CALLBACK_FAILED,reason:`missing_code`,...a?{serverUrl:a}:{}}),t.writeHead(400,{"Content-Type":`text/html`}),t.end(Ye(`missing_code`,`No authorization code was provided`)),clearTimeout(c.id),s(Error(`OAuth callback missing authorization code`));return}S.info(`OAuth authorization code received`,{codePrefix:`${r.substring(0,10)}...`,hasState:!!f}),t.writeHead(200,{"Content-Type":`text/html`}),t.end(`<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Authorization Successful</title>
|
|
7
|
+
<style>
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: center;
|
|
12
|
+
align-items: center;
|
|
13
|
+
min-height: 100vh;
|
|
14
|
+
margin: 0;
|
|
15
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
16
|
+
color: #fff;
|
|
17
|
+
}
|
|
18
|
+
.container {
|
|
19
|
+
text-align: center;
|
|
20
|
+
padding: 2rem;
|
|
21
|
+
}
|
|
22
|
+
.checkmark {
|
|
23
|
+
width: 80px;
|
|
24
|
+
height: 80px;
|
|
25
|
+
border-radius: 50%;
|
|
26
|
+
background: #10b981;
|
|
27
|
+
display: flex;
|
|
28
|
+
align-items: center;
|
|
29
|
+
justify-content: center;
|
|
30
|
+
margin: 0 auto 1.5rem;
|
|
31
|
+
animation: pop 0.3s ease-out;
|
|
32
|
+
}
|
|
33
|
+
.checkmark svg {
|
|
34
|
+
width: 40px;
|
|
35
|
+
height: 40px;
|
|
36
|
+
stroke: white;
|
|
37
|
+
stroke-width: 3;
|
|
38
|
+
}
|
|
39
|
+
h1 {
|
|
40
|
+
margin: 0 0 0.5rem;
|
|
41
|
+
font-size: 1.75rem;
|
|
42
|
+
font-weight: 600;
|
|
43
|
+
}
|
|
44
|
+
p {
|
|
45
|
+
margin: 0;
|
|
46
|
+
color: #a0aec0;
|
|
47
|
+
font-size: 1rem;
|
|
48
|
+
}
|
|
49
|
+
@keyframes pop {
|
|
50
|
+
0% { transform: scale(0); }
|
|
51
|
+
50% { transform: scale(1.1); }
|
|
52
|
+
100% { transform: scale(1); }
|
|
53
|
+
}
|
|
54
|
+
</style>
|
|
55
|
+
</head>
|
|
56
|
+
<body>
|
|
57
|
+
<div class="container">
|
|
58
|
+
<div class="checkmark">
|
|
59
|
+
<svg viewBox="0 0 24 24" fill="none">
|
|
60
|
+
<path d="M5 13l4 4L19 7" stroke-linecap="round" stroke-linejoin="round"/>
|
|
61
|
+
</svg>
|
|
62
|
+
</div>
|
|
63
|
+
<h1>Authorization Successful</h1>
|
|
64
|
+
<p>You can close this window and return to the terminal.</p>
|
|
65
|
+
</div>
|
|
66
|
+
<script>setTimeout(() => window.close(), 3000);<\/script>
|
|
67
|
+
</body>
|
|
68
|
+
</html>`),clearTimeout(c.id),o({code:r,state:f||void 0}),setTimeout(()=>d.close(),1e3)}catch(e){S.error(`Error processing OAuth callback`,{error:String(e),eventType:$.CALLBACK_FAILED,reason:`callback_processing_error`,...a?{serverUrl:a}:{}}),t.writeHead(500),t.end(`Internal Server Error`),clearTimeout(c.id),s(e instanceof Error?e:Error(String(e)))}});c.id=setTimeout(()=>{s(Error(`OAuth callback timeout after ${i}ms`)),d.close()},i);let f=[],p;for(;f.length<t;){let e;if(f.length===0&&n!==void 0)e=n;else for(e=Ge();f.includes(e);)e=Ge();f.push(e);try{await Ke(d,e),u=e;let t=`http://localhost:${u}/callback`;return S.info(`OAuth callback server started`,{attempt:f.length,callbackUrl:t,port:u}),{callbackUrl:t,close:()=>new Promise(e=>{clearTimeout(c.id),d.close(()=>e()),d.closeAllConnections()}),port:u,waitForCallback:()=>l}}catch(n){if(n.code===`EADDRINUSE`)S.debug(`Port in use, trying another port`,{attempt:f.length,maxAttempts:t,port:e}),p=Error(`Port ${e} is already in use`);else throw clearTimeout(c.id),d.close(),n}}throw clearTimeout(c.id),d.close(),Error(`Failed to start OAuth callback server after ${t} attempts. Tried ports: ${f.join(`, `)}. Last error: ${p?.message||`unknown`}`)}function Je(e){return e.replace(/&/g,`&`).replace(/</g,`<`).replace(/>/g,`>`).replace(/"/g,`"`).replace(/'/g,`'`)}function Ye(e,t){return`<!DOCTYPE html>
|
|
69
|
+
<html lang="en">
|
|
70
|
+
<head>
|
|
71
|
+
<meta charset="UTF-8">
|
|
72
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
73
|
+
<title>Authorization Failed</title>
|
|
74
|
+
<style>
|
|
75
|
+
body {
|
|
76
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
77
|
+
display: flex;
|
|
78
|
+
justify-content: center;
|
|
79
|
+
align-items: center;
|
|
80
|
+
min-height: 100vh;
|
|
81
|
+
margin: 0;
|
|
82
|
+
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
|
|
83
|
+
color: #fff;
|
|
84
|
+
}
|
|
85
|
+
.container {
|
|
86
|
+
text-align: center;
|
|
87
|
+
padding: 2rem;
|
|
88
|
+
max-width: 400px;
|
|
89
|
+
}
|
|
90
|
+
.error-icon {
|
|
91
|
+
width: 80px;
|
|
92
|
+
height: 80px;
|
|
93
|
+
border-radius: 50%;
|
|
94
|
+
background: #ef4444;
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
justify-content: center;
|
|
98
|
+
margin: 0 auto 1.5rem;
|
|
99
|
+
}
|
|
100
|
+
.error-icon svg {
|
|
101
|
+
width: 40px;
|
|
102
|
+
height: 40px;
|
|
103
|
+
stroke: white;
|
|
104
|
+
stroke-width: 3;
|
|
105
|
+
}
|
|
106
|
+
h1 {
|
|
107
|
+
margin: 0 0 0.5rem;
|
|
108
|
+
font-size: 1.75rem;
|
|
109
|
+
font-weight: 600;
|
|
110
|
+
}
|
|
111
|
+
.error-code {
|
|
112
|
+
color: #f87171;
|
|
113
|
+
font-family: monospace;
|
|
114
|
+
margin-bottom: 0.5rem;
|
|
115
|
+
}
|
|
116
|
+
p {
|
|
117
|
+
margin: 0;
|
|
118
|
+
color: #a0aec0;
|
|
119
|
+
font-size: 1rem;
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
122
|
+
</head>
|
|
123
|
+
<body>
|
|
124
|
+
<div class="container">
|
|
125
|
+
<div class="error-icon">
|
|
126
|
+
<svg viewBox="0 0 24 24" fill="none">
|
|
127
|
+
<path d="M6 18L18 6M6 6l12 12" stroke-linecap="round" stroke-linejoin="round"/>
|
|
128
|
+
</svg>
|
|
129
|
+
</div>
|
|
130
|
+
<h1>Authorization Failed</h1>
|
|
131
|
+
<p class="error-code">${Je(e)}</p>
|
|
132
|
+
${t?`<p>${Je(t)}</p>`:``}
|
|
133
|
+
</div>
|
|
134
|
+
</body>
|
|
135
|
+
</html>`}function Xe(e){try{let t=new xe(e);return t.username=``,t.password=``,t.search=``,t.hash=``,t.toString()}catch{return e}}var Ze=class{storageDir;constructor(e){this.storageDir=e.storageDir}async delete(e){let t=d(e),n=this.getFilePath(t);try{await de(n),S.debug(`Deleted stored credentials`,{filePath:n,serverUrl:t})}catch(e){e.code!==`ENOENT`&&S.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 S.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=d(e),n=this.getFilePath(t);try{let e=await ue(n,`utf-8`),r=JSON.parse(e);if(d(r.serverUrl)!==t){S.warn(`Credential file server URL mismatch`,{expected:t,filePath:n,found:r.serverUrl});return}return S.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`){S.debug(`No stored credentials found`,{serverUrl:t});return}S.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 fe(t,n,{encoding:`utf-8`,mode:384}),await ce(t,384),S.debug(`Saved credentials to disk`,{clientId:e.clientInfo?.client_id,filePath:t,hasTokens:!!e.tokens,serverUrl:e.serverUrl})}catch(n){throw S.error(`Failed to save credentials`,{error:String(n),filePath:t,serverUrl:e.serverUrl}),n}}async update(e,t){let n=d(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 le(this.storageDir,{mode:448,recursive:!0})}catch(e){if(e.code!==`EEXIST`)throw e}try{await g(this.storageDir)}catch(e){S.warn(`Failed to fix OAuth storage directory ownership`,{error:String(e),storageDir:this.storageDir})}}generateKey(e){return O(`sha256`).update(e).digest(`hex`).substring(0,16)}getFilePath(e){let t=this.generateKey(e);return k(this.storageDir,`${t}.json`)}};const Qe={"claude-code":`Claude Code (mcp-gateway)`,codex:`Codex`,copilot:`Visual Studio Code`,cursor:`Cursor`,opencode:`OpenCode`};async function $e(e,t={}){let{credentialStore:n,scope:r,timeoutMs:i}=t,a=d(e),o=new URL(a);if(S.info(`Starting OAuth flow`,{serverUrl:a}),n){let e=await it(o,n);if(e)return S.info(`Using existing OAuth credentials`,{clientId:e.clientInfo.client_id,serverUrl:a}),e}S.debug(`Starting OAuth callback server...`);let s=await qe({serverUrl:a,timeoutMs:i}),c=s.callbackUrl;S.info(`OAuth callback server started`,{callbackUrl:c,port:s.port});try{let e=se(o);if(e)return S.info(`Using pre-configured OAuth provider`,{providerId:e.id,providerName:e.name}),await rt(o,e,s,n,r);let i,l;try{({authMetadata:i,authServerUrl:l}=await E(o,{logger:S}))}catch(e){throw S.error(`Auth server metadata discovery failed`,{error:String(e),eventType:$.SERVER_METADATA_FAILED,serverUrl:a,...e instanceof T?{authServer:e.authServerUrl.toString()}:{}}),e}if(!i)throw S.error(`Auth server metadata absent (server may not support OAuth 2.0)`,{authServer:l.toString(),eventType:$.SERVER_METADATA_FAILED,reason:`metadata_absent`,serverUrl:a}),Error(`Could not discover OAuth metadata from ${l}. The server may not support OAuth 2.0 or the metadata endpoint is not accessible.`);let u,d=n?await n.load(a):void 0,f=d?.clientInfo?.redirect_uris||[];if(d?.clientInfo&&f.includes(c)&&d?.clientInfo)S.info(`Reusing existing DCR client registration`,{clientId:d.clientInfo.client_id,clientName:d.clientInfo.client_name,redirectUri:c}),u=d.clientInfo;else{d?.clientInfo&&S.info(`Existing DCR client has different redirect_uri, re-registering`,{existingRedirectUris:f,newRedirectUri:c});let e={client_name:t.clientMetadata?.client_name||nt(),grant_types:t.clientMetadata?.grant_types||[`authorization_code`,`refresh_token`],redirect_uris:[c],response_types:t.clientMetadata?.response_types||[`code`],token_endpoint_auth_method:t.clientMetadata?.token_endpoint_auth_method||`none`,...r&&{scope:r}};if(S.debug(`Client metadata for DCR`,{clientMetadata:e}),!i.registration_endpoint)throw S.error(`DCR registration unsupported by auth server`,{authServer:l.toString(),eventType:$.DCR_FAILED,reason:`no_registration_endpoint`,serverUrl:a}),Error(`Authorization server does not support Dynamic Client Registration. No registration_endpoint found in metadata.`);S.info(`Registering client via DCR...`,{registrationEndpoint:i.registration_endpoint});try{u=await w(l,{clientMetadata:e,metadata:i})}catch(e){throw S.error(`DCR registration failed`,{authServer:l.toString(),error:String(e),eventType:$.DCR_FAILED,registrationEndpoint:i.registration_endpoint,serverUrl:a}),e}S.info(`Client registered successfully via DCR`,{clientId:u.client_id,clientName:u.client_name,clientSecretExpiresAt:u.client_secret_expires_at}),n&&await n.update(a,{clientInfo:u})}let p=crypto.randomUUID();S.debug(`Starting authorization flow...`);let{authorizationUrl:m,codeVerifier:h}=await ne(l,{clientInformation:u,metadata:i,redirectUrl:c,scope:r,state:p});await ze(m),S.debug(`Waiting for OAuth callback...`);let g=await s.waitForCallback();if(g.state!==p)throw S.error(`OAuth state mismatch — possible CSRF attack`,{authServer:l.toString(),eventType:$.STATE_MISMATCH,serverUrl:a}),Error(`OAuth state mismatch - possible CSRF attack`);S.info(`Authorization code received`,{codePrefix:`${g.code.substring(0,10)}...`}),S.debug(`Exchanging authorization code for tokens...`);let _;try{_=await ee(l,{authorizationCode:g.code,clientInformation:u,codeVerifier:h,metadata:i,redirectUri:c})}catch(e){throw S.error(`Token exchange failed`,{authServer:l.toString(),clientId:u.client_id,error:String(e),eventType:$.TOKEN_EXCHANGE_FAILED,grantType:`authorization_code`,serverUrl:a}),e}if(S.info(`OAuth tokens obtained successfully`,{expiresIn:_.expires_in,hasRefreshToken:!!_.refresh_token,tokenType:_.token_type}),n){let e=new Date().toISOString();await n.update(a,{tokens:_,tokensObtainedAt:e}),S.info(`OAuth credentials persisted to disk`,{serverUrl:a})}return{clientInfo:u,fromCache:!1,tokens:_}}finally{await s.close()}}function et(e){let t=e?.trim().toLowerCase();return t?Qe[t]??`MCP Gateway`:`MCP Gateway`}async function tt(e,t,n,r){let i=e.tokenEndpoint,a=e.tokenEndpointAuthMethod||(e.clientSecret?`client_secret_post`:`none`),o=new URLSearchParams;o.set(`grant_type`,`authorization_code`),o.set(`code`,t),o.set(`redirect_uri`,n),r&&o.set(`code_verifier`,r);let s={Accept:`application/json`,"Content-Type":`application/x-www-form-urlencoded`};a===`client_secret_basic`&&e.clientSecret?s.Authorization=`Basic ${Buffer.from(`${e.clientId}:${e.clientSecret}`).toString(`base64`)}`:a===`client_secret_post`&&e.clientSecret?(o.set(`client_id`,e.clientId),o.set(`client_secret`,e.clientSecret)):o.set(`client_id`,e.clientId),S.debug(`Sending token request`,{authMethod:a,providerId:e.id,tokenEndpoint:i});let c=await fetch(i,{body:o.toString(),headers:s,method:`POST`});if(!c.ok){let t=await c.text();throw S.error(`Token exchange failed`,{authMethod:a,error:t,eventType:$.TOKEN_EXCHANGE_FAILED,grantType:`authorization_code`,httpStatus:c.status,providerId:e.id,tokenEndpoint:i}),Error(`Token exchange failed: ${c.status} ${t}`)}let l=c.headers.get(`content-type`)||``,u;if(l.includes(`application/json`))u=await c.json();else if(l.includes(`application/x-www-form-urlencoded`)||l.includes(`text/plain`)){let e=await c.text(),t=new URLSearchParams(e);u=Object.fromEntries(t.entries())}else{let e=await c.text();try{u=JSON.parse(e)}catch{let t=new URLSearchParams(e);u=Object.fromEntries(t.entries())}}return typeof u.expires_in==`string`&&(u.expires_in=parseInt(u.expires_in,10)),{access_token:u.access_token,expires_in:u.expires_in,refresh_token:u.refresh_token,scope:u.scope,token_type:u.token_type||`bearer`}}function nt(){return et(_.clientAppName)}async function rt(e,t,n,r,i){let a=e.toString(),o=n.callbackUrl,s={client_id:t.clientId,client_name:t.name,client_secret:t.clientSecret,redirect_uris:[o],token_endpoint_auth_method:t.tokenEndpointAuthMethod||(t.clientSecret?`client_secret_post`:`none`)};S.info(`Using pre-configured OAuth client`,{clientId:t.clientId,hasClientSecret:!!t.clientSecret,providerId:t.id,tokenEndpointAuthMethod:s.token_endpoint_auth_method});let c=i||t.scopes?.join(` `),l=t.usePkce!==!1,u,d,f;if(l){let{generateCodeChallenge:e,generateCodeVerifier:t}=await import(`./pkce-CAz04Nh9.js`);u=t(),d=await e(u),f=`S256`}let p=new URL(t.authorizationEndpoint);p.searchParams.set(`client_id`,t.clientId),p.searchParams.set(`redirect_uri`,o),p.searchParams.set(`response_type`,`code`),c&&p.searchParams.set(`scope`,c);let m=crypto.randomUUID();p.searchParams.set(`state`,m),d&&f&&(p.searchParams.set(`code_challenge`,d),p.searchParams.set(`code_challenge_method`,f)),await ze(p),S.debug(`Waiting for OAuth callback...`);let h=await n.waitForCallback();if(h.state!==m)throw S.error(`OAuth state mismatch — possible CSRF attack`,{eventType:$.STATE_MISMATCH,providerId:t.id,serverUrl:a}),Error(`OAuth state mismatch - possible CSRF attack`);S.info(`Authorization code received`,{codePrefix:`${h.code.substring(0,10)}...`,providerId:t.id}),S.debug(`Exchanging authorization code for tokens...`);let g=await tt(t,h.code,o,u);if(S.info(`OAuth tokens obtained successfully`,{expiresIn:g.expires_in,hasRefreshToken:!!g.refresh_token,providerId:t.id,tokenType:g.token_type}),r){let e=new Date().toISOString();await r.update(a,{clientInfo:s,tokens:g,tokensObtainedAt:e}),S.info(`OAuth credentials persisted to disk`,{providerId:t.id,serverUrl:a})}return{clientInfo:s,fromCache:!1,tokens:g}}async function it(e,t){let n=await t.load(e.toString());if(!n){S.debug(`No stored credentials found`,{serverUrl:e.toString()});return}if(!n.clientInfo){S.debug(`Stored credentials have no client info`,{serverUrl:e.toString()});return}if(t.hasValidAccessToken(n)&&n.tokens)return S.info(`Using cached OAuth credentials with valid access token`,{clientId:n.clientInfo.client_id,serverUrl:e.toString()}),{clientInfo:n.clientInfo,fromCache:!0,tokens:n.tokens};if(t.hasRefreshToken(n)){let r=await at(e,n,t);if(r)return r}S.debug(`Stored credentials are expired and no valid refresh token`,{serverUrl:e.toString()})}async function at(e,t,n){if(!(!t.clientInfo||!t.tokens?.refresh_token)){S.info(`Attempting to refresh expired access token`,{clientId:t.clientInfo.client_id,serverUrl:e.toString()});try{let r;try{r=await b(e)}catch{}let i;i=r?.authorization_servers?.length?new URL(r.authorization_servers[0]):e;let a=await y(i),o=await C(i,{clientInformation:t.clientInfo,metadata:a,refreshToken:t.tokens.refresh_token});S.info(`Successfully refreshed access token`,{clientId:t.clientInfo.client_id,expiresIn:o.expires_in,hasNewRefreshToken:!!o.refresh_token});let s=new Date().toISOString();return await n.update(e.toString(),{tokens:o,tokensObtainedAt:s}),{clientInfo:t.clientInfo,fromCache:!0,tokens:o}}catch(r){S.warn(`Failed to refresh access token, will require re-authorization`,{clientId:t.clientInfo.client_id,error:String(r),eventType:$.REFRESH_FAILED,serverUrl:e.toString()}),await n.update(e.toString(),{tokens:void 0,tokensObtainedAt:void 0});return}}}async function ot(e){let t=new URL(e.url),n=t.hostname===`localhost`||t.hostname===`127.0.0.1`||t.hostname===`::1`||t.hostname===`[::1]`;if(t.protocol!==`https:`&&!n)throw Error(`OAuth providers URL must use HTTPS, got ${t.protocol}`);let r=new AbortController,i=setTimeout(()=>r.abort(),e.timeoutMs);try{let t=await fetch(e.url,{headers:{Accept:`application/json`,apikey:e.apiKey},method:`GET`,signal:r.signal});if(!t.ok)throw Error(`OAuth providers service returned ${t.status}: ${t.statusText}`);let n=await t.json();return Array.isArray(n.providers)?n.providers:[]}catch(t){throw t instanceof Error&&t.name===`AbortError`?Error(`OAuth providers fetch timed out after ${e.timeoutMs}ms`):t}finally{clearTimeout(i)}}async function st(e){if(!e.enabled||!e.url||!e.apiKey){D([]),S.debug(`OAuth providers fetch disabled (missing URL or API key); skipping`);return}try{let t=await ot({apiKey:e.apiKey,timeoutMs:e.timeoutMs,url:e.url});D(t),S.info(`OAuth providers loaded`,{count:t.length,ids:t.map(e=>e.id)})}catch(t){D([]),S.warn(`OAuth providers fetch failed; falling back to DCR`,{error:String(t),url:e.url})}}var ct=class extends Ce{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(`
|
|
136
|
+
`);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(`
|
|
137
|
+
`)}\n`;n(null,Buffer.from(e))}else n(null,null)}logDroppedLine(e){if(!(this.droppedLinesLogged>50)){if(this.droppedLinesLogged===50){this.droppedLinesLogged+=1,S.info(`Suppressing further non-JSON stdout lines`,{eventType:`mcp_server_stdout_dropped_suppressed`,loggedSoFar:50});return}this.droppedLinesLogged+=1,S.info(`MCP server stdout (non-JSON, dropped)`,{eventType:`mcp_server_stdout_dropped`,line:e.length>1024?`${e.slice(0,1024)}…`:e})}}},lt=class{onclose;onerror;onmessage;get pid(){return this._process?.pid??null}get stderr(){return this._stderrStream?this._stderrStream:this._process?.stderr??null}_abortController=new AbortController;_process;_readBuffer=new i;_serverParams;_stderrStream=null;onEvent;constructor(e){this._serverParams=e,(e.stderr===`pipe`||e.stderr===`overlapped`)&&(this._stderrStream=new Se),this.onEvent=e.onEvent}async close(){if(this.onEvent?.({type:`close`}),this._process?.pid)try{if(process.platform===`win32`){let e=be(`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){S.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=p(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)=>{this._process=ye(this._serverParams.command,this._serverParams.args??[],{cwd:this._serverParams.cwd,detached:process.platform!==`win32`,env:this._serverParams.env,shell:this._serverParams.shell??!1,signal:this._abortController.signal,stdio:[`pipe`,`pipe`,this._serverParams.stderr??`inherit`]}),this._process.on(`error`,e=>{if(e.name===`AbortError`){this.onclose?.();return}S.error(`Process spawn error`,{args:this._serverParams.args,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 n,r;this._process.on(`spawn`,()=>{n=Date.now(),r=this._process?.pid,S.info(`MCP server process spawned`,{argCount:this._serverParams.args?.length,command:this._serverParams.command,eventType:`mcp_server_process_spawned`,pid:r}),e()}),this._process.on(`close`,(e,t)=>{let i=n===void 0?void 0:Date.now()-n;S[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:r,signal:t,uptimeMs:i}),this.onEvent?.({type:`close`}),this._process=void 0,this.onclose?.()}),this._process.stdin?.on(`error`,e=>{S.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 i=new ct;this._process.stdout?.pipe(i),i.on(`data`,e=>{this.onEvent?.({chunk:e.toString(),type:`data`}),this._readBuffer.append(e),this.processReadBuffer()}),i.on(`error`,e=>{S.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{}S.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 ut(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 dt(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 ft(e,t){try{let n=ve(`${t===`unknown`?`docker`:t} image inspect --format "{{json .RepoDigests}}" ${JSON.stringify(e)}`,{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:5e3}).trim(),r;try{r=JSON.parse(n)}catch{return S.debug(`Could not parse RepoDigests JSON`,{imageName:e,result:n,runtime:t}),[]}let i=[];for(let e of r){let t=e.match(/sha256:[a-f0-9]{64}/i);t?i.push(t[0]):/^sha256:[a-f0-9]{64}$/i.test(e)&&i.push(e)}return i.length>0?(S.debug(`Container image digests retrieved`,{digests:i,imageName:e,runtime:t}),i):(S.debug(`No digests available for image (may be locally built)`,{imageName:e,runtime:t}),[])}catch(n){return S.debug(`Could not get container image digests`,{error:n instanceof Error?n.message:String(n),imageName:e,runtime:t}),[]}}function pt(e,t){let n=ut(e);if(n===`unknown`)return{imageDigests:[],imageName:``,isContainerMCP:!1,runtime:`unknown`};if(!t||!t.includes(`run`))return{imageDigests:[],imageName:``,isContainerMCP:!1,runtime:n};let r=dt(t);return r?{imageDigests:ft(r,n),imageName:r,isContainerMCP:!0,runtime:n}:(S.debug(`Container command detected but could not extract image name`,{args:t,command:e,runtime:n}),{imageDigests:[],imageName:``,isContainerMCP:!0,runtime:n})}ge.inspect.defaultOptions.depth=8,`EventSource`in global||(global.EventSource=Q);const mt=async()=>{re(S);let i=await ae(ie(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 st(_.oauthProviders);let s,p,g,v,y,b={},ee={};if(i.env)for(let e of i.env){let[t,...n]=e.split(`=`);t&&n.length>0&&(ee[t.trim()]=n.join(`=`).trim())}let C=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(i.headers)for(let e of i.headers){let[t,...n]=e.split(`:`);t&&n.length>0&&(b[t.trim()]=n.join(`:`).trim())}if(i.bearerTokenEnv){let e=i.bearerTokenEnv,{missingVar:t,resolved:n}=C(e);t&&(S.error(`Bearer token env var specified but not set`,{envVar:t,eventType:`mcp_auth_bearer_env_missing`}),process.exit(1)),b.Authorization=`Bearer ${n}`,S.info(`Bearer token loaded from environment variable`,{authType:`bearer_token`,envVar:e,eventType:`mcp_auth_bearer_env`,remoteUrl:i.url})}if(i.envHttpHeaders)for(let e of i.envHttpHeaders){let[t,...n]=e.split(`:`),r=n.join(`:`).trim();if(t&&r){let e=t.trim(),{missingVar:n,resolved:a}=C(r);n&&(S.error(`Env var for HTTP header not set`,{envVar:n,eventType:`mcp_auth_env_header_missing`,header:e}),process.exit(1)),b[e]=a,S.info(`HTTP header loaded from environment`,{eventType:`mcp_auth_env_header`,header:e,remoteUrl:i.url})}}let w=te(b);if(w&&S.setTraceId(w),b.Authorization){let e=b.Authorization.startsWith(`Bearer `)?`bearer_token`:b.Authorization.startsWith(`Basic `)?`basic`:`api_key`;S.info(`Authorization header provided`,{authType:e,eventType:`mcp_auth_header_provided`,remoteUrl:i.url})}let ne={..._.scanner.headers};if(S.debug(`Initializing traffic scanner`,{failOpen:_.scanner.failOpen,hasApiKey:!!_.scanner.apiKey,scannerEnabled:_.scanner.enabled,scannerUrl:_.scanner.url,timeoutMs:_.scanner.timeoutMs}),i._[0]===`remote`){s=`remote`,i[`remote-transport`]&&S.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:i[`remote-transport`]});let e=i.url;if(!e)throw new n(`Remote URL is required for remote proxy type`,`url`);v=d(e),v!==e&&S.debug(`Normalized remote URL`,{normalizedUrl:v,originalUrl:e})}else{if(s=`stdio`,i[`--`]&&i[`--`].length>0){let e=i[`--`];p=e[0],g=e.slice(1).map(String)}else p=i.command,g=(i.args||[]).map(String);if(!p)throw new n(`No command specified for stdio proxy`,`command`)}let T;s===`stdio`&&p&&(T=pt(p,g),T.isContainerMCP&&S.info(`Container MCP detected`,{imageDigests:T.imageDigests,imageName:T.imageName,runtime:T.runtime}));let E;if(_.accessControl.url&&_.scanner.apiKey){let e=await c(),t=s===`stdio`?{...e,proxyType:`stdio`,stdioCliArgs:{args:g,command:p,dockerImageDigests:T?.imageDigests,dockerImageName:T?.imageName,proxyType:`stdio`}}:{...e,proxyType:`remote`,remoteCliArgs:{proxyType:`remote`,url:v}};E=new Re({apiKey:_.scanner.apiKey,headers:_.accessControl.headers,sessionData:t,timeoutMs:_.accessControl.timeoutMs,url:_.accessControl.url})}let se=s===`remote`?v:p,D=new Le({client:E,enabled:_.accessControl.enabled,serverName:se}),O=new Ze({storageDir:_.oauthDir}),k=()=>new t({name:`mcp-gateway`,version:_.appVersion},{capabilities:{}}),A=async t=>{if(!await D.isAllowed()){let t=D.getBlockReason();throw S.warn(`MCP server blocked by access control`,{proxyType:s,reason:t}),new e(t,`policy_block`)}if(S.info(`MCP server allowed by access control`),s===`stdio`){let e={...process.env,...ee},n=new lt({args:g,command:p,env:e,onEvent:e=>{i.debug&&S.debug(`Transport event`,{event:e})},shell:i.shell,stderr:`pipe`}),a=1024;a*8;let o=e=>e.length>a?`${e.slice(0,a)}…`:e,c=``,l=[],u=e=>{let t=o(e);l.push(t),l.length>100&&l.shift(),S.info(`MCP server stderr`,{command:p,eventType:`mcp_server_stderr`,line:t})},d=()=>{c.length!==0&&(u(c),c=``)},f=new me(`utf8`),m=!1,h=()=>{if(m)return;m=!0;let e=f.end();e&&(c+=e),d()};n.stderr?.on(`data`,e=>{process.stderr.write(e),c+=f.write(e);let t=c.split(`
|
|
138
|
+
`);c=t.pop()??``;for(let e of t){if(e.length===0)continue;u(e)}c.length>8192&&d()}),n.stderr?.once(`end`,h),n.stderr?.once(`close`,h);try{return await t.connect(n),t}catch(e){throw h(),S.warn(`Failed original server access`,{command:p,error:e instanceof Error?e.message:String(e),eventType:`mcp_server_access_failed`,proxyType:s,stderrTail:l.slice(-20)}),new r(`Failed to connect to stdio process: ${e}`,void 0,`stdio`,{argCount:g?.length,command:p})}}else if(s===`remote`){let e=v,t=e=>{let t={...b};return e&&(t.Authorization=`Bearer ${e}`),Object.keys(t).length>0?{headers:t}:void 0},n=e=>{if(e instanceof h)return!0;if(e&&typeof e==`object`){let t=e.status,n=e.code,r=e.message;if(t===401||n===401||r&&/unauthorized|401/i.test(String(r)))return!0}return!1},i=async()=>{let t=await $e(e,{credentialStore:O});return S.info(`Authentication performed`,{authType:`oauth`,eventType:`mcp_auth_performed`,fromCache:t.fromCache,remoteUrl:e}),t.tokens.access_token},a;try{let r=await O.load(e),o=r&&O.hasValidAccessToken(r)?r.tokens?.access_token:void 0,s=!1;try{let n=await oe(k,e,t(o));a=n.client,y=n.transportType,S.info(`Connected to remote server`,{hasAuth:!!o,transport:y})}catch(r){if(n(r)){if(s)throw r;o?(S.info(`Cached OAuth token rejected (possibly revoked), invalidating and re-authorizing...`),await O.update(e,{tokens:void 0,tokensObtainedAt:void 0})):S.info(`Server requires OAuth, starting authentication flow...`),o=await i(),s=!0;let n=await oe(k,e,t(o));a=n.client,y=n.transportType,S.info(`Connected to remote server with OAuth`,{transport:y})}else throw r}return a}catch(t){throw S.warn(`Failed original server access`,{error:t instanceof Error?t.message:String(t),eventType:`mcp_server_access_failed`,proxyType:s,remoteUrl:e}),t instanceof r?t:new r(`Failed to connect to remote server: ${t instanceof Error?t.message:String(t)}`,e,y,{headerCount:Object.keys(b).length})}}return t},ce=async()=>{if(i.port){let e=s===`stdio`?{args:g,command:p,dockerImageDigests:T?.imageDigests,dockerImageName:T?.imageName,proxyType:s}:{proxyType:s,url:v};await l({cliArgs:e,scanApiKey:_.scanner.apiKey,scanEnabled:_.scanner.enabled,scanFailOpen:_.scanner.failOpen,scanHeaders:ne,scanTimeoutMs:_.scanner.timeoutMs,scanUrl:_.scanner.url||``});let t,n=await m({createServer:async()=>{let e=k();t=await A(e);let n=t.getServerVersion(),r=t.getServerCapabilities(),i=new a(n,{capabilities:r});return f({authorizer:D,client:t,server:i,serverCapabilities:r}),i},onClose:async e=>{t&&await t.close(),await e.close()},port:i.port});return S.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`http`,port:i.port,proxyType:s}),s===`stdio`?S.info(`MCP server configuration`,{args:g?.join(` `)||``,command:p,eventType:`mcp_server_config`,proxyType:s}):S.info(`MCP server configuration`,{eventType:`mcp_server_config`,proxyType:s,remoteUrl:v}),{close:()=>n.close()}}let e=k(),t=await A(e),n=t.getServerVersion(),r=t.getServerCapabilities(),c=new a(n,{capabilities:r});f({authorizer:D,client:t,server:c,serverCapabilities:r});let u=new o,d=s===`stdio`?{args:g,command:p,dockerImageDigests:T?.imageDigests,dockerImageName:T?.imageName,proxyType:s}:{proxyType:s,url:v};return await l({cliArgs:d,scanApiKey:_.scanner.apiKey,scanEnabled:_.scanner.enabled,scanFailOpen:_.scanner.failOpen,scanHeaders:ne,scanTimeoutMs:_.scanner.timeoutMs,scanUrl:_.scanner.url||``}),await c.connect(u),S.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`stdio`,proxyType:s}),S.info(`MCP server configuration`,{capabilities:Object.keys(r||{}),eventType:`mcp_server_config`,proxyType:s,serverName:n?.name,serverVersion:n?.version,...s===`stdio`?{args:g?.join(` `)||``,command:p}:{remoteUrl:v,transport:y}}),{close:()=>t.close()}},le=({server:e,timeout:t})=>{let n=!1,r=async r=>{if(!n){n=!0,S.info(`MCP gateway stopping`,{eventType:`mcp_gateway_stopping`,signal:r});try{await e.close(),u(),await x(2e3),process.exit(0)}catch(e){let n=`Error during shutdown: ${e}`;S.error(`Error during shutdown`,{error:n,eventType:`mcp_gateway_stopped`,shutdownTimeout:t}),await x(2e3),process.exit(1)}}},i=e=>async()=>{he(()=>{S.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()};S.info(`MCP gateway starting`,{command:p,eventType:`mcp_gateway_starting`,proxyType:s,transport:s===`remote`?`auto-detect`:`stdio`,url:v});try{let e=await ce();le({server:e,timeout:i.gracefulShutdownTimeout})}catch(t){t instanceof e&&(console.error(`
|
|
139
|
+
❌ ACCESS DENIED`),console.error(`━`.repeat(60)),console.error(`
|
|
140
|
+
This MCP server has been blocked by Onyx because it is not authorized by your organization's access control policy. Please contact your administrator if you believe this is an error.
|
|
141
|
+
`),S.error(`MCP server blocked by access control policy`,{error:t.message,reason:t.reason}),await x(2e3),process.exit(1));let n=`Could not start the proxy: ${t}`;S.error(`MCP server failed to start`,{args:g,command:p,error:n,eventType:`mcp_server_start_failed`,proxyType:s,remoteUrl:v,transport:y}),await x(2e3),process.exit(1)}};export{mt as main};
|
|
142
|
+
//# sourceMappingURL=main-f8nUbpFM.js.map
|