@onyxsecurity/mcp-gateway 2.1.103 → 2.1.104
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 +2 -2
- package/dist/{cli-CvXyGrOs.js → cli-DSmVGQ7S.js} +2 -2
- package/dist/{cli-CvXyGrOs.js.map → cli-DSmVGQ7S.js.map} +1 -1
- package/dist/{env-BUBgLqL3.js → env-C2L1gLl2.js} +1 -1
- package/dist/{env-CHslGFcL.js → env-duRz5x3D.js} +2 -2
- package/dist/{env-CHslGFcL.js.map → env-duRz5x3D.js.map} +1 -1
- package/dist/{helpers-DKeE84-I.js → helpers-hq6c0S7B.js} +2 -2
- package/dist/{helpers-DKeE84-I.js.map → helpers-hq6c0S7B.js.map} +1 -1
- package/dist/index.js +1 -1
- package/dist/{logger-BVeblnO_.js → logger-B8xwR0Iw.js} +1 -1
- package/dist/{logger-BFfD4AjT.js → logger-BFCaHmBw.js} +2 -2
- package/dist/{logger-BFfD4AjT.js.map → logger-BFCaHmBw.js.map} +1 -1
- package/dist/{main-Cyg9hzix.js → main-Tw3H8OwF.js} +2 -2
- package/dist/{main-Cyg9hzix.js.map → main-Tw3H8OwF.js.map} +1 -1
- package/dist/oauthProvidersClient-CvXWVRjy.js +1 -0
- package/dist/{oauthProvidersClient-B1DkZb7Y.js → oauthProvidersClient-NJqT0eSr.js} +2 -2
- package/dist/{oauthProvidersClient-B1DkZb7Y.js.map → oauthProvidersClient-NJqT0eSr.js.map} +1 -1
- package/dist/{providers-BCivlFui.js → providers-CnL-Ka67.js} +2 -2
- package/dist/{providers-BCivlFui.js.map → providers-CnL-Ka67.js.map} +1 -1
- package/dist/{proxyFetch-BZE2K5U-.js → proxyFetch-CksCS9LD.js} +2 -2
- package/dist/{proxyFetch-BZE2K5U-.js.map → proxyFetch-CksCS9LD.js.map} +1 -1
- package/dist/{transportDetection-XErTExiO.js → transportDetection-DNZk1GCq.js} +2 -2
- package/dist/{transportDetection-XErTExiO.js.map → transportDetection-DNZk1GCq.js.map} +1 -1
- package/dist/{upstreamNegotiation-3bHVQIRc.js → upstreamNegotiation-B103VR9G.js} +2 -2
- package/dist/{upstreamNegotiation-3bHVQIRc.js.map → upstreamNegotiation-B103VR9G.js.map} +1 -1
- package/package.json +1 -1
- package/dist/oauthProvidersClient-BKKCkI6m.js +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import{proxiedFetch as e}from"./proxyFetch-BZE2K5U-.js";import{AccessControlBlockError as t,ConfigurationError as n,ProtocolEraMismatchError as r,ProxyConnectionError as i,Server as a,StdioServerTransport as o,compressClientInfo as s,errorCodeOf as c,getSessionData as l,initializeTrafficMirror as u,isUsableSerial as d,logRequestCounts as f,messageOf as p,proxyServer as m,redactCliArgs as h,serveStdio as ee,startHTTPServer as g,upstreamVersionNegotiation as te}from"./upstreamNegotiation-3bHVQIRc.js";import{config as _}from"./env-CHslGFcL.js";import{chownToRealUser as v,extractTraceIdFromHeaders as ne,flushLogs as re,gatewayCorrelationId as y,logger as b}from"./logger-BFfD4AjT.js";import{Client as ie,ProtocolError as x,ReadBuffer as ae,UnauthorizedError as oe,createParser as se,normalizeUrl as S,serializeMessage as ce}from"./normalizeUrl-DUUGubD4.js";import{emitKeychainOutcomeLog as le,emitProxySetupLog as ue,hideBin as de,probeOperatorProxyForChild as fe,restoreOperatorProxyEnv as pe,yargs_default as me}from"./helpers-DKeE84-I.js";import"./providers-BCivlFui.js";import{initializeOAuthProviders as he}from"./oauthProvidersClient-B1DkZb7Y.js";import"./pkce-DUsFn3Kw.js";import{connectWithTransportFallback as ge,discoverAuthServer as _e,performOAuthFlow as ve,tryRefreshCachedToken as ye}from"./transportDetection-XErTExiO.js";import{homedir as C}from"node:os";import{isAbsolute as be,join as w}from"node:path";import{createHash as T}from"node:crypto";import{accessSync as xe,constants as E}from"node:fs";import{chmod as Se,mkdir as Ce,readFile as we,rm as Te,writeFile as Ee}from"node:fs/promises";import{execFileSync as D,spawn as O,spawnSync as k}from"node:child_process";import{StringDecoder as De}from"node:string_decoder";import{clearInterval as Oe,setInterval as ke,setTimeout as Ae}from"node:timers";import je from"node:util";import{createInterface as Me}from"node:readline";import{PassThrough as Ne,Transform as Pe}from"node:stream";var A=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(Ie(this),t)}[Symbol.for(`Deno.customInspect`)](e,t){return e(Ie(this),t)}};function Fe(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 Ie(e){return{type:e.type,message:e.message,code:e.code,defaultPrevented:e.defaultPrevented,cancelable:e.cancelable,timeStamp:e.timeStamp}}var Le=e=>{throw TypeError(e)},Re=(e,t,n)=>t.has(e)||Le(`Cannot `+n),M=(e,t,n)=>(Re(e,t,`read from private field`),n?n.call(e):t.get(e)),N=(e,t,n)=>t.has(e)?Le(`Cannot add the same private member more than once`):t instanceof WeakSet?t.add(e):t.set(e,n),P=(e,t,n,r)=>(Re(e,t,`write to private field`),t.set(e,n),n),F=(e,t,n)=>(Re(e,t,`access private method`),n),I,L,R,z,B,V,H,U,W,G,K,q,J,Y,ze,Be,Ve,He,Ue,We,X,Ge,Ke,Z=class extends EventTarget{constructor(e,t){super(),N(this,Y),this.CONNECTING=0,this.OPEN=1,this.CLOSED=2,N(this,I),N(this,L),N(this,R),N(this,z),N(this,B),N(this,V),N(this,H),N(this,U,null),N(this,W),N(this,G),N(this,K,null),N(this,q,null),N(this,J,null),N(this,Be,async e=>{var t;M(this,G).reset();let{body:n,redirected:r,status:i,headers:a}=e;if(i===204){F(this,Y,X).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,Y,X).call(this,`Non-200 status code (${i})`,i);return}if(!(a.get(`content-type`)||``).startsWith(`text/event-stream`)){F(this,Y,X).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,J))==null||t.call(this,o),this.dispatchEvent(o),typeof n!=`object`||!n||!(`getReader`in n)){F(this,Y,X).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,G).feed(s.decode(t,{stream:!e})),e&&(l=!1,M(this,G).reset(),F(this,Y,Ge).call(this))}while(l)}),N(this,Ve,e=>{P(this,W,void 0),!(e.name===`AbortError`||e.type===`aborted`)&&F(this,Y,Ge).call(this,j(e))}),N(this,Ue,e=>{typeof e.id==`string`&&P(this,U,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,q)&&(!e.event||e.event===`message`)&&M(this,q).call(this,t),this.dispatchEvent(t)}),N(this,We,e=>{P(this,V,e)}),N(this,Ke,()=>{P(this,H,void 0),M(this,I)===this.CONNECTING&&F(this,Y,ze).call(this)});try{if(e instanceof URL)P(this,L,e);else if(typeof e==`string`)P(this,L,new URL(e,qe()));else throw Error(`Invalid URL`)}catch{throw Fe(`An invalid or illegal string was specified`)}P(this,G,se({onEvent:M(this,Ue),onRetry:M(this,We)})),P(this,I,this.CONNECTING),P(this,V,3e3),P(this,B,t?.fetch??globalThis.fetch),P(this,z,t?.withCredentials??!1),F(this,Y,ze).call(this)}get readyState(){return M(this,I)}get url(){return M(this,L).href}get withCredentials(){return M(this,z)}get onerror(){return M(this,K)}set onerror(e){P(this,K,e)}get onmessage(){return M(this,q)}set onmessage(e){P(this,q,e)}get onopen(){return M(this,J)}set onopen(e){P(this,J,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,H)&&clearTimeout(M(this,H)),M(this,I)!==this.CLOSED&&(M(this,W)&&M(this,W).abort(),P(this,I,this.CLOSED),P(this,W,void 0))}};I=new WeakMap,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 WeakSet,ze=function(){P(this,I,this.CONNECTING),P(this,W,new AbortController),M(this,B)(M(this,L),F(this,Y,He).call(this)).then(M(this,Be)).catch(M(this,Ve))},Be=new WeakMap,Ve=new WeakMap,He=function(){let e={mode:`cors`,redirect:`follow`,headers:{Accept:`text/event-stream`,...M(this,U)?{"Last-Event-ID":M(this,U)}:void 0},cache:`no-store`,signal:M(this,W)?.signal};return`window`in globalThis&&(e.credentials=this.withCredentials?`include`:`same-origin`),e},Ue=new WeakMap,We=new WeakMap,X=function(e,t){var n;M(this,I)!==this.CLOSED&&P(this,I,this.CLOSED);let r=new A(`error`,{code:t,message:e});(n=M(this,K))==null||n.call(this,r),this.dispatchEvent(r)},Ge=function(e,t){var n;if(M(this,I)===this.CLOSED)return;P(this,I,this.CONNECTING);let r=new A(`error`,{code:t,message:e});(n=M(this,K))==null||n.call(this,r),this.dispatchEvent(r),P(this,H,setTimeout(M(this,Ke),M(this,V)))},Ke=new WeakMap,Z.CONNECTING=0,Z.OPEN=1,Z.CLOSED=2;function qe(){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 Je=class{client;enabled;lastBlockReason;serverName;constructor(e){this.enabled=e.enabled,this.client=e.client,this.serverName=e.serverName,b.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 b.error(`Access control authorization failed with unexpected error`,{error:String(e)}),!0}return b.warn(`No access control client configured, allowing by default`),!0}},Ye=class{clientInfoBase64;config;constructor(e){this.config=e,this.clientInfoBase64=this.getClientInfoBase64(),b.info(`AccessControlClient initialized`,{timeoutMs:e.timeoutMs,url:e.url})}async authorize(){try{let e=await this.sendAuthorizeRequest();return b.debug(`Access control check successful`,{action:e.action}),e}catch(e){return b.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)}}},Xe=class{storageDir;constructor(e){this.storageDir=e.storageDir}async delete(e){let t=S(e),n=this.getFilePath(t);try{await Te(n),b.debug(`Deleted stored credentials`,{filePath:n,serverUrl:t})}catch(e){e.code!==`ENOENT`&&b.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 b.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=S(e),n=this.getFilePath(t);try{let e=await we(n,`utf-8`),r=JSON.parse(e);if(S(r.serverUrl)!==t){b.warn(`Credential file server URL mismatch`,{expected:t,filePath:n,found:r.serverUrl});return}return b.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`){b.debug(`No stored credentials found`,{serverUrl:t});return}b.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 Ee(t,n,{encoding:`utf-8`,mode:384}),await Se(t,384),b.debug(`Saved credentials to disk`,{clientId:e.clientInfo?.client_id,filePath:t,hasTokens:!!e.tokens,serverUrl:e.serverUrl})}catch(n){throw b.error(`Failed to save credentials`,{error:String(n),filePath:t,serverUrl:e.serverUrl}),n}}async update(e,t){let n=S(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 Ce(this.storageDir,{mode:448,recursive:!0})}catch(e){if(e.code!==`EEXIST`)throw e}try{await v(this.storageDir)}catch(e){b.warn(`Failed to fix OAuth storage directory ownership`,{error:String(e),storageDir:this.storageDir})}}generateKey(e){return T(`sha256`).update(e).digest(`hex`).substring(0,16)}getFilePath(e){let t=this.generateKey(e);return w(this.storageDir,`${t}.json`)}};function Ze(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:$e(e),wwwAuthenticate:s.headers.get(`www-authenticate`)??void 0};s.status===401?b.info(`Upstream returned non-2xx (auth challenge)`,n):b.warn(`Upstream returned non-2xx`,n)}if(s.status===401&&o){b.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?(b.info(`Silent refresh succeeded mid-session; retrying request`,{eventType:`mcp_auth_mid_session_refresh_succeeded`}),s=await n(e,a(r))):b.warn(`Silent refresh produced no new bearer; passing 401 through`,{eventType:`mcp_auth_mid_session_refresh_failed`})}return s}}function Qe(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 b.info(`Adopting newer access_token from disk (other process refreshed)`,{eventType:`mcp_auth_disk_bearer_adopted`,serverUrl:e}),r=i,i;let a=await ye(e,t);return a?.tokens.access_token?(r=a.tokens.access_token,r):void 0}finally{i=null}})(),i),setBearer:e=>{r=e}}}function $e(e){try{let t=typeof e==`string`?e:String(e),n=new URL(t);return`${n.origin}${n.pathname}`}catch{return`[unparseable-url]`}}const Q=[`2024-11-05`,`2025-03-26`,`2025-06-18`,`2025-11-25`],et=-32601,tt=new Set([-32004,-32022]),nt=/\binitialize\b/i,rt=/method not found[^\w]*\binitialize\b|\binitialize\b[^\w]*method not found/,it=/unsupported protocol version|protocol version is not supported/,at=e=>RegExp(`${rt.source}|${it.source}`,`i`).test(e);function ot(e,t){let n=`this gateway speaks the handshake era (${Q[0]} … ${Q[Q.length-1]})`;return t===void 0||ct(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 (${p(t)||`no detail given`}); ${n}`}function st(e){let t=p(e),n=c(e);return n!==void 0&&tt.has(n)||n===et&&nt.test(t)?!0:t.length>0&&at(t)}function ct(e){let t=p(e);return c(e)===et&&nt.test(t)?!0:new RegExp(rt.source,`i`).test(t)}const lt=/^(ctx7sk|tvly|sk|pat|gh[posu]|github_pat|glpat|xox[abprs]|AKIA|Bearer)[-_]/i,ut=e=>e.length>=12||lt.test(e),dt=e=>{try{return decodeURIComponent(e)}catch{return``}},ft=e=>{try{return encodeURIComponent(e)}catch{return``}},pt=e=>{try{return new URL(e).origin}catch{return e}},mt=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,dt(e),ft(e)])t&&ut(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)},ht=(e,t)=>{if(!t)return e;let n=pt(t),r=`\0onyx-origin\0`,i=n?e.split(n).join(r):e;for(let e of mt(t)){if(e===n)continue;i=i.split(e).join(`[REDACTED]`)}return i.split(r).join(n)};async function gt(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=Me({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)})}function _t(e){let t=!1,n;return _.logIngest.enabled&&e().then(e=>{if(t)return;let r=e.systemSerialNumber,i=e.deviceName?.trim(),a=d(r)?`serial:${r.trim()}`:i&&i!==`unknown-device`?`hostname:${i}`:void 0;if(!a)return;let o=T(`sha256`).update(a).digest(`hex`),s={system:0,user:0},c=process.hrtime.bigint()-BigInt(Math.round(process.uptime()*1e9)),l=()=>{try{let e=process.cpuUsage(),t=process.hrtime.bigint(),n=Number(t-c)/1e3,r=e.user+e.system-s.user-s.system;if(s=e,c=t,n<=0||r<0)return;b.info(`MCP gateway resource usage`,{event:`mcp_gateway_resources`,gateway_instance_id:y,gateway_metrics:{cpu_percent:100*r/n,instances:1,memory_bytes:process.memoryUsage.rss()},gateway_version:_.appVersion,machine_id:o})}catch{}};l(),n=setInterval(l,6e4),n.unref()}).catch(()=>{}),()=>{t=!0,clearInterval(n)}}const vt=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`]),yt=new Set([`EAI_AGAIN`,`ECONNREFUSED`,`EHOSTDOWN`,`EHOSTUNREACH`,`ENETDOWN`,`ENETUNREACH`,`ENOTFOUND`,`UND_ERR_CONNECT_TIMEOUT`]),bt=/\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,xt=/\bnot connected\b|transport (?:is )?closed/i,St=/session (?:not found|expired|has expired|is invalid|invalid|mismatch|does not|no longer)|no valid session|unknown session|mcp-session-id/i,Ct=/no valid session|unknown session|mcp-session-id|session not found/i;function $(e){return kt(e,new WeakSet)}function wt(e){return At(e,new WeakSet)}function Tt(e){if(e instanceof oe)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 Et(e){if(e instanceof x)return!1;let t=$(e);return t&&yt.has(t)||Ot(e)?!0:xt.test(p(e))}function Dt(e){if(e instanceof t||e instanceof r||st(e)||Tt(e))return!1;let n=$(e);if(n&&vt.has(n)||Ot(e))return!0;let i=wt(e);if(i!==void 0&&i>=500)return!0;let a=p(e);return!!(a.length>0&&bt.test(a))}function Ot(e){let t=p(e);if(e instanceof x)return Ct.test(t);let n=wt(e);return n===404||n===400&&St.test(t)?!0:St.test(t)}function kt(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=kt(e[n],t);if(r)return r}}function At(e,t){if(typeof e!=`object`||!e||t.has(e))return;t.add(e);let n=e instanceof x?[`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=At(e[n],t);if(r!==void 0)return r}}const jt=e=>new Promise(t=>setTimeout(t,e));async function Mt(e,t,n={}){let r=n.isRetryable??Dt,i=n.sleep??jt,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=Nt(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 Nt(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 Pt(e){let t=e.now??Date.now,n=e.initial,r=0,i=-1/0,a=null,o=!1,s=!1,c=[],l=async()=>{b.info(`Upstream connection lost mid-session; reconnecting`,{eventType:`mcp_upstream_reconnect_attempt`}),s&&b.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(()=>{}),b.info(`Upstream reconnected`,{eventType:`mcp_upstream_reconnect_succeeded`}),!0}catch(e){return b.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)&&!Dt(a))throw a;if(await u(i)&&(e||Et(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 Ft=class extends Pe{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(`
|
|
1
|
+
import{proxiedFetch as e}from"./proxyFetch-CksCS9LD.js";import{AccessControlBlockError as t,ConfigurationError as n,ProtocolEraMismatchError as r,ProxyConnectionError as i,Server as a,StdioServerTransport as o,compressClientInfo as s,errorCodeOf as c,getSessionData as l,initializeTrafficMirror as u,isUsableSerial as d,logRequestCounts as f,messageOf as p,proxyServer as m,redactCliArgs as h,serveStdio as ee,startHTTPServer as g,upstreamVersionNegotiation as te}from"./upstreamNegotiation-B103VR9G.js";import{config as _}from"./env-duRz5x3D.js";import{chownToRealUser as v,extractTraceIdFromHeaders as ne,flushLogs as re,gatewayCorrelationId as y,logger as b}from"./logger-BFCaHmBw.js";import{Client as ie,ProtocolError as x,ReadBuffer as ae,UnauthorizedError as oe,createParser as se,normalizeUrl as S,serializeMessage as ce}from"./normalizeUrl-DUUGubD4.js";import{emitKeychainOutcomeLog as le,emitProxySetupLog as ue,hideBin as de,probeOperatorProxyForChild as fe,restoreOperatorProxyEnv as pe,yargs_default as me}from"./helpers-hq6c0S7B.js";import"./providers-CnL-Ka67.js";import{initializeOAuthProviders as he}from"./oauthProvidersClient-NJqT0eSr.js";import"./pkce-DUsFn3Kw.js";import{connectWithTransportFallback as ge,discoverAuthServer as _e,performOAuthFlow as ve,tryRefreshCachedToken as ye}from"./transportDetection-DNZk1GCq.js";import{homedir as C}from"node:os";import{isAbsolute as be,join as w}from"node:path";import{createHash as T}from"node:crypto";import{accessSync as xe,constants as E}from"node:fs";import{chmod as Se,mkdir as Ce,readFile as we,rm as Te,writeFile as Ee}from"node:fs/promises";import{execFileSync as D,spawn as O,spawnSync as k}from"node:child_process";import{StringDecoder as De}from"node:string_decoder";import{clearInterval as Oe,setInterval as ke,setTimeout as Ae}from"node:timers";import je from"node:util";import{createInterface as Me}from"node:readline";import{PassThrough as Ne,Transform as Pe}from"node:stream";var A=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(Ie(this),t)}[Symbol.for(`Deno.customInspect`)](e,t){return e(Ie(this),t)}};function Fe(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 Ie(e){return{type:e.type,message:e.message,code:e.code,defaultPrevented:e.defaultPrevented,cancelable:e.cancelable,timeStamp:e.timeStamp}}var Le=e=>{throw TypeError(e)},Re=(e,t,n)=>t.has(e)||Le(`Cannot `+n),M=(e,t,n)=>(Re(e,t,`read from private field`),n?n.call(e):t.get(e)),N=(e,t,n)=>t.has(e)?Le(`Cannot add the same private member more than once`):t instanceof WeakSet?t.add(e):t.set(e,n),P=(e,t,n,r)=>(Re(e,t,`write to private field`),t.set(e,n),n),F=(e,t,n)=>(Re(e,t,`access private method`),n),I,L,R,z,B,V,H,U,W,G,K,q,J,Y,ze,Be,Ve,He,Ue,We,X,Ge,Ke,Z=class extends EventTarget{constructor(e,t){super(),N(this,Y),this.CONNECTING=0,this.OPEN=1,this.CLOSED=2,N(this,I),N(this,L),N(this,R),N(this,z),N(this,B),N(this,V),N(this,H),N(this,U,null),N(this,W),N(this,G),N(this,K,null),N(this,q,null),N(this,J,null),N(this,Be,async e=>{var t;M(this,G).reset();let{body:n,redirected:r,status:i,headers:a}=e;if(i===204){F(this,Y,X).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,Y,X).call(this,`Non-200 status code (${i})`,i);return}if(!(a.get(`content-type`)||``).startsWith(`text/event-stream`)){F(this,Y,X).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,J))==null||t.call(this,o),this.dispatchEvent(o),typeof n!=`object`||!n||!(`getReader`in n)){F(this,Y,X).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,G).feed(s.decode(t,{stream:!e})),e&&(l=!1,M(this,G).reset(),F(this,Y,Ge).call(this))}while(l)}),N(this,Ve,e=>{P(this,W,void 0),!(e.name===`AbortError`||e.type===`aborted`)&&F(this,Y,Ge).call(this,j(e))}),N(this,Ue,e=>{typeof e.id==`string`&&P(this,U,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,q)&&(!e.event||e.event===`message`)&&M(this,q).call(this,t),this.dispatchEvent(t)}),N(this,We,e=>{P(this,V,e)}),N(this,Ke,()=>{P(this,H,void 0),M(this,I)===this.CONNECTING&&F(this,Y,ze).call(this)});try{if(e instanceof URL)P(this,L,e);else if(typeof e==`string`)P(this,L,new URL(e,qe()));else throw Error(`Invalid URL`)}catch{throw Fe(`An invalid or illegal string was specified`)}P(this,G,se({onEvent:M(this,Ue),onRetry:M(this,We)})),P(this,I,this.CONNECTING),P(this,V,3e3),P(this,B,t?.fetch??globalThis.fetch),P(this,z,t?.withCredentials??!1),F(this,Y,ze).call(this)}get readyState(){return M(this,I)}get url(){return M(this,L).href}get withCredentials(){return M(this,z)}get onerror(){return M(this,K)}set onerror(e){P(this,K,e)}get onmessage(){return M(this,q)}set onmessage(e){P(this,q,e)}get onopen(){return M(this,J)}set onopen(e){P(this,J,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,H)&&clearTimeout(M(this,H)),M(this,I)!==this.CLOSED&&(M(this,W)&&M(this,W).abort(),P(this,I,this.CLOSED),P(this,W,void 0))}};I=new WeakMap,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 WeakSet,ze=function(){P(this,I,this.CONNECTING),P(this,W,new AbortController),M(this,B)(M(this,L),F(this,Y,He).call(this)).then(M(this,Be)).catch(M(this,Ve))},Be=new WeakMap,Ve=new WeakMap,He=function(){let e={mode:`cors`,redirect:`follow`,headers:{Accept:`text/event-stream`,...M(this,U)?{"Last-Event-ID":M(this,U)}:void 0},cache:`no-store`,signal:M(this,W)?.signal};return`window`in globalThis&&(e.credentials=this.withCredentials?`include`:`same-origin`),e},Ue=new WeakMap,We=new WeakMap,X=function(e,t){var n;M(this,I)!==this.CLOSED&&P(this,I,this.CLOSED);let r=new A(`error`,{code:t,message:e});(n=M(this,K))==null||n.call(this,r),this.dispatchEvent(r)},Ge=function(e,t){var n;if(M(this,I)===this.CLOSED)return;P(this,I,this.CONNECTING);let r=new A(`error`,{code:t,message:e});(n=M(this,K))==null||n.call(this,r),this.dispatchEvent(r),P(this,H,setTimeout(M(this,Ke),M(this,V)))},Ke=new WeakMap,Z.CONNECTING=0,Z.OPEN=1,Z.CLOSED=2;function qe(){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 Je=class{client;enabled;lastBlockReason;serverName;constructor(e){this.enabled=e.enabled,this.client=e.client,this.serverName=e.serverName,b.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 b.error(`Access control authorization failed with unexpected error`,{error:String(e)}),!0}return b.warn(`No access control client configured, allowing by default`),!0}},Ye=class{clientInfoBase64;config;constructor(e){this.config=e,this.clientInfoBase64=this.getClientInfoBase64(),b.info(`AccessControlClient initialized`,{timeoutMs:e.timeoutMs,url:e.url})}async authorize(){try{let e=await this.sendAuthorizeRequest();return b.debug(`Access control check successful`,{action:e.action}),e}catch(e){return b.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)}}},Xe=class{storageDir;constructor(e){this.storageDir=e.storageDir}async delete(e){let t=S(e),n=this.getFilePath(t);try{await Te(n),b.debug(`Deleted stored credentials`,{filePath:n,serverUrl:t})}catch(e){e.code!==`ENOENT`&&b.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 b.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=S(e),n=this.getFilePath(t);try{let e=await we(n,`utf-8`),r=JSON.parse(e);if(S(r.serverUrl)!==t){b.warn(`Credential file server URL mismatch`,{expected:t,filePath:n,found:r.serverUrl});return}return b.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`){b.debug(`No stored credentials found`,{serverUrl:t});return}b.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 Ee(t,n,{encoding:`utf-8`,mode:384}),await Se(t,384),b.debug(`Saved credentials to disk`,{clientId:e.clientInfo?.client_id,filePath:t,hasTokens:!!e.tokens,serverUrl:e.serverUrl})}catch(n){throw b.error(`Failed to save credentials`,{error:String(n),filePath:t,serverUrl:e.serverUrl}),n}}async update(e,t){let n=S(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 Ce(this.storageDir,{mode:448,recursive:!0})}catch(e){if(e.code!==`EEXIST`)throw e}try{await v(this.storageDir)}catch(e){b.warn(`Failed to fix OAuth storage directory ownership`,{error:String(e),storageDir:this.storageDir})}}generateKey(e){return T(`sha256`).update(e).digest(`hex`).substring(0,16)}getFilePath(e){let t=this.generateKey(e);return w(this.storageDir,`${t}.json`)}};function Ze(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:$e(e),wwwAuthenticate:s.headers.get(`www-authenticate`)??void 0};s.status===401?b.info(`Upstream returned non-2xx (auth challenge)`,n):b.warn(`Upstream returned non-2xx`,n)}if(s.status===401&&o){b.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?(b.info(`Silent refresh succeeded mid-session; retrying request`,{eventType:`mcp_auth_mid_session_refresh_succeeded`}),s=await n(e,a(r))):b.warn(`Silent refresh produced no new bearer; passing 401 through`,{eventType:`mcp_auth_mid_session_refresh_failed`})}return s}}function Qe(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 b.info(`Adopting newer access_token from disk (other process refreshed)`,{eventType:`mcp_auth_disk_bearer_adopted`,serverUrl:e}),r=i,i;let a=await ye(e,t);return a?.tokens.access_token?(r=a.tokens.access_token,r):void 0}finally{i=null}})(),i),setBearer:e=>{r=e}}}function $e(e){try{let t=typeof e==`string`?e:String(e),n=new URL(t);return`${n.origin}${n.pathname}`}catch{return`[unparseable-url]`}}const Q=[`2024-11-05`,`2025-03-26`,`2025-06-18`,`2025-11-25`],et=-32601,tt=new Set([-32004,-32022]),nt=/\binitialize\b/i,rt=/method not found[^\w]*\binitialize\b|\binitialize\b[^\w]*method not found/,it=/unsupported protocol version|protocol version is not supported/,at=e=>RegExp(`${rt.source}|${it.source}`,`i`).test(e);function ot(e,t){let n=`this gateway speaks the handshake era (${Q[0]} … ${Q[Q.length-1]})`;return t===void 0||ct(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 (${p(t)||`no detail given`}); ${n}`}function st(e){let t=p(e),n=c(e);return n!==void 0&&tt.has(n)||n===et&&nt.test(t)?!0:t.length>0&&at(t)}function ct(e){let t=p(e);return c(e)===et&&nt.test(t)?!0:new RegExp(rt.source,`i`).test(t)}const lt=/^(ctx7sk|tvly|sk|pat|gh[posu]|github_pat|glpat|xox[abprs]|AKIA|Bearer)[-_]/i,ut=e=>e.length>=12||lt.test(e),dt=e=>{try{return decodeURIComponent(e)}catch{return``}},ft=e=>{try{return encodeURIComponent(e)}catch{return``}},pt=e=>{try{return new URL(e).origin}catch{return e}},mt=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,dt(e),ft(e)])t&&ut(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)},ht=(e,t)=>{if(!t)return e;let n=pt(t),r=`\0onyx-origin\0`,i=n?e.split(n).join(r):e;for(let e of mt(t)){if(e===n)continue;i=i.split(e).join(`[REDACTED]`)}return i.split(r).join(n)};async function gt(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=Me({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)})}function _t(e){let t=!1,n;return _.logIngest.enabled&&e().then(e=>{if(t)return;let r=e.systemSerialNumber,i=e.deviceName?.trim(),a=d(r)?`serial:${r.trim()}`:i&&i!==`unknown-device`?`hostname:${i}`:void 0;if(!a)return;let o=T(`sha256`).update(a).digest(`hex`),s={system:0,user:0},c=process.hrtime.bigint()-BigInt(Math.round(process.uptime()*1e9)),l=()=>{try{let e=process.cpuUsage(),t=process.hrtime.bigint(),n=Number(t-c)/1e3,r=e.user+e.system-s.user-s.system;if(s=e,c=t,n<=0||r<0)return;b.info(`MCP gateway resource usage`,{event:`mcp_gateway_resources`,gateway_instance_id:y,gateway_metrics:{cpu_percent:100*r/n,instances:1,memory_bytes:process.memoryUsage.rss()},gateway_version:_.appVersion,machine_id:o})}catch{}};l(),n=setInterval(l,6e4),n.unref()}).catch(()=>{}),()=>{t=!0,clearInterval(n)}}const vt=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`]),yt=new Set([`EAI_AGAIN`,`ECONNREFUSED`,`EHOSTDOWN`,`EHOSTUNREACH`,`ENETDOWN`,`ENETUNREACH`,`ENOTFOUND`,`UND_ERR_CONNECT_TIMEOUT`]),bt=/\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,xt=/\bnot connected\b|transport (?:is )?closed/i,St=/session (?:not found|expired|has expired|is invalid|invalid|mismatch|does not|no longer)|no valid session|unknown session|mcp-session-id/i,Ct=/no valid session|unknown session|mcp-session-id|session not found/i;function $(e){return kt(e,new WeakSet)}function wt(e){return At(e,new WeakSet)}function Tt(e){if(e instanceof oe)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 Et(e){if(e instanceof x)return!1;let t=$(e);return t&&yt.has(t)||Ot(e)?!0:xt.test(p(e))}function Dt(e){if(e instanceof t||e instanceof r||st(e)||Tt(e))return!1;let n=$(e);if(n&&vt.has(n)||Ot(e))return!0;let i=wt(e);if(i!==void 0&&i>=500)return!0;let a=p(e);return!!(a.length>0&&bt.test(a))}function Ot(e){let t=p(e);if(e instanceof x)return Ct.test(t);let n=wt(e);return n===404||n===400&&St.test(t)?!0:St.test(t)}function kt(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=kt(e[n],t);if(r)return r}}function At(e,t){if(typeof e!=`object`||!e||t.has(e))return;t.add(e);let n=e instanceof x?[`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=At(e[n],t);if(r!==void 0)return r}}const jt=e=>new Promise(t=>setTimeout(t,e));async function Mt(e,t,n={}){let r=n.isRetryable??Dt,i=n.sleep??jt,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=Nt(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 Nt(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 Pt(e){let t=e.now??Date.now,n=e.initial,r=0,i=-1/0,a=null,o=!1,s=!1,c=[],l=async()=>{b.info(`Upstream connection lost mid-session; reconnecting`,{eventType:`mcp_upstream_reconnect_attempt`}),s&&b.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(()=>{}),b.info(`Upstream reconnected`,{eventType:`mcp_upstream_reconnect_succeeded`}),!0}catch(e){return b.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)&&!Dt(a))throw a;if(await u(i)&&(e||Et(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 Ft=class extends Pe{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
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
3
|
`)}\n`;n(null,Buffer.from(e))}else n(null,null)}logDroppedLine(e){if(!(this.droppedLinesLogged>50)){if(this.droppedLinesLogged===50){this.droppedLinesLogged+=1,b.info(`Suppressing further non-JSON stdout lines`,{eventType:`mcp_server_stdout_dropped_suppressed`,loggedSoFar:50});return}this.droppedLinesLogged+=1,b.info(`MCP server stdout (non-JSON, dropped)`,{eventType:`mcp_server_stdout_dropped`,line:e.length>1024?`${e.slice(0,1024)}…`:e})}}},It=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 ae;_serverParams;_spawnedAt;_spawnedPid;_stderrStream=null;onEvent;constructor(e){this._serverParams=e,(e.stderr===`pipe`||e.stderr===`overlapped`)&&(this._stderrStream=new Ne),this.onEvent=e.onEvent}async close(){if(this.onEvent?.({type:`close`}),this._process?.pid)try{if(process.platform===`win32`){let e=k(`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){b.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=ce(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?Lt(this._serverParams.command):this._serverParams.command,a=r?(this._serverParams.args??[]).map(Lt):this._serverParams.args??[];this._process=O(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}b.error(`Process spawn error`,{args:this._serverParams.args?h(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,b.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;b[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=>{b.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 Ft;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=>{b.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{}b.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 Lt(e){return e.length===0||!/[\s"&|<>^()]/.test(e)?e:`"${e.replace(/"/g,`""`).replace(/(\\+)$/,`$1$1`)}"`}const Rt=[`$`,"`",`;`,`|`,`&`,`>`,`<`,`(`,`)`,`{`,`}`,`'`,`"`,`\\`,`!`,`*`,`?`,`~`,`#`],zt=`[a-z0-9]+`,Bt=`${zt}(?:(?:[._]|__|-+)${zt})*`,Vt=`(?:[a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9-]*[a-zA-Z0-9])`,Ht=`(?:${`(?:${`${Vt}(?:\\.${Vt})*`}|\\[[a-fA-F0-9:]+\\])(?::[0-9]+)?`}/)?${Bt}(?:/${Bt})*`,Ut=RegExp(`^${Ht}(?::[A-Za-z0-9_][A-Za-z0-9_.-]{0,127})?(?:@[a-z0-9]+(?:[.+_-][a-z0-9]+)*:[0-9a-fA-F]{32,})?$`);function Wt(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}:Ut.test(e)?{valid:!0}:{reason:Gt(e),valid:!1}}function Gt(e){if(/[\u0000-\u001f\u007f]/.test(e))return`contains a control character`;if(/\s/.test(e))return`contains whitespace`;let t=Rt.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 Kt(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 qt(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 Jt(e,t){let n=Kt(e);if(n===`unknown`)return{imageName:``,isContainerMCP:!1,runtime:`unknown`};if(!t||!t.includes(`run`))return{imageName:``,isContainerMCP:!1,runtime:n};let r=qt(t);return r?{imageName:r,isContainerMCP:!0,runtime:n}:(b.debug(`Container command detected but could not extract image name`,{args:t,command:e,runtime:n}),{imageName:``,isContainerMCP:!0,runtime:n})}function Yt(e,t){let n=t===`unknown`?`docker`:t,r=Wt(e);if(!r.valid)return b.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=D(n,[`image`,`inspect`,`--format`,`{{json .RepoDigests}}`,e],{encoding:`utf-8`,stdio:[`pipe`,`pipe`,`pipe`],timeout:5e3})}catch(t){return b.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 b.warn(`Could not parse RepoDigests JSON`,{eventType:`mcp_container_image_digest_lookup_failed`,imageName:e,result:a,runtime:n}),[]}if(!Array.isArray(o))return b.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?(b.info(`Container image digests resolved`,{digests:c,eventType:`mcp_container_image_digests_resolved`,imageName:e,runtime:n}),c):(b.info(`No container image digests available (image may be locally built)`,{eventType:`mcp_container_image_digests_empty`,imageName:e,runtime:n}),[])}const Xt=/^[0-9a-f]{64}$/,Zt=new Set([`java`,`javaw`]),Qt=new Set([`--class-path`,`--classpath`,`-classpath`,`-cp`]),$t=(e,t)=>{let n=(e.trim().split(/[/\\]/).pop()??``).toLowerCase().replace(/\.(?:exe|cmd|bat)$/,``);if(!Zt.has(n))return!1;let r=t.findIndex(e=>Qt.has(e.toLowerCase()));return r===-1||r+1>=t.length?!1:!t.slice(0,r).some(e=>e.toLowerCase()===`-jar`)},en=()=>{let e=_.scanner.binPath?.trim(),t=process.platform===`win32`?`onyx-scanner.exe`:`onyx-scanner`,n=C();return[...e?[e]:[],w(n,`.claude`,`onyx`,t),w(n,`.cursor`,`onyx`,t),w(n,`.codex`,`onyx`,t),w(n,`.copilot`,`onyx`,t),w(n,`.config`,`opencode`,`plugin`,`onyx`,t),w(n,`.openclaw`,`onyx`,t),w(n,`.openclaw`,`extensions`,`onyx-guard`,`onyx`,t)]};let tn;const nn=()=>{if(tn!==void 0)return tn??void 0;for(let e of en()){if(!be(e)){b.warn(`Skipping a non-absolute onyx-scanner path; it must not be resolved through PATH`,{candidate:e,eventType:`mcp_file_fingerprint_scanner_path_not_absolute`});continue}try{return xe(e,E.X_OK),tn=e,e}catch{}}tn=null},rn=(e,t)=>{if(!e)return;if($t(e,t)){b.debug(`Class-path JVM launch: version comes from the command, sending no file hash`,{eventType:`mcp_file_fingerprint_classpath_skipped`});return}let n=nn();if(!n){b.debug(`No onyx-scanner found; sending no file content hash`,{eventType:`mcp_file_fingerprint_scanner_missing`});return}let r;try{r=D(n,[`mcp-fingerprint`],{encoding:`utf-8`,input:JSON.stringify({args:t,command:e}),stdio:[`pipe`,`pipe`,`pipe`],timeout:_.scanner.fingerprintTimeoutMs})}catch(e){b.warn(`File content fingerprint lookup failed; sending no hash`,{error:e instanceof Error?e.message:String(e),eventType:`mcp_file_fingerprint_failed`,scanner:n});return}let i;try{i=JSON.parse(r)}catch{b.warn(`File content fingerprint output was not JSON; sending no hash`,{eventType:`mcp_file_fingerprint_unparseable`,scanner:n});return}let a=i.file_content_hash?.trim().toLowerCase();if(!a){b.debug(`No file content hash for this server`,{eventType:`mcp_file_fingerprint_absent`,source:i.source});return}if(!Xt.test(a)){b.warn(`File content fingerprint was not a sha256; sending no hash`,{eventType:`mcp_file_fingerprint_malformed`,length:a.length});return}return b.debug(`Resolved file content hash`,{eventType:`mcp_file_fingerprint_resolved`,fileContentHash:a,source:i.source}),a};let an;const on=()=>({pid:an?.spawnedServerPid,startedAtMs:an?.spawnedServerStartedAt});je.inspect.defaultOptions.depth=8,`EventSource`in global||(global.EventSource=Z);const sn=async e=>{b.error(e.logMessage,e.meta),await new Promise(t=>{process.stderr.write(`${e.stderrLine}\n`,()=>t())}),e.respondToClient&&await gt(e.reason);let t=ke(()=>{},50);try{await re(2e3)}catch{}finally{Oe(t)}process.exit(e.exitCode)},cn=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 sn({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}`})},ln=e=>{let t=p(e.error),n=pt(e.subject),i=t=>ht(t,e.url),a=i(t),o=Object.fromEntries(Object.entries(e.extra??{}).map(([e,t])=>[e,typeof t==`string`?i(pt(t)):t]));throw b.error(e.logMessage,{eventType:`mcp_protocol_era_mismatch`,originalError:a,supportedEra:`${Q[0]}..${Q[Q.length-1]}`,...o}),new r(i(ot(n,e.error)),e.url,{originalError:a,...o})},un=async()=>{ue(b),le(b);let e=await me(de(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 tool calls 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 he(_.oauthProviders);let s,c=!1,d,p,v,y,x={},ae={};if(e.env)for(let t of e.env){let[e,...n]=t.split(`=`);e&&n.length>0&&(ae[e.trim()]=n.join(`=`).trim())}let oe=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&&(x[e.trim()]=n.join(`:`).trim())}if(e.bearerTokenEnv){let t=e.bearerTokenEnv,{missingVar:n,resolved:r}=oe(t);n&&await cn({envVar:n,eventType:`mcp_auth_bearer_env_missing`,logMessage:`Bearer token env var specified but not set`,respondToClient:!e.port}),x.Authorization=`Bearer ${r}`,b.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}=oe(i);r&&await cn({envVar:r,eventType:`mcp_auth_env_header_missing`,header:t,logMessage:`Env var for HTTP header not set`,respondToClient:!e.port}),x[t]=a,b.info(`HTTP header loaded from environment`,{eventType:`mcp_auth_env_header`,header:t,remoteUrl:e.url})}}let se=ne(x);if(se&&b.setTraceId(se),x.Authorization){let t=x.Authorization.startsWith(`Bearer `)?`bearer_token`:x.Authorization.startsWith(`Basic `)?`basic`:`api_key`;b.info(`Authorization header provided`,{authType:t,eventType:`mcp_auth_header_provided`,remoteUrl:e.url})}let ce={..._.scanner.headers};b.debug(`Initializing traffic scanner`,{failOpen:_.scanner.failOpen,hasApiKey:!!_.scanner.apiKey,scannerEnabled:_.scanner.enabled,scannerUrl:_.scanner.url,timeoutMs:_.scanner.timeoutMs});let ye=async a=>{let o=!e.port&&!c,l=v?(()=>{try{return new URL(v).origin}catch{return`[invalid remote URL]`}})():void 0,u=e=>v&&l?e.split(v).join(l):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
4
|
`);return sn({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 f=u(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${l?` at ${l}`:``} — ${a.message}`:`Onyx MCP gateway: failed to start — ${a instanceof Error?a.message:String(a)}`);return sn({exitCode:1,logMessage:`MCP server failed to start`,meta:{args:p?h(p):void 0,command:d,errno:$(a),error:u(`Could not start the proxy: ${a}`),eventType:`mcp_server_start_failed`,proxyType:s,remoteUrl:l,transport:y},reason:f,respondToClient:o,stderrLine:`[mcp-gateway] FATAL: ${f}`})};if(e._[0]===`remote`){s=`remote`,e[`remote-transport`]&&b.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`)),v=S(t),v!==t&&b.debug(`Normalized remote URL`,{normalizedUrl:v,originalUrl:t})}else{if(s=`stdio`,e[`--`]&&e[`--`].length>0){let t=e[`--`];d=t[0],p=t.slice(1).map(String)}else d=e.command,p=(e.args||[]).map(String);d||await ye(new n(`No command specified for stdio proxy`,`command`))}let C;s===`stdio`&&d&&(C=Jt(d,p),C.isContainerMCP&&b.info(`Container MCP detected`,{imageName:C.imageName,runtime:C.runtime}));let be,w,T=async()=>{w??=l(),b.setSessionData({...await w,proxyType:s})},xe=async()=>{be!==void 0||!C?.isContainerMCP||!C.imageName||(await T(),be=Yt(C.imageName,C.runtime))},E,Se=!1,Ce=()=>Se||s!==`stdio`||!d?E:(Se=!0,E=rn(d,p??[]),E),we=()=>s===`stdio`?{args:p,command:d,dockerImageDigests:be,dockerImageName:C?.imageName,fileContentHash:Ce(),proxyType:s}:{proxyType:s,url:v},Te;if(_.accessControl.url&&_.scanner.apiKey){let e=we();await T();let t=await w,n=e.proxyType===`stdio`?{...t,fileContentHash:e.fileContentHash,proxyType:`stdio`,stdioCliArgs:{...e,args:h(e.args)}}:{...t,proxyType:`remote`,remoteCliArgs:e};Te=new Ye({apiKey:_.scanner.apiKey,headers:_.accessControl.headers,sessionData:n,timeoutMs:_.accessControl.timeoutMs,url:_.accessControl.url})}let Ee=s===`remote`?v:d,D=new Je({client:Te,enabled:_.accessControl.enabled,serverName:Ee}),O=new Xe({storageDir:_.oauthDir}),k=()=>new ie({name:`mcp-gateway`,version:_.appVersion},{capabilities:{},versionNegotiation:te()}),Oe=async(n,{allowInteractiveAuth:a=!0}={})=>{if(!await D.isAllowed()){let e=D.getBlockReason();throw b.warn(`MCP server blocked by access control`,{proxyType:s,reason:e}),new t(e,`policy_block`)}if(b.info(`MCP server allowed by access control`),await xe(),s===`stdio`){let t=await fe(process.env);if(t.proxyHost!==void 0){let e=t.reachability===`unreachable`;b.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={...pe(process.env,t.reachability),...ae},a=new It({args:p,command:d,env:r,onEvent:t=>{e.debug&&b.debug(`Transport event`,{event:t})},shell:e.shell,stderr:`pipe`});an=a;let o=1024;o*8;let c=e=>e.length>o?`${e.slice(0,o)}…`:e,l=``,u=[],f=e=>{let t=c(e);u.push(t),u.length>100&&u.shift(),b.info(`MCP server stderr`,{command:d,eventType:`mcp_server_stderr`,line:t})},m=()=>{l.length!==0&&(f(l),l=``)},h=new De(`utf8`),ee=!1,g=()=>{if(ee)return;ee=!0;let e=h.end();e&&(l+=e),m()};a.stderr?.on(`data`,e=>{process.stderr.write(e),l+=h.write(e);let t=l.split(`
|
|
5
5
|
`);l=t.pop()??``;for(let e of t){if(e.length===0)continue;f(e)}l.length>8192&&m()}),a.stderr?.once(`end`,g),a.stderr?.once(`close`,g);try{return await n.connect(a),n}catch(e){throw g(),b.warn(`Failed original server access`,{command:d,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(()=>{}),st(e)&&ln({error:e,extra:{command:d},logMessage:`Spawned MCP server speaks a different protocol era; cannot negotiate a session`,subject:d??`the spawned MCP server`}),new i(`Failed to connect to stdio process: ${e}`,void 0,`stdio`,{argCount:p?.length,command:d},e)}}else if(s===`remote`){let e=v,t=()=>{let e={...x};return Object.keys(e).length>0?{headers:e}:void 0},n=async()=>{let t=await ve(e,{credentialStore:O});return b.info(`Authentication performed`,{authType:`oauth`,eventType:`mcp_auth_performed`,fromCache:t.fromCache,remoteUrl:e}),t.tokens.access_token},o;try{let r=await O.load(e),i=r&&O.hasValidAccessToken(r)?r.tokens?.access_token:void 0,s=Qe(e,O,i),c=Ze(s),l=!1;try{let n=await ge(k,e,t(),c);o=n.client,y=n.transportType,b.info(`Connected to remote server`,{hasAuth:!!i,transport:y})}catch(r){if(st(r)&&ln({error:r,extra:{remoteUrl:e},logMessage:`Upstream speaks a different MCP protocol era; cannot negotiate a session`,subject:e,url:e}),Tt(r)){if(l)throw r;if(s.getCurrentBearer()??i?(b.info(`Cached + refresh both rejected; falling back to full OAuth flow`),await O.update(e,{tokensObtainedAt:void 0})):b.info(`Server requires OAuth, starting authentication flow...`),!a)throw b.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 ge(k,e,t(),c);o=d.client,y=d.transportType,b.info(`Connected to remote server with OAuth`,{transport:y})}else if(!l&&!(s.getCurrentBearer()??i)&&!new Headers(x).has(`Authorization`)){let i=!1,u;try{let{authMetadata:t}=await _e(new URL(e),{logger:b});i=!!t}catch(e){u=e instanceof Error?e.message:String(e)}if(!i)throw b.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(b.info(`Cold-start non-401 but server advertises OAuth; attempting OAuth flow`,{originalError:r instanceof Error?r.message:String(r)}),!a)throw b.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 ge(k,e,t(),c);o=f.client,y=f.transportType,b.info(`Connected to remote server with OAuth (recovered from non-401)`,{transport:y})}else throw r}return o}catch(t){throw b.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:(st(t)&&ln({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,y,{headerCount:Object.keys(x).length},t))}}return n},ke=()=>Mt(()=>Oe(k()),_.upstream.connect,{onRetry:({attempt:e,delayMs:t,error:n})=>{b.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})}}),je=s===`remote`?_.upstream.reconnect.enabled:_.upstream.reconnect.enabledForStdio,Me=e=>je?Pt({cooldownMs:_.upstream.reconnect.cooldownMs,initial:e,reconnect:()=>Oe(k(),{allowInteractiveAuth:!1})}):e,Ne,Pe=()=>(Ne??=u({cliArgs:we(),scanApiKey:_.scanner.apiKey,scanEnabled:_.scanner.enabled,scanFailOpen:_.scanner.failOpen,scanHeaders:ce,scanTimeoutMs:_.scanner.timeoutMs,scanUrl:_.scanner.url||``,spawnedServerInfoProvider:on}),Ne),A=e=>{b.info(`Upstream protocol era negotiated`,{era:e.getProtocolEra(),eventType:`mcp_upstream_era_negotiated`,negotiation:_.supportNewMcpProtocol?`auto`:`legacy`,protocolVersion:e.getNegotiatedProtocolVersion()})},Fe=async()=>{if(e.port){let t,n=await g({createServer:async()=>{let e=await ke();A(e),await Pe();let n=e.getServerVersion(),r=e.getServerCapabilities();t=Me(e);let i=new a(n,{capabilities:r});return m({authorizer:D,client:t,server:i,serverCapabilities:r}),i},onClose:async e=>{t&&await t.close(),await e.close()},port:e.port});return b.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`http`,port:e.port,proxyType:s}),s===`stdio`?b.info(`MCP server configuration`,{args:h(p??[]).join(` `),command:d,eventType:`mcp_server_config`,proxyType:s}):b.info(`MCP server configuration`,{eventType:`mcp_server_config`,proxyType:s,remoteUrl:v}),{close:()=>n.close()}}let t=await ke();A(t);let n=t.getServerVersion(),r=t.getServerCapabilities(),i=Me(t),l=new a(n,{capabilities:r});m({authorizer:D,client:i,server:l,serverCapabilities:r}),await Pe();let u=()=>{b.info(`MCP gateway started`,{eventType:`mcp_gateway_started`,mode:`stdio`,proxyType:s}),b.info(`MCP server configuration`,{capabilities:Object.keys(r||{}),eventType:`mcp_server_config`,proxyType:s,serverName:n?.name,serverVersion:n?.version,...s===`stdio`?{args:h(p??[]).join(` `),command:d}:{remoteUrl:v,transport:y}})};if(_.supportNewMcpProtocol){let e=ee(()=>l,{legacy:`serve`});return c=!0,u(),{close:async()=>{await e.close(),await i.close()}}}let f=new o;return await l.connect(f),c=!0,u(),{close:()=>i.close()}},j=({server:e,stopResourceMetrics:t,timeout:n})=>{let r=!1,i=async i=>{if(!r){r=!0,t(),b.info(`MCP gateway stopping`,{eventType:`mcp_gateway_stopping`,signal:i});try{await e.close(),f(),await re(2e3),process.exit(0)}catch(e){let t=`Error during shutdown: ${e}`;b.error(`Error during shutdown`,{error:t,eventType:`mcp_gateway_stopped`,shutdownTimeout:n}),await re(2e3),process.exit(1)}}},a=e=>async()=>{Ae(()=>{b.error(`Graceful shutdown timeout exceeded, forcing exit`),process.exit(1)},n).unref(),await i(e)};return process.once(`SIGTERM`,a(`SIGTERM`)),process.once(`SIGINT`,a(`SIGINT`)),process.stdin.once(`end`,a(`stdin-end`)),()=>e.close()};b.info(`MCP gateway starting`,{command:d,eventType:`mcp_gateway_starting`,proxyType:s,transport:s===`remote`?`auto-detect`:`stdio`,url:v});try{let t=await Fe();j({server:t,stopResourceMetrics:_t(()=>w??=l()),timeout:e.gracefulShutdownTimeout})}catch(e){await ye(e)}};export{un as main};
|
|
6
|
-
//# sourceMappingURL=main-
|
|
6
|
+
//# sourceMappingURL=main-Tw3H8OwF.js.map
|