@agimon-ai/po-mcp-proxy 0.0.1-alpha.2 → 0.0.1-alpha.21

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.
@@ -1,72 +0,0 @@
1
- import{existsSync as e}from"node:fs";import t,{dirname as n,isAbsolute as r,join as i,resolve as a}from"node:path";import{createCipheriv as o,createDecipheriv as s,createHash as c,randomBytes as l,randomUUID as u,timingSafeEqual as d}from"node:crypto";import{createServer as f}from"node:http";import{access as p,chmod as m,lstat as h,mkdir as g,mkdtemp as _,open as v,readFile as y,readdir as b,rename as x,rm as S,stat as C,unlink as w,utimes as ee,watch as te,writeFile as T}from"node:fs/promises";import{homedir as E,tmpdir as ne}from"node:os";import{spawn as D}from"node:child_process";import{fileURLToPath as re}from"node:url";import{PROCESS_REGISTRY_OWNER_ID_ENV_VAR as ie,PROCESS_REGISTRY_OWNER_KIND_ENV_VAR as ae,ProcessRegistryService as oe,createProcessLease as se,resolveSiblingRegistryPath as ce}from"@agimon-ai/foundation-process-registry";import*as le from"js-yaml";import{z as O}from"zod";import{METHOD_NOT_FOUND as ue,ProtocolError as de,Server as fe,createMcpHandler as pe}from"@modelcontextprotocol/server";import{PortRegistryService as me}from"@agimon-ai/foundation-port-registry";import{createNodeTelemetry as he}from"@agimon-ai/po-logsink/telemetry/node";import{setTimeout as ge}from"node:timers/promises";import{Client as _e,ProtocolError as ve,ProtocolErrorCode as ye,SSEClientTransport as be,StreamableHTTPClientTransport as xe,UnauthorizedError as Se,isCallToolResult as Ce}from"@modelcontextprotocol/client";import{StdioClientTransport as we}from"@modelcontextprotocol/client/stdio";import{AsyncLocalStorage as Te}from"node:async_hooks";import{AjvJsonSchemaValidator as Ee}from"@modelcontextprotocol/client/validators/ajv";import{once as De}from"node:events";import{inspect as Oe,promisify as ke}from"node:util";import{getRequestListener as Ae}from"@hono/node-server";import{toNodeHandler as je}from"@modelcontextprotocol/node";import{Hono as Me}from"hono";import{Liquid as Ne}from"liquidjs";import{coerceArgs as Pe,formatZodError as Fe,jsonSchemaToZod as Ie}from"@agimon-ai/foundation-validator";import{serveStdio as Le}from"@modelcontextprotocol/server/stdio";const Re=[`pnpm-workspace.yaml`,`nx.json`,`.git`];function k(n=process.env.PROJECT_PATH||process.cwd()){let r=t.resolve(n);for(;;){for(let n of Re)if(e(t.join(r,n)))return r;let i=t.dirname(r);if(i===r)return t.resolve(n);r=i}}const ze=`host.json`,A=`.reserved`,j=`.result`,Be=6e4;function Ve(e){try{return process.kill(e,0),!0}catch(e){return e.code===`EPERM`}}function He(e){return e.replace(/[^\x20-\x7E]/g,``).slice(0,200)}function Ue(){return i(E(),`.mcp-proxy`,`callbacks`)}var We=class e{root;isPidAlive;constructor(e={}){this.root=e.root??Ue(),this.isPidAlive=e.isPidAlive??Ve}directoryFor(e){return i(this.root,String(e))}static keyFor(e){return c(`sha256`).update(e,`utf8`).digest(`hex`)}async ensureDirectory(e){let t=this.directoryFor(e);return await g(t,{recursive:!0,mode:448}),t}async publish(e,t,n){let r=i(e,`.${t}.${l(6).toString(`hex`)}`);await T(r,JSON.stringify(n),{encoding:`utf-8`,mode:384});try{await x(r,i(e,t))}catch(e){throw await S(r,{force:!0}).catch(()=>void 0),e}}async readJson(e){try{return JSON.parse(await y(e,`utf-8`))}catch{return}}async claimHost(e){let t=await this.ensureDirectory(e),n={pid:process.pid,startedAt:(/* @__PURE__ */ new Date()).toISOString()};await this.publish(t,ze,n)}async releaseHost(e){await S(i(this.directoryFor(e),ze),{force:!0}).catch(()=>void 0)}async readHost(e){let t=await this.readJson(i(this.directoryFor(e),ze));if(t&&typeof t.pid==`number`)return this.isPidAlive(t.pid)?t:void 0}async reserve(t,n){let r=await this.ensureDirectory(t),i={pid:process.pid};await this.publish(r,`${e.keyFor(n)}${A}`,i)}async heartbeat(t,n){let r=i(this.directoryFor(t),`${e.keyFor(n)}${A}`),a=/* @__PURE__ */ new Date;await ee(r,a,a).catch(()=>void 0)}async release(t,n){let r=e.keyFor(n),a=this.directoryFor(t);await Promise.all([S(i(a,`${r}${A}`),{force:!0}).catch(()=>void 0),S(i(a,`${r}${j}`),{force:!0}).catch(()=>void 0)])}async hasReservation(t,n){let r=i(this.directoryFor(t),`${e.keyFor(n)}${A}`);return this.isReservationLive(r)}async hasLiveReservations(e){let t=this.directoryFor(e),n;try{n=await b(t)}catch{return!1}for(let e of n)if(e.endsWith(A)&&await this.isReservationLive(i(t,e)))return!0;return!1}async isReservationLive(e){let t=await this.readJson(e);if(!t||typeof t.pid!=`number`||!this.isPidAlive(t.pid))return!1;try{let t=await C(e);return Date.now()-t.mtimeMs<Be}catch{return!1}}async bank(t,n,r){let i=await this.ensureDirectory(t),a=r.status===`denied`?{status:`denied`,error:He(r.error)}:r;await this.publish(i,`${e.keyFor(n)}${j}`,a)}async takeResult(t,n){let r=i(this.directoryFor(t),`${e.keyFor(n)}${j}`),a=await this.readJson(r);if(a&&typeof a.status==`string`)return await S(r,{force:!0}).catch(()=>void 0),a}async collectGarbage(e){let t=this.directoryFor(e),n;try{n=await b(t)}catch{return}for(let e of n){if(e.endsWith(A)){if(!await this.isReservationLive(i(t,e))){await S(i(t,e),{force:!0}).catch(()=>void 0);let n=e.slice(0,-9);await S(i(t,`${n}${j}`),{force:!0}).catch(()=>void 0)}continue}if(!e.endsWith(j))continue;let n=e.slice(0,-7);await this.isReservationLive(i(t,`${n}${A}`))||await S(i(t,e),{force:!0}).catch(()=>void 0)}}};const Ge=19876,Ke=100;function qe(e){let t=c(`sha256`).update(e).digest();return Ge+t.readUInt16BE(0)%100}const Je=`/callback`,Ye=3e5,Xe=6e4,Ze=250,M={"content-type":`text/html; charset=utf-8`};function Qe(e){return`Authorization failed: ${e}`}function N(e,t){return`<!doctype html><meta charset="utf-8"><title>${e}</title><body style="font-family:system-ui;padding:2rem"><h1>${e}</h1><p>${t}</p></body>`}function $e(e){return e?.code===`EADDRINUSE`}function et(e){return new Promise(t=>{setTimeout(t,e).unref?.()})}var tt=class{server;boundPort;requestedPort;guestPort;closing=!1;listening;pending=/* @__PURE__ */ new Map;path;rendezvous;pollIntervalMs;bindWaitMs;constructor(e=Je){let t=typeof e==`string`?{path:e}:e;this.path=t.path??`/callback`,this.rendezvous=new We(t),this.pollIntervalMs=t.pollIntervalMs??250,this.bindWaitMs=t.bindWaitMs??6e4}getPort(){return this.boundPort}getRedirectPort(){return this.boundPort??this.guestPort}hasPendingAuthorizations(){return this.pending.size>0}async listen(e){let t=this.listening;if(t){if(t.port===e)return t.promise;await t.promise.catch(()=>void 0)}let n=this.acquire(e);this.listening={port:e,promise:n};try{return await n}finally{this.listening?.promise===n&&(this.listening=void 0)}}async acquire(e){let t=this.getRedirectPort();if(t!==void 0){if(e!==0&&e!==t){if(this.hasPendingAuthorizations())throw Error(`OAuth callback server is bound to port ${t} with an authorization in progress; cannot rebind to ${e}.`);await this.close()}else if(this.server||this.guestPort!==void 0)return t}let n=Date.now()+this.bindWaitMs;for(;;)try{return await this.bind(e)}catch(t){if(e===0||!$e(t))throw t;if(await this.rendezvous.readHost(e))return this.guestPort=e,e;if(Date.now()>=n)throw Error(`OAuth callback port ${e} is held by another process that cannot forward callbacks. Waited ${Math.round(this.bindWaitMs/1e3)}s for it to be released. Finish or cancel the other authorization, or set this server's oauth.redirectUri to a different port.`);await et(this.pollIntervalMs)}}async bind(e){let t=f((t,n)=>{this.handleRequest(t.url??`/`,e,n)});await new Promise((n,r)=>{t.once(`error`,r),t.listen(e,`127.0.0.1`,()=>{t.removeListener(`error`,r),n()})});let n=t.address();if(n===null||typeof n==`string`)throw t.close(),Error(`OAuth callback server failed to report a bound port.`);return t.unref(),this.server=t,this.boundPort=n.port,this.requestedPort=e,this.guestPort=void 0,e!==0&&(await this.rendezvous.claimHost(this.boundPort).catch(()=>void 0),await this.rendezvous.collectGarbage(this.boundPort).catch(()=>void 0),await this.adoptOwnReservations(this.boundPort)),this.boundPort}async adoptOwnReservations(e){for(let[t,n]of this.pending)n.guest&&(n.guest.poll&&clearTimeout(n.guest.poll),n.guest=void 0,await this.rendezvous.release(e,t).catch(()=>void 0))}async handleRequest(e,t,n){let r=new URL(e,`http://localhost:${this.boundPort??t}`);if(r.pathname!==this.path){n.writeHead(404,M).end(N(`Not found`,`Unexpected callback path.`));return}let i=r.searchParams.get(`state`)??``,a=r.searchParams.get(`error`),o=r.searchParams.get(`code`),s=r.searchParams.get(`iss`),c=a?{status:`denied`,error:a}:o?{status:`ok`,code:o,...s===null?{}:{iss:s}}:{status:`malformed`};if(this.pending.has(i)){this.settleOutcome(i,c),this.respond(n,c);return}let l=this.boundPort;l!==void 0&&i&&await this.rendezvous.hasReservation(l,i)?(await this.rendezvous.bank(l,i,c).catch(()=>void 0),this.respond(n,c)):n.writeHead(400,M).end(N(`Invalid request`,`This authorization request is not recognised.`))}respond(e,t){if(t.status===`ok`){e.writeHead(200,M).end(N(`Authorized`,`You can close this window and return to your terminal.`));return}let n=t.status===`denied`?`You can close this window.`:`No authorization code was returned.`;e.writeHead(400,M).end(N(`Authorization failed`,n))}settleOutcome(e,t){if(t.status===`ok`){this.settle(e,{code:t.code,state:e,...t.iss===void 0?{}:{iss:t.iss}});return}let n=t.status===`denied`?Qe(t.error):`Authorization response did not include a code.`;this.settle(e,void 0,Error(n))}async reserve(e,t=Ye){if(this.pending.has(e))throw Error(`An authorization with this state is already pending.`);let n=this.server?void 0:this.guestPort;n!==void 0&&await this.rendezvous.reserve(n,e);let r=this.register(e,t);n!==void 0&&(r.guest={port:n,poll:void 0},this.scheduleGuestPoll(e,r))}waitForCallback(e,t=Ye){let n=this.pending.get(e);if(n)return n.claimed?Promise.reject(/* @__PURE__ */ Error(`An authorization with this state is already pending.`)):(n.claimed=!0,n.promise);if(!this.server&&this.guestPort!==void 0)return Promise.reject(/* @__PURE__ */ Error(`This process does not own the OAuth callback port; reserve the state before waiting on it.`));let r=this.register(e,t);return r.claimed=!0,r.promise}register(e,t){let n,r=new Promise((r,i)=>{let a=setTimeout(()=>{this.abandon(e,Error(this.timeoutMessage(e,t)))},t);a.unref?.(),n={resolve:r,reject:i,timer:a}});return n.promise=r,r.catch(()=>void 0),this.pending.set(e,n),n}timeoutMessage(e,t){let n=Math.round(t/1e3);return this.pending.get(e)?.guest?`Timed out after ${n}s waiting for the OAuth redirect. Another process was receiving it and may have exited; reload the redirect page in your browser or start the authorization again.`:`Timed out after ${n}s waiting for the OAuth redirect.`}cancel(e){this.abandon(e,/* @__PURE__ */ Error(`Authorization cancelled.`))}async abandon(e,t){let n=this.pending.get(e)?.guest;this.settle(e,void 0,t),n&&await this.rendezvous.release(n.port,e).catch(()=>void 0)}settle(e,t,n){let r=this.pending.get(e);r&&(clearTimeout(r.timer),r.guest?.poll&&clearTimeout(r.guest.poll),this.pending.delete(e),n?r.reject(n):t&&r.resolve(t),this.releaseWhenIdle())}scheduleGuestPoll(e,t){let n=t.guest;if(!n)return;let r=setTimeout(()=>{this.pollAsGuest(e)},this.pollIntervalMs);r.unref?.(),n.poll=r}async tryPromote(e){if(this.server)return!0;let t=this.listening;if(t)return await t.promise.catch(()=>void 0),this.server!==void 0;let n=this.bind(e);this.listening={port:e,promise:n};try{return await n,!0}catch{return!1}finally{this.listening?.promise===n&&(this.listening=void 0)}}async pollAsGuest(e){let t=this.pending.get(e),n=t?.guest;if(!t||!n)return;let r=await this.rendezvous.takeResult(n.port,e).catch(()=>void 0);r?(this.settleOutcome(e,r),await this.rendezvous.release(n.port,e).catch(()=>void 0)):(await this.tryPromote(n.port),this.pending.get(e)?.guest&&(await this.rendezvous.heartbeat(n.port,e).catch(()=>void 0),this.scheduleGuestPoll(e,t)))}async releaseWhenIdle(){if(this.closing||!this.server||this.pending.size>0||this.requestedPort===0)return;let e=this.boundPort;e!==void 0&&await this.rendezvous.hasLiveReservations(e).catch(()=>!1)||this.closing||!this.server||this.pending.size>0||await this.close()}async close(){this.closing=!0;try{for(let e of Array.from(this.pending.keys()))await this.abandon(e,/* @__PURE__ */ Error(`OAuth callback server shut down.`));let e=this.server,t=this.boundPort;if(this.server=void 0,this.boundPort=void 0,this.requestedPort=void 0,this.guestPort=void 0,t!==void 0&&await this.rendezvous.releaseHost(t).catch(()=>void 0),!e)return;await new Promise(t=>{e.close(()=>t())})}finally{this.closing=!1}}};let P,F=0;function nt(){return P??=new tt,P}function rt(){return F+=1,nt()}async function it(){F>0&&--F,!(F>0)&&(P?.hasPendingAuthorizations()||await at())}async function at(){let e=P;P=void 0,F=0,await e?.close()}function ot(e){return e?.access_token}function I(e,t){return e.replace(/\/$/,``)===t.replace(/\/$/,``)}var st=class{serverName;serverUrl;store;callbackServer;config;logger;callbackPort;callbackTimeoutMs;onAuthorizationUrl;pendingState;authorizationCancelled=!1;pendingCallback;flowCodeVerifier;flowClientInformation;flowDiscoveryState;flowTokenFingerprint;constructor(e){this.serverName=e.serverName,this.serverUrl=e.serverUrl,this.store=e.store,this.callbackServer=e.callbackServer,this.config=e.config??{},this.logger=e.logger,this.callbackPort=e.callbackPort??19876,this.callbackTimeoutMs=e.callbackTimeoutMs,this.onAuthorizationUrl=e.onAuthorizationUrl}get redirectUrl(){return this.config.grantType===`client_credentials`?void 0:this.config.redirectUri?this.config.redirectUri:this.callbackServer.redirectUri?.()||`http://127.0.0.1:${this.callbackPort>0?this.callbackPort:this.callbackServer.getPort()??19876}${Je}`}get clientMetadata(){let e=this.config.grantType===`client_credentials`,t=e?[]:[this.redirectUrl];return{client_name:this.config.clientName??`mcp-proxy`,...this.config.clientUri?{client_uri:this.config.clientUri}:{},redirect_uris:t,grant_types:e?[`client_credentials`]:[`authorization_code`,`refresh_token`],response_types:e?[]:[`code`],token_endpoint_auth_method:this.config.clientSecret?`client_secret_post`:`none`,...this.config.scope?{scope:this.config.scope}:{}}}state(){return this.pendingState=l(32).toString(`hex`),this.pendingState}async clientInformation(e){if(this.config.clientId)return{client_id:this.config.clientId,...this.config.clientSecret?{client_secret:this.config.clientSecret}:{},...e?{issuer:e.issuer}:{}};if(this.flowClientInformation&&(!e||!this.flowClientInformation.issuer||I(this.flowClientInformation.issuer,e.issuer)))return this.flowClientInformation;let t=(await this.readBoundEntry())?.clientInformation;return e&&t?.issuer&&!I(t.issuer,e.issuer)?void 0:t}async saveClientInformation(e,t){if(t&&e.issuer&&!I(e.issuer,t.issuer))throw Error(`OAuth client information issuer does not match the discovered issuer.`);this.flowClientInformation=e,await this.mergeEntry({clientInformation:e})}async tokens(e){let t=(await this.readBoundEntry())?.tokens;return e&&t?.issuer&&!I(t.issuer,e.issuer)?void 0:t}async saveTokens(e,t){if(t&&e.issuer&&!I(e.issuer,t.issuer))throw Error(`OAuth token issuer does not match the discovered issuer.`);this.flowCodeVerifier=void 0,await this.mergeEntry({tokens:e,codeVerifier:void 0})}async saveDiscoveryState(e){this.flowDiscoveryState=e,await this.mergeEntry({discoveryState:e})}async discoveryState(){return this.flowDiscoveryState??(await this.readBoundEntry())?.discoveryState}async saveCodeVerifier(e){this.flowCodeVerifier=e,await this.mergeEntry({codeVerifier:e})}async codeVerifier(){if(this.flowCodeVerifier)return this.flowCodeVerifier;let e=await this.readBoundEntry();if(!e?.codeVerifier)throw Error(`No PKCE code verifier stored for MCP server "${this.serverName}"; restart the authorization.`);return e.codeVerifier}async redirectToAuthorization(e){this.assertAuthorizationActive();let t=this.pendingState;if(!t)throw Error(`No authorization state was reserved for MCP server "${this.serverName}".`);try{if(this.flowTokenFingerprint=ot((await this.readBoundEntry())?.tokens),this.assertAuthorizationActive(),await this.callbackServer.listen(this.callbackPort),this.assertAuthorizationActive(),await this.callbackServer.reserve(t,this.callbackTimeoutMs),this.authorizationCancelled&&this.callbackServer.cancel(t),this.assertAuthorizationActive(),this.pendingCallback=this.callbackServer.waitForCallback(t,this.callbackTimeoutMs),this.pendingCallback.catch(()=>void 0),this.onAuthorizationUrl){await this.onAuthorizationUrl(e,this.serverName),this.assertAuthorizationActive();return}this.logger?.info(`[oauth] Authorize MCP server "${this.serverName}" by visiting: ${e.toString()}`)}catch(e){throw this.cancelAuthorization(),e}}cancelAuthorization(){this.authorizationCancelled=!0,this.pendingState&&this.callbackServer.cancel(this.pendingState),this.pendingCallback=void 0,this.pendingState=void 0}assertAuthorizationActive(){if(this.authorizationCancelled)throw Error(`Authorization cancelled.`)}async waitForAuthorizationCode(){return(await this.waitForAuthorizationCallback()).get(`code`)}async waitForAuthorizationCallback(){let e=this.pendingCallback,t=this.pendingState;if(!e)throw Error(`No authorization is in progress for MCP server "${this.serverName}".`);let n=this.watchForPeerAuthorization();try{let r=await Promise.race([e,n.result]);if(r.state!==t)throw Error(`OAuth callback state mismatch.`);let i=new URLSearchParams({code:r.code,state:r.state});return r.iss!==void 0&&i.set(`iss`,r.iss),i}catch(e){throw t&&this.callbackServer.cancel(t),e}finally{n.stop(),this.pendingCallback=void 0,this.pendingState=void 0}}watchForPeerAuthorization(){let e,t=!1,n=()=>{t=!0,e&&clearTimeout(e)},r=new Promise((n,r)=>{let i=this.flowTokenFingerprint,a=async()=>{if(t)return;let e=ot((await this.readBoundEntry().catch(()=>void 0))?.tokens);e!==void 0&&e!==i?r(/* @__PURE__ */ Error(`MCP server "${this.serverName}" was authorized by another session; reconnect to use the shared credentials.`)):o()},o=()=>{t||(e=setTimeout(()=>void a(),1e3),e.unref?.())};o()});return r.catch(()=>void 0),{result:r,stop:n}}hasPendingAuthorization(){return this.pendingCallback!==void 0}prepareTokenRequest(e){if(this.config.grantType!==`client_credentials`)return;let t=new URLSearchParams({grant_type:`client_credentials`}),n=e??this.config.scope;return n&&t.set(`scope`,n),t}async invalidateCredentials(e){e===`all`||e===`client`?(this.flowClientInformation=void 0,this.flowCodeVerifier=void 0,this.flowDiscoveryState=void 0,await this.store.clear(this.serverName)):e===`tokens`?await this.mergeEntry({tokens:void 0}):(e===`verifier`&&(this.flowCodeVerifier=void 0,await this.mergeEntry({codeVerifier:void 0})),e===`discovery`&&(this.flowDiscoveryState=void 0,await this.mergeEntry({discoveryState:void 0})))}async readBoundEntry(){let e=await this.store.read(this.serverName);if(e){if(e.serverUrl!==this.serverUrl)this.logger?.warn(`[oauth] Stored credentials for "${this.serverName}" were issued for a different URL and were ignored.`);else{if(!this.registrationMatchesRedirect(e)){this.logger?.warn(`[oauth] The stored client registration for "${this.serverName}" names a different redirect URI and will be replaced.`);let{clientInformation:t,...n}=e;return n}return e}}}registrationMatchesRedirect(e){let t=e.clientInformation&&`redirect_uris`in e.clientInformation?e.clientInformation.redirect_uris:void 0;if(!Array.isArray(t)||t.length===0)return!0;let n=this.redirectUrl;return n===void 0||t.includes(n)}async mergeEntry(e){let t=await this.readBoundEntry()??{};await this.store.write(this.serverName,{...t,...e,serverUrl:this.serverUrl})}};function ct(){return i(E(),`.mcp-proxy`,`oauth`)}function lt(e){return`sha256-${c(`sha256`).update(e,`utf8`).digest(`hex`)}`}function ut(e,t){let n=l(12),r=o(`aes-256-gcm`,t,n),i=Buffer.concat([r.update(JSON.stringify(e),`utf8`),r.final()]);return{version:1,iv:n.toString(`base64`),tag:r.getAuthTag().toString(`base64`),ciphertext:i.toString(`base64`)}}function dt(e,t){let n=JSON.parse(e);if(!n||typeof n!=`object`||!(`version`in n)||n.version!==1||!(`iv`in n)||typeof n.iv!=`string`||!(`tag`in n)||typeof n.tag!=`string`||!(`ciphertext`in n)||typeof n.ciphertext!=`string`)throw Error(`Invalid encrypted OAuth credential format.`);let r=Buffer.from(n.iv,`base64`),i=Buffer.from(n.tag,`base64`);if(r.length!==12||i.length!==16)throw Error(`Invalid OAuth credential nonce or tag.`);let a=s(`aes-256-gcm`,t,r);a.setAuthTag(i);let o=JSON.parse(Buffer.concat([a.update(Buffer.from(n.ciphertext,`base64`)),a.final()]).toString(`utf8`));if(!o||typeof o!=`object`||Array.isArray(o))throw Error(`Invalid OAuth credential entry.`);return o}var ft=class{baseDir;fallback=new pt;unavailable=!1;constructor(e=ct()){this.baseDir=e}pathFor(e){return i(this.baseDir,`${lt(e)}.json`)}async key(){await g(this.baseDir,{recursive:!0,mode:448});let e=await h(this.baseDir);if(!e.isDirectory()||e.uid!==process.getuid?.())throw Error(`OAuth credential directory is not owned by this user.`);await m(this.baseDir,448);let t=i(this.baseDir,`key.bin`),n;try{n=await v(t,`wx`,384),await n.writeFile(l(32)),await n.close(),n=void 0}catch(e){if(n&&await n.close(),e.code!==`EEXIST`)throw e}let r=await h(t);if(!r.isFile()||r.isSymbolicLink()||r.uid!==process.getuid?.()||r.mode&63)throw Error(`OAuth encryption key is not an owner-only regular file.`);let a=await y(t);if(a.length!==32)throw Error(`Invalid OAuth encryption key.`);let o=await h(t);if(o.ino!==r.ino||o.mode&63)throw Error(`OAuth encryption key changed during read.`);return a}async read(e){let t=await this.fallback.read(e);if(t)return t;if(!this.unavailable)try{let t=await this.key(),n=this.pathFor(e),r=await h(n);if(!r.isFile()||r.isSymbolicLink()||r.uid!==process.getuid?.()||r.mode&63)throw Error(`OAuth credential file is not owner-only.`);let i=await y(n,`utf8`),a=await h(n);return a.ino!==r.ino||a.mode&63?void 0:dt(i,t)}catch{return}}async write(e,t){if(this.unavailable)await this.fallback.write(e,t);else try{let n=await this.key(),r=this.pathFor(e),a=i(this.baseDir,`.${lt(e)}-${l(12).toString(`hex`)}.tmp`),o=await v(a,`wx`,384);try{await o.writeFile(JSON.stringify(ut(t,n)))}catch(e){throw await o.close(),await S(a,{force:!0}),e}await o.close();try{await x(a,r)}catch(e){throw await S(a,{force:!0}),e}await this.fallback.clear(e)}catch{this.unavailable=!0,await this.fallback.write(e,t)}}async clear(e){await this.fallback.clear(e);try{await S(this.pathFor(e),{force:!0})}catch{}}},pt=class{entries=/* @__PURE__ */ new Map;async read(e){return this.entries.get(e)}async write(e,t){this.entries.set(e,t)}async clear(e){this.entries.delete(e)}};async function mt(e,t,n){let r=await e.read(t);if(r&&r.serverUrl===n)return r}function ht(e){return typeof e.auth==`object`&&e.auth?.type===`api-key`?`api-key`:e.auth===!1||e.oauth===!1?e.bearerToken||e.bearerTokenEnv?`bearer`:`none`:e.auth===`bearer`||e.bearerToken||e.bearerTokenEnv?`bearer`:e.auth===`oauth`?`oauth`:Object.keys(e.headers??{}).some(e=>gt.test(e))?`none`:`oauth`}const gt=/authorization|api[-_]?key|token|secret|cookie/i;function _t(e){return e.bearerTokenEnv?process.env[e.bearerTokenEnv]:e.bearerToken}function vt(e){if(ht(e.config)!==`oauth`)return;let t=e.config.oauth===!1?void 0:e.config.oauth;return new st({serverName:e.serverName,serverUrl:e.config.url,store:e.store??new ft,callbackServer:e.callbackServer??nt(),config:t,logger:e.logger,callbackPort:yt(e.config,e.workspaceRoot),callbackTimeoutMs:e.callbackTimeoutMs,onAuthorizationUrl:e.onAuthorizationUrl})}function yt(e,t=k()){let n=e.oauth===!1?void 0:e.oauth;if(n?.redirectUri){let e=Number.parseInt(new URL(n.redirectUri).port,10);return Number.isFinite(e)&&e>0?e:qe(t)}return qe(t)}function L(e,t=process.env){return e.replace(/\$\{([^}]+)\}/g,(e,n)=>{let r=t[n];return r===void 0?`\${${n}}`:r})}function R(e,t){if(typeof e==`string`)return L(e,t);if(Array.isArray(e))return e.map(e=>R(e,t));if(typeof e==`object`&&e){let n={};for(let[r,i]of Object.entries(e))n[r]=R(i,t);return n}return e}const bt=[/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\./,/^224\./,/^240\./,/^localhost$/i,/^.*\.localhost$/i,/^\[::\]/,/^\[::1\]/,/^\[0:0:0:0:0:0:0:1\]/,/^\[0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:1\]/i,/^\[fe80:/i,/^\[fc00:/i,/^\[fd00:/i,/^\[::ffff:127\./i,/^\[::ffff:7f[0-9a-f]{2}:/i,/^\[::ffff:10\./i,/^\[::ffff:a[0-9a-f]{2}:/i,/^\[::ffff:172\.(1[6-9]|2\d|3[01])\./i,/^\[::ffff:ac1[0-9a-f]:/i,/^\[::ffff:192\.168\./i,/^\[::ffff:c0a8:/i,/^\[::ffff:169\.254\./i,/^\[::ffff:a9fe:/i,/^\[::ffff:0\./i,/^\[::127\./i,/^\[::7f[0-9a-f]{2}:/i,/^\[::10\./i,/^\[::a[0-9a-f]{2}:/i,/^\[::192\.168\./i,/^\[::c0a8:/i];function xt(e,t){let n=t?.allowPrivateIPs??!1,r=t?.enforceHttps??!0,i;try{i=new URL(e)}catch{throw Error(`Invalid URL format: ${e}`)}let a=i.protocol.replace(`:`,``);if(r&&a!==`https`)throw Error(`HTTPS is required for security. URL uses '${a}://'. Set security.enforceHttps: false to allow HTTP.`);if(a!==`http`&&a!==`https`)throw Error(`Invalid URL protocol '${a}://'. Only http:// and https:// are allowed.`);if(!n){let e=i.hostname.toLowerCase();if(bt.some(t=>t.test(e)))throw Error(`Private IP addresses and localhost are blocked for security (${e}). Set security.allowPrivateIPs: true to allow internal networks.`)}}function St(e,t=process.env){let n=L(e.url,t);if(xt(n,e.security),e.validation){if(e.validation.url&&!new RegExp(e.validation.url).test(n))throw Error(`Remote config URL "${n}" does not match validation pattern: ${e.validation.url}`);if(e.validation.headers&&Object.keys(e.validation.headers).length>0){if(!e.headers){let t=Object.keys(e.validation.headers);throw Error(`Remote config is missing required headers: ${t.join(`, `)}`)}for(let[n,r]of Object.entries(e.validation.headers)){if(!(n in e.headers))throw Error(`Remote config is missing required header: ${n}`);let i=L(e.headers[n],t);if(!new RegExp(r).test(i))throw Error(`Remote config header "${n}" value "${i}" does not match validation pattern: ${r}`)}}}}const Ct=O.object({name:O.string(),description:O.string(),folder:O.string().optional()}),wt=O.object({skill:Ct.optional()}),Tt=O.object({instruction:O.string().optional(),toolBlacklist:O.array(O.string()).optional(),omitToolDescription:O.boolean().optional(),prompts:O.record(O.string(),wt).optional()}).optional(),Et=O.object({command:O.string(),args:O.array(O.string()).optional(),env:O.record(O.string(),O.string()).optional(),cwd:O.string().optional(),disabled:O.boolean().optional(),instruction:O.string().optional(),timeout:O.number().positive().optional(),requestTimeout:O.number().positive().optional(),config:Tt}),Dt=O.union([O.literal(!1),O.object({grantType:O.enum([`authorization_code`,`client_credentials`]).optional(),clientId:O.string().optional(),clientSecret:O.string().optional(),scope:O.string().optional(),redirectUri:O.string().optional(),clientName:O.string().optional(),clientUri:O.string().optional()})]).optional(),Ot=O.discriminatedUnion(`mode`,[O.strictObject({type:O.literal(`api-key`),mode:O.literal(`bearer`)}),O.strictObject({type:O.literal(`api-key`),mode:O.literal(`header`),name:O.string().regex(/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/).max(128)})]),kt={auth:O.union([O.literal(`oauth`),O.literal(`bearer`),O.literal(!1),Ot]).optional(),bearerToken:O.string().optional(),bearerTokenEnv:O.string().optional(),oauth:Dt},At=O.object({...kt,url:O.string().url(),headers:O.record(O.string(),O.string()).optional(),type:O.enum([`http`,`sse`]).optional(),disabled:O.boolean().optional(),instruction:O.string().optional(),timeout:O.number().positive().optional(),requestTimeout:O.number().positive().optional(),config:Tt}),jt=O.union([Et,At]),Mt=O.object({url:O.string().optional(),headers:O.record(O.string(),O.string()).optional()}).optional(),Nt=O.object({allowPrivateIPs:O.boolean().optional(),enforceHttps:O.boolean().optional()}).optional(),Pt=O.object({url:O.string(),headers:O.record(O.string(),O.string()).optional(),validation:Mt,security:Nt,mergeStrategy:O.enum([`local-priority`,`remote-priority`,`merge-deep`]).optional()}),Ft=O.object({paths:O.array(O.string())}),It=O.union([O.boolean(),O.object({maxBytes:O.number().int().positive().optional(),maxLines:O.number().int().positive().optional(),structuredMaxBytes:O.number().int().positive().optional()})]).optional(),Lt=O.object({type:O.enum([`stdio`,`http`,`sse`,`stdio-http`]).optional(),port:O.number().int().positive().optional(),host:O.string().optional(),keepAlive:O.boolean().optional(),outputGuard:It}).optional(),Rt=O.object({id:O.string().optional(),proxy:Lt,mcpServers:O.record(O.string(),jt),remoteConfigs:O.array(Pt).optional(),skills:Ft.optional()}),zt=O.object({command:O.string(),args:O.array(O.string()).optional(),env:O.record(O.string(),O.string()).optional(),cwd:O.string().optional()}),Bt=O.object({...kt,url:O.string().url(),headers:O.record(O.string(),O.string()).optional()}),Vt=O.object({...kt,url:O.string().url(),headers:O.record(O.string(),O.string()).optional()}),Ht=O.object({name:O.string(),description:O.string(),folder:O.string().optional()}),Ut=O.object({skill:Ht.optional()}),Wt=O.discriminatedUnion(`transport`,[O.object({name:O.string(),instruction:O.string().optional(),toolBlacklist:O.array(O.string()).optional(),omitToolDescription:O.boolean().optional(),prompts:O.record(O.string(),Ut).optional(),timeout:O.number().positive().optional(),requestTimeout:O.number().positive().optional(),transport:O.literal(`stdio`),config:zt}),O.object({name:O.string(),instruction:O.string().optional(),toolBlacklist:O.array(O.string()).optional(),omitToolDescription:O.boolean().optional(),prompts:O.record(O.string(),Ut).optional(),timeout:O.number().positive().optional(),requestTimeout:O.number().positive().optional(),transport:O.literal(`http`),config:Bt}),O.object({name:O.string(),instruction:O.string().optional(),toolBlacklist:O.array(O.string()).optional(),omitToolDescription:O.boolean().optional(),prompts:O.record(O.string(),Ut).optional(),timeout:O.number().positive().optional(),requestTimeout:O.number().positive().optional(),transport:O.literal(`sse`),config:Vt})]),Gt=O.object({id:O.string().optional(),proxy:Lt,mcpServers:O.record(O.string(),Wt),skills:Ft.optional()});function Kt(e,t=process.env){let n={};for(let[r,i]of Object.entries(e.mcpServers))if(!(`disabled`in i&&i.disabled===!0)){if(`command`in i){let e=i,a=L(e.command,t),o=e.args?.map(e=>L(e,t)),s=e.env?R(e.env,t):void 0,c=e.cwd?L(e.cwd,t):void 0;n[r]={name:r,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:`stdio`,config:{command:a,args:o,env:s,cwd:c}}}else if(`url`in i){let e=i,a=e.type===`sse`?`sse`:`http`,o=L(e.url,t),s=e.headers?R(e.headers,t):void 0;n[r]={name:r,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:a,config:{url:o,headers:s,...e.auth===void 0?{}:{auth:e.auth},...e.bearerToken?{bearerToken:L(e.bearerToken,t)}:{},...e.bearerTokenEnv?{bearerTokenEnv:e.bearerTokenEnv}:{},...e.oauth===void 0?{}:{oauth:e.oauth}}}}}return{id:e.id,proxy:e.proxy,mcpServers:n,skills:e.skills}}function qt(e,t=process.env){let n=Kt(Rt.parse(e),t);return Gt.parse(n)}var Jt=class{cacheDir;cacheTTL;readEnabled;writeEnabled;logger;constructor(e,t=console){this.cacheDir=i(ne(),`mcp-proxy-cache`,`remote-configs`),this.cacheTTL=e?.ttl||36e5,this.readEnabled=e?.readEnabled===void 0||e.readEnabled,this.writeEnabled=e?.writeEnabled===void 0||e.writeEnabled,this.logger=t}generateCacheKey(e){return c(`sha256`).update(e).digest(`hex`)}getCacheFilePath(e){return i(this.cacheDir,`${e}.json`)}async ensureCacheDir(){try{await g(this.cacheDir,{recursive:!0})}catch(e){if(e?.code!==`EEXIST`)throw e}}async get(t){if(!this.readEnabled)return null;try{await this.ensureCacheDir();let n=this.generateCacheKey(t),r=this.getCacheFilePath(n);if(!e(r))return null;let i=await y(r,`utf-8`),a=JSON.parse(i),o=Date.now();if(o>a.expiresAt)return await w(r).catch(()=>{}),null;let s=Math.round((a.expiresAt-o)/1e3);return this.logger.debug(`Remote config cache hit for ${t} (expires in ${s}s)`),a.data}catch(e){return this.logger.warn(`Failed to read remote config cache for ${t}`,e),null}}async set(e,t){if(this.writeEnabled)try{await this.ensureCacheDir();let n=this.generateCacheKey(e),r=this.getCacheFilePath(n),i=Date.now(),a={data:t,timestamp:i,expiresAt:i+this.cacheTTL,url:e};await T(r,JSON.stringify(a,null,2),`utf-8`),this.logger.debug(`Cached remote config for ${e} (TTL: ${Math.round(this.cacheTTL/1e3)}s)`)}catch(t){this.logger.warn(`Failed to write remote config cache for ${e}`,t)}}async clear(t){try{let n=this.generateCacheKey(t),r=this.getCacheFilePath(n);e(r)&&(await w(r),this.logger.info(`Cleared remote config cache for ${t}`))}catch(e){this.logger.warn(`Failed to clear remote config cache for ${t}`,e)}}async clearAll(){try{if(!e(this.cacheDir))return;let t=await b(this.cacheDir),n=t.filter(e=>e.endsWith(`.json`)).map(e=>w(i(this.cacheDir,e)).catch(t=>{this.logger.debug(`Failed to delete remote config cache file ${e}`,t)}));await Promise.all(n),this.logger.info(`Cleared all remote config cache entries (${t.length} files)`)}catch(e){this.logger.warn(`Failed to clear all remote config cache`,e)}}async cleanExpired(){try{if(!e(this.cacheDir))return;let t=Date.now(),n=(await b(this.cacheDir)).filter(e=>e.endsWith(`.json`)),r=(await Promise.all(n.map(async e=>{let n=i(this.cacheDir,e);try{let e=await y(n,`utf-8`),r=JSON.parse(e);return t>r.expiresAt&&(await w(n),!0)}catch(e){return await w(n).catch(()=>{this.logger.debug(`Failed to delete corrupt cache file ${n}`,e)}),this.logger.warn(`Removed unreadable remote config cache file ${n}`,e),!0}}))).filter(Boolean).length;r>0&&this.logger.info(`Cleaned up ${r} expired remote config cache entries`)}catch(e){this.logger.warn(`Failed to clean expired remote config cache`,e)}}async getStats(){try{if(!e(this.cacheDir))return{totalEntries:0,totalSize:0};let t=(await b(this.cacheDir)).filter(e=>e.endsWith(`.json`)),n=(await Promise.all(t.map(async e=>{let t=i(this.cacheDir,e);try{let e=await y(t,`utf-8`);return Buffer.byteLength(e,`utf-8`)}catch{return 0}}))).reduce((e,t)=>e+t,0);return{totalEntries:t.length,totalSize:n}}catch(e){return this.logger.warn(`Failed to get remote config cache stats`,e),{totalEntries:0,totalSize:0}}}isReadEnabled(){return this.readEnabled}isWriteEnabled(){return this.writeEnabled}setReadEnabled(e){this.readEnabled=e}setWriteEnabled(e){this.writeEnabled=e}};function Yt(e,t){let n=e?.url,r=t?.url;return typeof n==`string`&&typeof r==`string`&&n!==r}function z(e,t){return e?t?{...e,...t}:e:t}function Xt(e){return e.configSources?.length?e.configSources:e.configFilePath?[{path:e.configFilePath}]:[]}var Zt=class{configSources;cacheTtlMs;cachedConfig=null;lastFetchTime=0;remoteConfigCache;logger;env;constructor(e,t=console){this.env=e.env??process.env,this.configSources=Xt(e),this.cacheTtlMs=e.cacheTtlMs||6e4,this.logger=t;let n=e.useCache===void 0||e.useCache;if(this.remoteConfigCache=new Jt({ttl:e.remoteCacheTtlMs||36e5,readEnabled:n,writeEnabled:!0},t),this.configSources.length===0)throw Error(`configFilePath or configSources must be provided`)}async fetchConfiguration(e=!1){let t=Date.now();if(!e&&this.cachedConfig&&t-this.lastFetchTime<this.cacheTtlMs)return this.cachedConfig;let n=null,r=[],i=[];for(let e of this.configSources){let t=await this.loadRawConfigFromSource(e);if(t===null){i.push(e.path);continue}if((e.format??`claude`)===`claude`){let e=t;e.remoteConfigs&&r.push(...e.remoteConfigs)}let a=await this.parseConfig(t,e);n=n===null?a:this.mergeConfigurations(n,a,e.mergeStrategy??`remote-priority`)}if(n===null)throw Error(`Config file not found or empty: ${i.join(`, `)}`);let a=r.map(async e=>{try{return St(e,this.env),{config:await this.loadFromUrl(e),mergeStrategy:e.mergeStrategy||`local-priority`,url:e.url}}catch(t){return this.logger.warn(`Failed to fetch remote config from ${e.url}`,t),null}}),o=await Promise.all(a);for(let e of o)e!==null&&(n=this.mergeConfigurations(n,e.config,e.mergeStrategy));if(!n.mcpServers||typeof n.mcpServers!=`object`)throw Error(`Invalid MCP configuration: missing or invalid mcpServers`);return this.cachedConfig=n,this.lastFetchTime=t,n}async loadRawConfigFromSource(t){if(!e(t.path)){if(t.optional)return null;throw Error(`Config file not found: ${t.path}`)}try{let e=await y(t.path,`utf-8`);if(e.trim()===``)return null;if(t.path.endsWith(`.yaml`)||t.path.endsWith(`.yml`)){let t=le.loadAll(e);if(t.length>1)throw new le.YAMLException(`expected a single document in the stream, but found more`);return t[0]??null}return JSON.parse(e)??null}catch(e){throw e instanceof Error?Error(`Failed to load config file ${t.path}: ${e.message}`):Error(`Failed to load config file ${t.path}: Unknown error`)}}async parseConfig(e,t){try{if((t.format??`claude`)===`internal`)return Gt.parse(e);let{remoteConfigs:n,...r}=e;return qt(r,this.env)}catch(e){throw e instanceof Error?Error(`Failed to parse config: ${e.message}`):Error(`Failed to parse config: Unknown error`)}}async loadFromUrl(e){try{let t=this.interpolateEnvVars(e.url),n=await this.remoteConfigCache.get(t);if(n)return n;let r=e.headers?Object.fromEntries(Object.entries(e.headers).map(([e,t])=>[e,this.interpolateEnvVars(t)])):{},i=await fetch(t,{headers:r,signal:AbortSignal.timeout(3e4)});if(!i.ok)throw Error(`Failed to fetch remote config: ${i.status} ${i.statusText}`);let a=qt(await i.json());return await this.remoteConfigCache.set(t,a),a}catch(t){throw t instanceof Error?Error(`Failed to fetch remote config from ${e.url}: ${t.message}`,{cause:t}):Error(`Failed to fetch remote config from ${e.url}: Unknown error`)}}interpolateEnvVars(e){return e.replace(/\$\{([^}]+)\}/g,(e,t)=>{let n=this.env[t];return n===void 0?(this.logger.warn(`Environment variable ${t} is not defined, keeping placeholder`),`\${${t}}`):n})}mergeConfigurations(e,t,n){switch(n){case`local-priority`:return{id:e.id??t.id,proxy:z(t.proxy,e.proxy),mcpServers:{...t.mcpServers,...e.mcpServers},skills:z(t.skills,e.skills)};case`remote-priority`:return{id:t.id??e.id,proxy:z(e.proxy,t.proxy),mcpServers:{...e.mcpServers,...t.mcpServers},skills:z(e.skills,t.skills)};case`merge-deep`:{let n={...t.mcpServers};for(let[t,r]of Object.entries(e.mcpServers))if(n[t]){let e=n[t],i={...e.config,...r.config},a=`env`in e.config?e.config.env:void 0,o=`env`in r.config?r.config.env:void 0;(a||o)&&(i.env={...a,...o});let s=`headers`in e.config?e.config.headers:void 0,c=`headers`in r.config?r.config.headers:void 0;(s||c)&&(i.headers=Yt(e.config,r.config)?{...c}:{...s,...c}),n[t]={...e,...r,config:i}}else n[t]=r;return{id:e.id??t.id,proxy:z(t.proxy,e.proxy),mcpServers:n,skills:z(t.skills,e.skills)}}default:throw Error(`Unknown merge strategy: ${String(n)}`)}}clearCache(){this.cachedConfig=null,this.lastFetchTime=0}isCacheValid(){let e=Date.now();return this.cachedConfig!==null&&e-this.lastFetchTime<this.cacheTtlMs}};const Qt=`[capability-discovery]`;function $t(e,t=[]){return[...t,e]}function en(e){return e?Array.isArray(e)?e:[e]:[]}function tn(e){return e.map(e=>({path:e}))}function nn(){let t=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],r=process.env.PROJECT_PATH;if(r)for(let n of t){let t=a(r,n);if(e(t))return t}let o=process.cwd();for(let r=0;r<=3;r++){for(let n of t){let t=i(o,n);if(e(t))return t}let r=n(o);if(r===o)break;o=r}return null}function rn(e=6){let t=``,n=e;for(;n>0;){let e=l(n);for(let r=0;r<e.length&&n>0;r++){let i=e[r];i>247||(t+=`23456789abcdefghjkmnpqrstuvwxyz`[i%31],n--)}}return t}function an(e){let t=e.trimStart();if(!t.startsWith(`---`))return{frontMatter:null,content:e};let n=t.indexOf(`
2
- ---`,3);if(n===-1)return{frontMatter:null,content:e};let r=t.slice(4,n).trim();if(!r)return{frontMatter:null,content:e};let i={},a=r.split(`
3
- `),o=null,s=[],c=null,l=0,u=()=>{o&&s.length>0&&(c===`literal`?i[o]=s.join(`
4
- `).trimEnd():c===`folded`?i[o]=s.join(` `).trim():i[o]=s.join(``).trim()),o=null,s=[],c=null,l=0};for(let e=0;e<a.length;e++){let t=a[e],n=t.trim(),r=t.indexOf(`:`);if(r!==-1&&!t.startsWith(` `)&&!t.startsWith(` `)){u();let n=t.slice(0,r).trim(),s=t.slice(r+1).trim();if(s===`|`||s===`|-`){if(o=n,c=`literal`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else if(s===`>`||s===`>-`){if(o=n,c=`folded`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else(s.startsWith(`"`)&&s.endsWith(`"`)||s.startsWith(`'`)&&s.endsWith(`'`))&&(s=s.slice(1,-1)),n&&s&&(i[n]=s)}else if(c&&o){let e=t.match(/^(\s*)/)?.[1].length||0;if(n===``)s.push(``);else if(e>=l){let e=t.slice(l);s.push(e)}else u()}}return u(),{frontMatter:i,content:t.slice(n+4).trimStart()}}function on(e){return e!==null&&typeof e.name==`string`&&e.name.length>0&&typeof e.description==`string`&&e.description.length>0}function sn(e){let{frontMatter:t,content:n}=an(e);return t&&on(t)?{skill:{name:t.name,description:t.description},content:n}:null}function B(e){let t=e.indexOf(`__`);return t>0?{serverName:e.substring(0,t),actualToolName:e.substring(t+2)}:{actualToolName:e}}async function cn(e,t){try{await t()}catch(t){console.error(`[mcp-proxy] ${e} cleanup failed: ${t instanceof Error?t.message:String(t)}`)}}async function ln(){await Promise.all([cn(`Process registry`,async()=>new oe(process.env.PROCESS_REGISTRY_PATH).cleanupStaleProcesses()),cn(`Port registry`,async()=>new me(process.env.PORT_REGISTRY_PATH).cleanupStaleAllocations())])}function un(e){return e.endsWith(`.yaml`)||e.endsWith(`.yml`)}function V(e){return e instanceof Error?e.message:String(e)}function dn(e){return(e instanceof de||typeof e==`object`&&!!e&&`code`in e)&&e.code===ue}function fn(e){let t=a(e),n=t.length>=2&&t[1]===`:`&&(t[0]>=`A`&&t[0]<=`Z`||t[0]>=`a`&&t[0]<=`z`)?`${t[0].toLowerCase()}${t.slice(1)}`:t,r=``,i=!1;for(let e of n)e>=`a`&&e<=`z`||e>=`A`&&e<=`Z`||e>=`0`&&e<=`9`||e===`.`||e===`_`||e===`-`?(r+=e,i=!1):i||=(r+=`_`,!0);let o=0,s=r.length;for(;o<s&&r[o]===`_`;)o+=1;for(;s>o&&r[s-1]===`_`;)--s;return r.slice(o,s)}function H(e){return{...e,failures:[...e.failures??[]],skills:(e.skills??[]).map(e=>({...e})),servers:Object.fromEntries(Object.entries(e.servers).map(([e,t])=>[e,{...t,tools:(t.tools??[]).map(e=>({...e})),resources:(t.resources??[]).map(e=>({...e})),prompts:(t.prompts??[]).map(e=>({...e,arguments:e.arguments?.map(e=>({...e}))})),promptSkills:(t.promptSkills??[]).map(e=>({...e,skill:{...e.skill}})),capabilityDiscovery:t.capabilityDiscovery?{resources:{...t.capabilityDiscovery.resources},prompts:{...t.capabilityDiscovery.prompts}}:void 0}]))}}var pn=class extends Error{constructor(){super(`Definitions cache uses an incompatible format and must be refreshed`),this.name=`DefinitionsCacheVersionError`}},U=class e{clientManager;skillService;cacheData;liveDefinitionsPromise=null;mergedDefinitionsPromise=null;logger;constructor(t,n,r,i=console){this.clientManager=t,this.skillService=n,this.cacheData=r?.cacheData&&e.isCacheValid(r.cacheData,{})?r.cacheData:void 0,this.logger=i}static async readFromFile(e){let t=await y(e,`utf-8`),n=un(e)?le.load(t):JSON.parse(t);if(!n||typeof n!=`object`)throw Error(`Definitions cache must be an object`);let r=n;if(r.version!==2)throw new pn;if(!r.servers||typeof r.servers!=`object`||Array.isArray(r.servers))throw Error(`Definitions cache is missing required fields`);return{...r,failures:Array.isArray(r.failures)?r.failures:[],skills:Array.isArray(r.skills)?r.skills:[],servers:Object.fromEntries(Object.entries(r.servers).map(([e,t])=>[e,{...t,tools:Array.isArray(t.tools)?t.tools:[],resources:Array.isArray(t.resources)?t.resources:[],prompts:Array.isArray(t.prompts)?t.prompts:[],promptSkills:Array.isArray(t.promptSkills)?t.promptSkills:[]}]))}}static async inspectFile(t,n){try{let r=await e.readFromFile(t);return e.isCacheValid(r,n)?{state:`usable`,cachePath:t,cache:r}:{state:`invalid`,cachePath:t,reason:`metadata_mismatch`}}catch(e){return e.code===`ENOENT`?{state:`absent`,cachePath:t}:e instanceof pn?{state:`invalid`,cachePath:t,reason:`incompatible_schema`}:{state:`invalid`,cachePath:t,reason:`unreadable`,error:V(e)}}}static async writeToFile(e,t){let r=un(e)?le.dump(t,{noRefs:!0}):JSON.stringify(t,null,2);await g(n(e),{recursive:!0}),await T(e,r,`utf-8`)}static getDefaultCachePath(e){let t=Array.isArray(e)?e:[e];if(t.length===0)throw Error(`getDefaultCachePath requires at least one config path`);let n=fn(t[0]);if(t.length===1)return i(E(),`.mcp-proxy`,`${n}.definitions-cache.json`);let r=c(`sha256`).update(t.map(e=>a(e)).join(`\0`)).digest(`hex`).slice(0,12);return i(E(),`.mcp-proxy`,`${n}.${r}.definitions-cache.json`)}static generateConfigHash(e){return c(`sha256`).update(JSON.stringify(e)).digest(`hex`)}static isCacheValid(e,t){return!(e.version!==2||t.configHash&&e.configHash!==t.configHash||t.oneMcpVersion&&e.oneMcpVersion!==t.oneMcpVersion)}static async clearFile(e){await S(e,{force:!0})}clearLiveCache(){this.liveDefinitionsPromise=null,this.mergedDefinitionsPromise=null}setCacheData(t){this.cacheData=t&&e.isCacheValid(t,{})?t:void 0,this.mergedDefinitionsPromise=null}async collectForCache(e){let t=await this.collectLiveDefinitions(e);return this.setCacheData(t),this.liveDefinitionsPromise=Promise.resolve(H(t)),H(t)}logCapabilitySummary(e,t){let n=Object.values(e.servers).map(e=>({serverName:e.serverName,tools:e.tools.length,resources:{state:e.capabilityDiscovery?.resources.state??`unknown`,count:e.resources.length,error:e.capabilityDiscovery?.resources.error},prompts:{state:e.capabilityDiscovery?.prompts.state??`unknown`,count:e.prompts.length,error:e.capabilityDiscovery?.prompts.error}})),r=n.some(e=>e.resources.state===`degraded`||e.prompts.state===`degraded`),i={source:t,servers:n,failures:e.failures,degraded:r||e.failures.length>0};i.degraded?this.logger.warn(`${Qt} MCP server capability summary`,i):this.logger.info(`${Qt} MCP server capability summary`,i)}async getDefinitions(){return this.mergedDefinitionsPromise||=(async()=>{let e=this.clientManager.getAllClients();if(!this.cacheData)return this.getLiveDefinitions();let t=e.map(e=>e.serverName).filter(e=>!this.cacheData?.servers[e]);if(t.length===0)return H(this.cacheData);let n=await this.getLiveDefinitions(),r=H(this.cacheData);for(let e of t){let t=n.servers[e];t&&(r.servers[e]=t)}let i=/* @__PURE__ */ new Map;for(let e of[...r.failures,...n.failures])i.set(e.serverName,e.error);return r.failures=Array.from(i.entries()).map(([e,t])=>({serverName:e,error:t})),r.skills.length===0&&n.skills.length>0&&(r.skills=n.skills.map(e=>({...e}))),r})(),this.mergedDefinitionsPromise}async getServerDefinitions(){let e=await this.getDefinitions(),t=this.clientManager.getKnownServerNames();return t.length===0?Object.values(e.servers):t.map(t=>e.servers[t]).filter(e=>e!==void 0)}async getServersForTool(e){return(await this.getServerDefinitions()).filter(t=>t.tools.some(t=>t.name===e)).map(e=>e.serverName)}async getToolSchema(e,t){return(await this.getDefinitions()).servers[e]?.tools.find(e=>e.name===t)?.inputSchema}async getServersForResource(e){return(await this.getServerDefinitions()).filter(t=>t.resources.some(t=>t.uri===e)).map(e=>e.serverName)}async getPromptSkillByName(e){let t=await this.getDefinitions();for(let[n,r]of Object.entries(t.servers))for(let t of r.promptSkills)if(t.skill.name===e)return{serverName:n,promptName:t.promptName,skill:t.skill,autoDetected:t.autoDetected}}async getCachedFileSkills(){return(await this.getDefinitions()).skills.map(e=>({...e}))}async getLiveDefinitions(){return this.liveDefinitionsPromise||=this.collectLiveDefinitions(),this.liveDefinitionsPromise}async collectLiveDefinitions(e){let t=this.clientManager.getAllClients(),n=[],r={},i=await Promise.all(t.map(async e=>{try{let t=await e.listTools(),n=e.getServerCapabilities?.(),r=await this.listResourcesSafe(e,n?n.resources!==void 0:void 0),i=await this.listPromptsSafe(e,n?n.prompts!==void 0:void 0),a=new Set(e.toolBlacklist||[]),o=t.filter(e=>!a.has(e.name)),s=await this.collectPromptSkillsForClient(e,i.items);return{serverName:e.serverName,serverInstruction:e.serverInstruction,omitToolDescription:e.omitToolDescription,toolBlacklist:e.toolBlacklist,tools:o.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,_meta:e._meta})),resources:r.items,prompts:i.items,promptSkills:s,capabilityDiscovery:{resources:{state:r.state,error:r.error},prompts:{state:i.state,error:i.error}}}}catch(t){return n.push({serverName:e.serverName,error:V(t)}),null}}));for(let e of i)e&&(r[e.serverName]=e);let a={version:2,oneMcpVersion:e?.oneMcpVersion,generatedAt:(/* @__PURE__ */ new Date()).toISOString(),configPath:e?.configPath,configHash:e?.configHash,serverId:e?.serverId,servers:r,skills:await this.collectFileSkills(),failures:n};return this.logCapabilitySummary(a,`live`),a}async collectFileSkills(){return this.skillService?(await this.skillService.getSkills()).map(e=>this.toCachedFileSkill(e)):[]}toCachedFileSkill(e){return{name:e.name,description:e.description,location:e.location,basePath:e.basePath}}async listPromptsSafe(e,t){if(t===!1)return{items:[],state:`unsupported`};try{return{state:`available`,items:(await e.listPrompts()).map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(e=>({...e}))}))}}catch(e){return dn(e)?{items:[],state:`unsupported`}:{items:[],state:`degraded`,error:V(e)}}}async listResourcesSafe(e,t){if(t===!1)return{items:[],state:`unsupported`};try{return{state:`available`,items:(await e.listResources()).map(e=>({uri:e.uri,name:e.name,description:e.description,mimeType:e.mimeType}))}}catch(e){return dn(e)?{items:[],state:`unsupported`}:{items:[],state:`degraded`,error:V(e)}}}async collectPromptSkillsForClient(e,t){let n=new Set(e.prompts?Object.keys(e.prompts):[]),r=[];if(e.prompts)for(let[t,n]of Object.entries(e.prompts))n.skill&&r.push({promptName:t,skill:{...n.skill}});let i=t.filter(e=>!n.has(e.name)).slice(0,50),a=await Promise.all(i.map(async t=>{try{let n=sn((await e.getPrompt(t.name)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
5
- `)||``);return n?{promptName:t.name,skill:n.skill,autoDetected:!0}:null}catch(n){return this.logger.warn(`[skill-detection] Failed to fetch prompt '${t.name}' from ${e.serverName}: ${V(n)}`),null}}));for(let e of a)e&&r.push(e);return r}};function mn(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function hn(e){if(typeof e==`string`||typeof e==`number`||typeof e==`boolean`||Array.isArray(e)&&e.every(e=>typeof e==`string`)||Array.isArray(e)&&e.every(e=>typeof e==`number`)||Array.isArray(e)&&e.every(e=>typeof e==`boolean`))return e;try{return JSON.stringify(e)??String(e)}catch{return String(e)}}function gn(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,hn(t)]))}function W(e){if(e!==void 0)return e instanceof Error?{exception:e}:mn(e)&&(`attributes`in e||`exception`in e||`context`in e)?e:mn(e)?{attributes:gn(e)}:{attributes:{value:hn(e)}}}function _n(e){let t=e.logger;return{backend:e.backend,enabled:e.enabled,endpoint:e.endpoint,tracesEndpoint:e.tracesEndpoint,logsEndpoint:e.logsEndpoint,endpointSource:e.endpointSource,filePath:e.filePath,trace(e,n){t.trace(e,W(n))},debug(e,n){t.debug(e,W(n))},info(e,n){t.info(e,W(n))},warn(e,n){t.warn(e,W(n))},error(e,n){t.error(e,W(n))},getTraceContext(){return e.getTraceContext()},runInSpan:(t,n,r)=>e.runInSpan(t,n,r),flush:()=>e.flush(),shutdown:()=>e.shutdown()}}async function vn(e={}){return _n(await he({env:e.env,workspaceRoot:e.workspaceRoot,packageName:e.packageName??`@agimon-ai/po-mcp-proxy`,serviceName:e.serviceName??`@agimon-ai/mcp-proxy`,serviceVersion:e.serviceVersion,logDir:e.logDir,logFileName:e.logFileName,maxFileSizeBytes:e.maxFileSizeBytes,maxFileCount:e.maxFileCount}))}function yn(e){let t=typeof e==`object`&&e?e:void 0;return{enabled:Fn(`MCP_OUTPUT_GUARD`)??e!==!1,maxBytes:t?.maxBytes,maxLines:t?.maxLines,structuredMaxBytes:t?.structuredMaxBytes}}var bn=class{enabled;maxBytes;maxLines;structuredMaxBytes;constructor(e={}){this.enabled=e.enabled??Fn(`MCP_OUTPUT_GUARD`)??!0,this.maxBytes=Pn(e.maxBytes)??51200,this.maxLines=Pn(e.maxLines)??2e3,this.structuredMaxBytes=Pn(e.structuredMaxBytes)??16384}isEnabled(){return this.enabled}async guard(e){if(!this.enabled)return e;let t=await this.guardContent(e);return await this.guardStructuredContent(t)}async guardContent(e){let t=Array.isArray(e.content)?e.content:[],n=t.filter(e=>e.type===`text`),r=t.filter(e=>e.type!==`text`),i=n.map(e=>typeof e.text==`string`?e.text:``).join(`
6
- `),a=Mn(i);if(a.bytes<=this.maxBytes&&a.lines<=this.maxLines)return e;let{path:o,error:s}=await kn(`output`,i),c=wn(a,o,s),l=xn(this.maxBytes,this.maxLines,c),u=`${Sn(i,l.maxBytes,l.maxLines)}\n\n${c}`,d=Mn(u),f=r.filter(e=>e.type===`image`).length,p={truncated:!0,originalBytes:a.bytes,returnedBytes:d.bytes,originalLines:a.lines,returnedLines:d.lines,...f>0?{imageBlocksPassedThrough:f}:{},...o?{fullOutputPath:o}:{},...s?{writeError:s}:{}};return{...e,content:[{type:`text`,text:u},...r],_meta:{...e._meta,"agiflowai/outputGuard":p}}}async guardStructuredContent(e){if(e.structuredContent===void 0)return e;let t=jn(e.structuredContent),n=Nn(t);if(n<=this.structuredMaxBytes)return e;let{path:r,error:i}=await kn(`structured-content`,t);return{...e,structuredContent:{omitted:!0,reason:`structuredContent exceeded the size limit and was replaced with this summary to keep the caller context bounded.`,rawBytes:n,summary:Tn(e.structuredContent),...r?{fullResultPath:r}:{},...i?{resultWriteError:i}:{}}}}};function xn(e,t,n){let r=Mn(`\n\n${n}`);return{maxBytes:Math.max(0,e-r.bytes),maxLines:Math.max(0,t-r.lines)}}function Sn(e,t,n){let r=e.split(`
7
- `),i=[],a=0;for(let e of r){if(i.length>=n)break;let r=+(i.length>0),o=Nn(e);if(a+r+o>t){let n=t-a-r;n>0&&i.push(Cn(e,n));break}i.push(e),a+=r+o}return i.join(`
8
- `)}function Cn(e,t){if(Nn(e)<=t)return e;let n=Buffer.from(e,`utf8`),r=Math.max(0,t);for(;r>0&&(n[r]&192)==128;)r--;return n.subarray(0,r).toString(`utf8`)}function wn(e,t,n){let r=`[MCP tool output truncated: original ${e.lines.toLocaleString()} lines / ${In(e.bytes)}.`;return t?`${r} Full text saved to: ${t}]`:`${r} Full output could not be saved: ${n??`unknown error`}]`}function Tn(e){let t=An(e);if(!t)return{type:e===null?`null`:typeof e,omitted:!0};let n=Object.keys(t);return{type:Array.isArray(e)?`array`:`object`,keyCount:Array.isArray(e)?e.length:n.length,keysPreview:n.slice(0,20).map(En),...Array.isArray(e)&&e.length>20?{itemsOmitted:e.length-20}:{},omitted:!0}}function En(e){return e.length<=120?e:`${e.slice(0,119)}…`}let Dn;function On(){return Dn??=_(i(ne(),`mcp-proxy-output-`)),Dn}async function kn(e,t){try{let n=await On(),r=i(n,`${e}-${l(8).toString(`hex`)}.txt`);return await T(r,t,{encoding:`utf8`,mode:384}),{path:r}}catch(e){return Dn=void 0,{error:e instanceof Error?e.message:String(e)}}}function An(e){return typeof e==`object`&&e?e:void 0}function jn(e){try{return JSON.stringify(e)??``}catch{return``}}function Mn(e){return{bytes:Nn(e),lines:e.length===0?0:e.split(`
9
- `).length}}function Nn(e){return Buffer.byteLength(e,`utf8`)}function Pn(e){if(typeof e!=`number`||!Number.isFinite(e))return;let t=Math.floor(e);return t>0?t:void 0}function Fn(e){let t=process.env[e]?.trim().toLowerCase();if(t){if([`0`,`false`,`no`,`off`].includes(t))return!1;if([`1`,`true`,`yes`,`on`].includes(t))return!0}}function In(e){return e<1024?`${e} B`:e<1048576?`${(e/1024).toFixed(1)} KiB`:`${(e/1048576).toFixed(1)} MiB`}const G=`x-mcp-proxy-original-output-schema`;function Ln(e){return Array.from(e.slice(0,256)).filter(e=>{let t=e.charCodeAt(0);return t>=32&&t<=126||t>=160}).join(``)}var Rn=class extends _e{serverName;compatibility;calls;constructor(e,t,n,r){let i=new Te,a=new Ee;super(e,{...t,jsonSchemaValidator:{getValidator:e=>t=>{let n=i.getStore()?.toolName,r=Object.hasOwn(e,G)?e[G]:e;try{!a.getValidator(r)(t).valid&&n&&this.warn(n,`tools/call`,`structuredContent`,`Structured output does not match its output schema.`)}catch{n&&this.warn(n,`tools/call`,`outputSchema`,`Output schema could not be compiled or evaluated.`)}return{valid:!0,data:t,errorMessage:void 0}}}}),this.serverName=n,this.compatibility=r,this.calls=i}warn(e,t,n,r){try{Promise.resolve(this.compatibility.onWarning({serverName:Ln(this.serverName),toolName:Ln(e),method:t,path:n,message:r})).catch(()=>{})}catch{}}request(e,t,n){if(t&&`~standard`in t)return super.request(e,t,n);if(e.method!==`tools/list`){let n=super.request(e,t);return e.method===`tools/call`?n.then(e=>{let t=this.calls.getStore();return t&&(t.result=e),e}):n}return super.request(e,{"~standard":{version:1,vendor:`mcp-proxy-output-compatibility`,validate:e=>this.validateListing(e)}},t)}validateListing(e){if(!e||typeof e!=`object`||!(`tools`in e)||!Array.isArray(e.tools))return{issues:[{message:`Invalid tools/list result`}]};let t=e.tools,n=t.map(e=>{if(!e||typeof e!=`object`)return e;let{outputSchema:t,...n}=e;return n}),r=this._wireCodec().validateResult(`tools/list`,{...e,tools:n});if(!r.ok)return{issues:[{message:`Invalid non-output tools/list descriptor`}]};for(let[e,n]of r.value.tools.entries()){let r=t[e];Object.hasOwn(r,`outputSchema`)&&(n.outputSchema={type:`object`,[G]:r.outputSchema},this._wireCodec().validateResult(`tools/list`,{tools:[r]}).ok||this.warn(n.name,`tools/list`,`tools/${e}/outputSchema`,`Output schema descriptor is not MCP-compatible.`))}return{value:r.value}}async listTools(e,t){let n=await super.listTools(e,t);return{...n,tools:n.tools.map(e=>e.outputSchema&&Object.hasOwn(e.outputSchema,G)?{...e,outputSchema:e.outputSchema[G]}:e)}}async callTool(e,t){let n={toolName:e.name,result:void 0};return this.calls.run(n,async()=>{try{return await super.callTool(e,t)}catch(t){if(!(t instanceof ve)||t.code!==ye.InvalidRequest||t.message!==`Tool ${e.name} has an output schema but did not return structured content`||!n.result||n.result.structuredContent!==void 0||n.result.isError)throw t;return this.warn(e.name,`tools/call`,`structuredContent`,`Tool omitted structured output required by its output schema.`),n.result}})}};const zn=`mcp-proxy-client-manager`,Bn=[0,100];function Vn(e){return e===`reconnecting`?`connecting`:e}var Hn=class extends Error{serverName;attempts;code=`MCP_SERVER_RECOVERY_EXHAUSTED`;constructor(e,t,n){super(`MCP server "${e}" did not recover after ${t} attempts.`,n),this.serverName=e,this.attempts=t,this.name=`McpServerRecoveryExhaustedError`}};async function Un(e){let t=await Promise.allSettled([Promise.resolve().then(()=>e.client.close()),Promise.resolve().then(()=>e.stdioTransport?.close())]);try{await e.processLease?.release({kill:!1,releasePort:!1})}catch(e){t.push({status:`rejected`,reason:e})}let n=t.flatMap(e=>e.status===`rejected`?[e.reason]:[]);if(n.length)throw AggregateError(n,`MCP connection cleanup failed`)}function Wn(e){return Yn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=qn(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function Gn(e){return e instanceof Se||Yn(e).some(({message:e,code:t})=>{let n=e.toLowerCase();return t===`401`||n.includes(`unauthorized`)||n.includes(`http 401`)||n.includes(`invalid_token`)})}function Kn(e){return Yn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=qn(t);return n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`premature close`)||n.includes(`socket hang up`)||n.includes(`write epipe`)||n.includes(`read econnreset`)||n.includes(`fetch failed`)||r===`epipe`||r===`econnreset`})}function qn(e){return typeof e==`string`?e.toLowerCase():void 0}function Jn(e){if(typeof e==`string`)return e;if(typeof e==`symbol`)return e.toString();if(typeof e==`object`&&e)try{return JSON.stringify(e)??`Unknown error`}catch{return`Unknown error`}return String(e)}function Yn(e){let t=/* @__PURE__ */ new Set,n=[],r=e;for(;r&&!t.has(r);)if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause}else if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:Jn(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause}else{n.push({message:Jn(r)});break}return n}var Xn=class{outputGuard;serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;stdioTransport;processLease;connected=!1;lifecycleState=`closed`;recoveryError;reconnectFn;reconnectPromise;pendingLeaseRelease;onDisconnected;onLifecycleChange;closing=!1;closePromise;lifetime=new AbortController;constructor(e,t,n,r,i,a){this.outputGuard=a,this.serverName=e,this.serverInstruction=i.instruction,this.toolBlacklist=i.toolBlacklist,this.omitToolDescription=i.omitToolDescription,this.prompts=i.prompts,this.transport=t,this.logger=r,this.client=n}setStdioTransport(e){this.stdioTransport=e}setProcessLease(e){this.processLease=e}setConnected(e){this.connected=e,this.setLifecycleState(e?`connected`:`closed`),e&&(this.recoveryError=void 0)}getLifecycleState(){return this.lifecycleState}setLifecycleChangeCallback(e){this.onLifecycleChange=e}setLifecycleState(e,t){this.lifecycleState!==e&&(this.lifecycleState=e,this.onLifecycleChange?.(e,t))}async waitUntilReady(){await this.ensureReady()}getServerCapabilities(){return this.client.getServerCapabilities()}setReconnectFn(e){this.reconnectFn=e}setDisconnectedCallback(e){this.onDisconnected=e}handleStdioClosed(e){if(this.stdioTransport!==e||this.closing)return;let t=this.processLease;this.stdioTransport=void 0,this.processLease=void 0,this.connected=!1,this.recoveryError=void 0,this.setLifecycleState(`reconnecting`),this.pendingLeaseRelease=this.releaseProcessLease(t),!this.closing&&(this.logger.warn(`mcp_proxy.server.disconnected`,{"mcp.server.name":this.serverName,"mcp.server.transport":this.transport,"mcp.server.lifecycle":this.lifecycleState,"mcp.server.disconnect_reason":`stdio transport closed`,"mcp.server.recovery_mode":`proactive`}),this.onDisconnected?.(this),this.reconnectClient(`stdio transport closed`).catch(()=>{}))}async releaseProcessLease(e){try{await e?.release({kill:!1,releasePort:!1})}catch(e){this.logger.warn(`Failed to release process lease for ${this.serverName}`,e)}}async releaseOwnedResources(e){let t=this.stdioTransport,n=this.processLease,r=this.pendingLeaseRelease;this.stdioTransport=void 0,this.processLease=void 0,this.pendingLeaseRelease=void 0;try{t&&e.killChild&&await t.close()}finally{await Promise.all([r,n?.release({kill:!1,releasePort:!1})])}}async reconnectClient(e=`recoverable transport error`){if(this.lifetime.signal.throwIfAborted(),!this.reconnectFn)throw Error(`No reconnect function configured for ${this.serverName}`);let t=this.reconnectFn;this.reconnectPromise||=(async()=>{this.connected=!1,this.setLifecycleState(`reconnecting`),this.recoveryError=void 0,await this.releaseOwnedResources({killChild:!0});try{await this.client.close()}catch(e){this.logger.warn(`Failed to close stale client for ${this.serverName}`,e)}let n;for(let[r,i]of Bn.entries()){i>0&&await ge(i,void 0,{signal:this.lifetime.signal}),this.lifetime.signal.throwIfAborted();try{let n=await t(this.lifetime.signal);this.closing&&(await Un(n),this.lifetime.signal.throwIfAborted()),this.client=n.client,n.stdioTransport&&(this.stdioTransport=n.stdioTransport),n.processLease&&(this.processLease=n.processLease),this.connected=!0,this.setLifecycleState(`connected`),this.logger.info(`mcp_proxy.server.recovered`,{"mcp.server.name":this.serverName,"mcp.server.transport":this.transport,"mcp.server.lifecycle":`connected`,"mcp.server.recovery_attempt":r+1,"mcp.server.recovery_trigger":e});return}catch(e){this.lifetime.signal.throwIfAborted(),n=e,this.logger.warn(`mcp_proxy.server.reconnect_failed`,{"mcp.server.name":this.serverName,"mcp.server.transport":this.transport,"mcp.server.recovery_attempt":r+1,"error.message":e instanceof Error?e.message:String(e)})}}throw this.connected=!1,this.recoveryError=new Hn(this.serverName,Bn.length,{cause:n}),this.setLifecycleState(`degraded`,this.recoveryError.message),this.logger.error(`mcp_proxy.server.degraded`,{"mcp.server.name":this.serverName,"mcp.server.transport":this.transport,"mcp.server.lifecycle":`degraded`,"mcp.server.recovery_attempts":Bn.length,"error.message":n instanceof Error?n.message:String(n)}),this.recoveryError})();let n=this.reconnectPromise;try{await n}finally{this.reconnectPromise===n&&(this.reconnectPromise=void 0)}}async ensureReady(){if(this.lifetime.signal.throwIfAborted(),!this.connected){if(this.recoveryError)throw this.recoveryError;await this.reconnectClient(`operation requested while disconnected`)}}async withSessionRetry(e,t){t?.throwIfAborted(),await this.ensureReady(),t?.throwIfAborted();try{return await e()}catch(n){if(t?.throwIfAborted(),!this.reconnectFn||!Wn(n)&&!Kn(n))throw n;return this.logger.warn(`Session error for ${this.serverName}, reconnecting: ${n instanceof Error?n.message:String(n)}`),await this.reconnectClient(n instanceof Error?n.message:String(n)),t?.throwIfAborted(),await e()}}async listTools(){return this.withSessionRetry(async()=>(await this.client.listTools()).tools)}async listResources(){return this.withSessionRetry(async()=>(await this.client.listResources()).resources)}async listPrompts(){return this.withSessionRetry(async()=>(await this.client.listPrompts()).prompts)}async callTool(e,t,n){let r=n?.signal?AbortSignal.any([n.signal,this.lifetime.signal]):this.lifetime.signal,i=await this.withSessionRetry(async()=>{let i={signal:r,...n?.timeout===void 0?{}:{timeout:n.timeout}},a=await this.client.callTool({name:e,arguments:t},i);if(!Ce(a))throw Error(`Unexpected interactive response from MCP tool '${e}': this call requires a context-aware relay`);return a},r);if(r.throwIfAborted(),n?.onResult)try{await n.onResult(structuredClone(i))}catch(t){this.logger.warn(`MCP result observer failed for ${this.serverName}.${e}`,t)}return r.throwIfAborted(),this.outputGuard?await this.outputGuard.guard(i):i}async readResource(e,t){let n=t?.signal?AbortSignal.any([t.signal,this.lifetime.signal]):this.lifetime.signal,r=await this.withSessionRetry(async()=>await this.client.readResource({uri:e},{signal:n,...t?.timeout===void 0?{}:{timeout:t.timeout}}),n);return n.throwIfAborted(),r}async getPrompt(e,t){return this.withSessionRetry(async()=>await this.client.getPrompt({name:e,arguments:t}))}close(){return this.closePromise||=(this.closing=!0,this.lifetime.abort(/* @__PURE__ */ Error(`MCP client '${this.serverName}' is closed`)),this.connected=!1,this.setLifecycleState(`closed`),(async()=>{let e=(await Promise.allSettled([this.releaseOwnedResources({killChild:!0}),Promise.resolve().then(()=>this.client.close())])).flatMap(e=>e.status===`rejected`?[e.reason]:[]);if(e.length)throw AggregateError(e,`Failed to close MCP client '${this.serverName}'`)})()),this.closePromise}},Zn=class{outputSchemaValidation;clientCapabilities;clients=/* @__PURE__ */ new Map;serverConfigs=/* @__PURE__ */ new Map;connectionPromises=/* @__PURE__ */ new Map;connectionControllers=/* @__PURE__ */ new Map;disposed=!1;disposePromise;logger;repositoryPath;workspaceRoot;executionCwd;env;processOwnerId=u();outputGuard;stateListeners=/* @__PURE__ */ new Set;serverStates=/* @__PURE__ */ new Map;tokenStore;onAuthorizationUrl;callbackTimeoutMs;callbackServer;resolveUrlCredentials;constructor(e=console,t=process.cwd(),n=new bn,r={},i,a,o,s,c={}){this.outputSchemaValidation=s,this.clientCapabilities=c,this.logger=e,this.repositoryPath=t,this.workspaceRoot=i,this.executionCwd=o,this.env=a,this.outputGuard=n,this.tokenStore=r.tokenStore,this.onAuthorizationUrl=r.onAuthorizationUrl,this.callbackTimeoutMs=r.callbackTimeoutMs,this.callbackServer=r.callbackServer,this.resolveUrlCredentials=r.resolveUrlCredentials}onServerStateChange(e){this.stateListeners.add(e);for(let[t,n]of this.serverStates)this.notifyListener(e,{...n,serverName:t});return()=>{this.stateListeners.delete(e)}}getServerState(e){return this.serverStates.get(e)?.state}emitServerState(e){this.serverStates.set(e.serverName,e);for(let t of this.stateListeners)this.notifyListener(t,e)}notifyListener(e,t){try{e(t)}catch(e){this.logger.warn(`[mcp-proxy] Server state listener threw for ${t.serverName}: ${e instanceof Error?e.message:String(e)}`)}}setOutputGuard(e){this.outputGuard=e}async cleanupChildProcesses(){await this.disconnectAll()}async connectToServer(e,t){this.serverConfigs.set(e,t),await this.ensureConnected(e)}registerServerConfigs(e){for(let[t,n]of Object.entries(e))this.serverConfigs.set(t,n)}getKnownServerNames(){return Array.from(this.serverConfigs.keys())}getServerRequestTimeout(e){return this.serverConfigs.get(e)?.requestTimeout}async ensureConnected(e){if(this.disposed)throw Error(`The MCP client manager is disposed`);let t=this.clients.get(e);if(t)return await t.waitUntilReady(),t;let n=this.connectionPromises.get(e);if(n)return await n;let r=this.serverConfigs.get(e);if(!r)throw Error(`No configuration found for server "${e}"`);let i=this.createConnection(e,r);this.connectionPromises.set(e,i);try{return await i}finally{this.connectionPromises.get(e)===i&&this.connectionPromises.delete(e)}}async createConnection(e,t){let n=t.timeout??3e4,r=new AbortController;this.connectionControllers.set(e,r),this.emitServerState({serverName:e,state:`connecting`});let i,a=new Promise((e,t)=>{i=()=>t(r.signal.reason),r.signal.addEventListener(`abort`,i,{once:!0}),r.signal.aborted&&i()}),o,s,c=new Promise((e,t)=>{s=e=>{clearTimeout(o),!(e||r.signal.aborted)&&(o=setTimeout(()=>{let e=/* @__PURE__ */ Error(`Connection timeout after ${n}ms`);r.abort(e),t(e)},n))},s(!1)}),l;try{l=await Promise.race([this.createSdkClientConnection(e,t,r.signal,e=>s?.(e)),c,a])}catch(n){let i=t.transport===`http`||t.transport===`sse`?t.config.auth:void 0,a=typeof i==`object`&&i?.type===`api-key`,o=n instanceof Error&&[`Invalid MCP API-key configuration.`,`MCP API-key credential is unavailable.`,`MCP credential destination was rejected.`].includes(n.message),s=a&&!o?/* @__PURE__ */ Error(`MCP API-key connection failed.`):n;throw this.emitServerState({serverName:e,state:this.disposed||r.signal.aborted&&!String(r.signal.reason).includes(`timeout`)?`closed`:Gn(s)?`needs-auth`:`failed`,error:s instanceof Error?s.message:String(s)}),s}finally{s=void 0,clearTimeout(o),r.signal.removeEventListener(`abort`,i),this.connectionControllers.get(e)===r&&this.connectionControllers.delete(e)}let u=new Xn(e,t.transport,l.client,this.logger,{instruction:t.instruction,toolBlacklist:t.toolBlacklist,omitToolDescription:t.omitToolDescription,prompts:t.prompts},this.outputGuard);u.setDisconnectedCallback(()=>void 0),u.setLifecycleChangeCallback((t,n)=>{this.emitServerState({serverName:e,state:Vn(t),...n?{error:n}:{}})});try{if(l.stdioTransport&&u.setStdioTransport(l.stdioTransport),l.processLease&&u.setProcessLease(l.processLease),r.signal.throwIfAborted(),this.disposed)throw Error(`The MCP client manager is disposed`);if(u.setConnected(!0),u.setReconnectFn(async n=>{try{if(this.disposed)throw Error(`The MCP client manager is disposed`);return await this.createSdkClientConnection(e,t,n)}catch(t){throw this.logger.warn(`Failed to reconnect to ${e}`,t),t}}),!u.serverInstruction)try{let e=u.client.getInstructions();e&&(u.serverInstruction=e)}catch(t){this.logger.warn(`Failed to get server instruction from ${e}`,t)}return this.clients.set(e,u),u}catch(e){throw await u.close(),e}}createSdkClient(e,t=`auto`){let n={name:`@agimon-ai/po-mcp-proxy-client`,version:`0.1.0`},r={capabilities:structuredClone(this.clientCapabilities),versionNegotiation:t===`legacy`?{mode:`legacy`}:{mode:`auto`,probe:{timeoutMs:1e4,maxRetries:0}}};return this.outputSchemaValidation?new Rn(n,r,e,this.outputSchemaValidation):new _e(n,r)}async createSdkClientConnection(e,t,n,r){n?.throwIfAborted();let i;if(t.transport===`stdio`)i=await this.connectStdioSdkClient(e,this.createSdkClient(e),t.config,n);else if(t.transport===`http`||t.transport===`sse`)i=await this.connectUrlSdkClient(e,t.transport,t.config,!0,n,r);else{let{transport:e}=t;throw Error(`Unsupported transport type: ${e}`)}if(n?.aborted||this.disposed)throw await Un(i),n?.throwIfAborted(),Error(`The MCP client manager is disposed`);return i}async connectUrlSdkClient(e,t,n,r=!0,i,a){i?.throwIfAborted();let o=n.auth,s=typeof o==`object`&&o?.type===`api-key`?o:void 0,c=this.resolveAuthHeaders(n),l;if(s){let r=new URL(n.url),a=s.mode===`bearer`?`Authorization`:s.name;if(s.mode!==`bearer`&&s.mode!==`header`||!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(a)||s.mode===`header`&&(a.toLowerCase()===`authorization`||/^(?:host|cookie|set-cookie|connection|keep-alive|te|trailer|upgrade|transfer-encoding|content-length|accept|origin|referer|forwarded|x-forwarded-.*|proxy-.*|sec-.*|mcp-session-id)$/i.test(a))||r.username||r.password||r.protocol!==`https:`&&!(r.protocol===`http:`&&[`localhost`,`127.0.0.1`,`[::1]`].includes(r.hostname))||n.bearerToken||n.bearerTokenEnv||n.oauth!==void 0||Object.keys(c??{}).some(e=>[`authorization`,a.toLowerCase()].includes(e.toLowerCase())))throw Error(`Invalid MCP API-key configuration.`);let o;try{o=await this.resolveUrlCredentials?.({serverName:e,transport:t,url:r.href,auth:s,signal:i})}catch{throw Error(`MCP API-key credential is unavailable.`)}i?.throwIfAborted();let u=o?.[a];if(!u||Object.keys(o??{}).length!==1||Array.from(u).some(e=>e.charCodeAt(0)<=31||e.charCodeAt(0)===127)||s.mode===`bearer`&&!/^Bearer [^\s]+$/.test(u))throw Error(`MCP API-key credential is unavailable.`);c={...c,[a]:u},l=async(e,t)=>{let n=new URL(typeof e==`string`?e:e instanceof URL?e.href:e.url);if(n.origin!==r.origin||n.username||n.password)throw Error(`MCP credential destination was rejected.`);return fetch(e,{...t,redirect:`error`})}}let u=this.createSdkClient(e,t===`sse`?`legacy`:`auto`),d=c?{headers:c}:void 0,f=this.createAuthProvider(e,n),p={requestInit:d,authProvider:f,...l?{fetch:l}:{}},m=t===`http`?new xe(new URL(n.url),p):new be(new URL(n.url),p),h=()=>{f?.cancelAuthorization(),u.close().catch(t=>this.logger.warn(`Failed to close cancelled client ${e}`,s?`API-key connection closed`:t))};i?.addEventListener(`abort`,h,{once:!0});let g=!1;try{return await u.connect(m),i?.throwIfAborted(),g=!0,{client:u}}catch(o){if(i?.throwIfAborted(),s)throw Error(`MCP API-key connection failed.`);if(!f||!r||!Gn(o)||!f.hasPendingAuthorization())throw o;this.logger.info(`[oauth] Waiting for authorization of MCP server "${e}"`),a?.(!0);let c=await f.waitForAuthorizationCallback();return i?.throwIfAborted(),a?.(!1),this.emitServerState({serverName:e,state:`connecting`}),await m.finishAuth(c),i?.throwIfAborted(),await this.connectUrlSdkClient(e,t,n,!1,i,a)}finally{i?.removeEventListener(`abort`,h),g||(f?.cancelAuthorization(),await u.close().catch(t=>this.logger.warn(`Failed to close client ${e}`,s?`API-key connection closed`:t)))}}resolveAuthHeaders(e){let t={...e.headers};if(ht(e)===`bearer`){let n=e.bearerTokenEnv?this.env?.[e.bearerTokenEnv]??_t(e):_t(e);n?t.Authorization=`Bearer ${n}`:this.logger.warn(`[oauth] Bearer auth configured for an MCP server but no token was resolved${e.bearerTokenEnv?` (env ${e.bearerTokenEnv} is unset)`:``}.`)}return Object.keys(t).length>0?t:void 0}createAuthProvider(e,t){return vt({serverName:e,config:t,store:this.tokenStore,logger:this.logger,callbackTimeoutMs:this.callbackTimeoutMs,workspaceRoot:this.repositoryPath,...this.callbackServer?{callbackServer:this.callbackServer}:{},onAuthorizationUrl:(e,t)=>{if(this.emitServerState({serverName:t,state:`needs-auth`}),this.onAuthorizationUrl)return this.onAuthorizationUrl(e,t);this.logger.info(`[oauth] Authorize MCP server "${t}" by visiting: ${e.toString()}`)}})}relayChildStderr(e,t){t&&(t.on(`data`,t=>{let n=t.toString(`utf8`).trimEnd();n&&this.logger.debug(`[${e}] ${n}`)}),t.on(`error`,()=>void 0))}async connectStdioSdkClient(e,t,n,r){let i=new we({command:n.command,args:n.args,cwd:this.executionCwd?a(this.executionCwd,n.cwd??`.`):this.workspaceRoot?a(this.workspaceRoot,n.cwd??`.`):n.cwd,env:{...process.env,...this.env,...n.env,PROJECT_PATH:this.repositoryPath,[ae]:zn,[ie]:this.processOwnerId},stderr:`pipe`}),o=()=>{Un({client:t,stdioTransport:i}).catch(t=>this.logger.warn(`Failed to close cancelled stdio connection for ${e}`,t))};r?.addEventListener(`abort`,o,{once:!0});try{r?.throwIfAborted(),await t.connect(i),r?.throwIfAborted(),this.relayChildStderr(e,i.stderr);let a=i.pid;if(typeof a!=`number`||a<=0)throw Error(`Failed to capture pid for stdio child process on server "${e}"`);let o=await se({repositoryPath:this.repositoryPath,serviceName:e,serviceType:`tool`,pid:a,command:n.command,args:n.args,metadata:{transport:`stdio`},ownerKind:zn,ownerId:this.processOwnerId,resourceKey:e});return t.onclose=()=>{let t=this.clients.get(e);t instanceof Xn&&t.handleStdioClosed(i)},{client:t,processLease:o,stdioTransport:i}}catch(n){try{await Un({client:t,stdioTransport:i})}catch(t){this.logger.warn(`Failed to clean up incomplete stdio connection for ${e}`,t)}throw n}finally{r?.removeEventListener(`abort`,o)}}getClient(e){return this.clients.get(e)}getAllClients(){return Array.from(this.clients.values())}async disconnectServer(e){this.connectionControllers.get(e)?.abort(/* @__PURE__ */ Error(`MCP connection '${e}' was closed`));let t=this.connectionPromises.get(e);this.connectionPromises.delete(e);let n=this.clients.get(e);this.clients.delete(e),await Promise.all([t?.catch(()=>void 0),n?.close()])}async disconnectAll(){let e=[...this.clients.values()],t=[...this.connectionPromises.values()];this.clients.clear(),this.connectionPromises.clear();for(let e of this.connectionControllers.values())e.abort(/* @__PURE__ */ Error(`MCP connections were closed`));this.connectionControllers.clear();let n=(await Promise.allSettled([...e.map(e=>e.close()),...t.map(e=>e.catch(()=>void 0))])).flatMap(e=>e.status===`rejected`?[e.reason]:[]);if(n.length)throw AggregateError(n,`Failed to close MCP connections`)}dispose(){return this.disposed=!0,this.disposePromise??=this.disconnectAll(),this.disposePromise}isConnected(e){return this.clients.get(e)?.getLifecycleState()===`connected`}getConnectionState(e){return this.clients.get(e)?.getLifecycleState()}};const Qn=`install`,$n=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,er=`pipe`;function tr(e){return typeof e==`object`&&!!e&&`command`in e}var nr=class{config;constructor(e){this.config=e}extractPackages(){let e=[],{mcpConfig:t,filter:n}=this.config;for(let[r,i]of Object.entries(t.mcpServers)){if(i.disabled||i.transport!==`stdio`||!tr(i.config))continue;let t=this.extractPackageInfo(r,i.config);if(t){if(n&&t.packageManager!==n)continue;e.push(t)}}return e}async prefetch(){try{let e=this.extractPackages(),t=[];if(e.length===0)return{totalPackages:0,successful:0,failed:0,results:[]};if(this.config.parallel){let n=e.map(async e=>this.prefetchPackage(e));t.push(...await Promise.all(n))}else for(let n of e){let e=await this.prefetchPackage(n);t.push(e)}let n=t.filter(e=>e.success).length,r=t.filter(e=>!e.success).length;return{totalPackages:e.length,successful:n,failed:r,results:t}}catch(e){throw Error(`Failed to prefetch packages: ${e instanceof Error?e.message:String(e)}`)}}async prefetchPackage(e){try{let[t,...n]=e.fullCommand,r=await this.runCommand(t,n);return{package:e,success:r.success,output:r.output}}catch(t){return{package:e,success:!1,output:t instanceof Error?t.message:String(t)}}}isValidPackageName(e){return $n.test(e)}extractPackageInfo(e,t){let n=t.command.toLowerCase(),r=t.args||[];if(n===`npx`||n.endsWith(`/npx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`npx`,packageName:t,fullCommand:[`npm`,Qn,`-g`,t]}}if(n===`pnpx`||n.endsWith(`/pnpx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`pnpx`,packageName:t,fullCommand:[`pnpm`,`add`,`-g`,t]}}if(n===`uvx`||n.endsWith(`/uvx`)){let t=this.extractUvxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uvx`,packageName:t,fullCommand:[`uvx`,t]}}if((n===`uv`||n.endsWith(`/uv`))&&r.includes(`run`)){let t=this.extractUvRunPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uv`,packageName:t,fullCommand:[`uv`,`tool`,Qn,t]}}return null}extractNpxPackage(e){for(let t=0;t<e.length;t++){let n=e[t];if(n.startsWith(`--package=`))return n.slice(10)||null;if(n===`--package`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}if(n===`-p`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}}for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvxPackage(e){for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvRunPackage(e){let t=e.indexOf(`run`);if(t===-1)return null;for(let n=t+1;n<e.length;n++){let t=e[n];if(!t.startsWith(`-`))return t}return null}runCommand(e,t){return new Promise(n=>{let r=D(e,t,{stdio:[`ignore`,er,er],shell:process.platform===`win32`}),i=``,a=``;r.stdout?.on(`data`,e=>{i+=e.toString()}),r.stderr?.on(`data`,e=>{a+=e.toString()}),r.on(`close`,e=>{n({success:e===0,output:i||a})}),r.on(`error`,e=>{n({success:!1,output:e.message})})})}};const rr=`.runtime.json`;async function ir(e){await g(e,{recursive:!0,mode:448});try{await m(e,448)}catch{}}function ar(e){return typeof e==`object`&&!!e}function or(e){return ar(e)?typeof e.serverId==`string`&&typeof e.host==`string`&&typeof e.port==`number`&&e.transport===`http`&&typeof e.shutdownToken==`string`&&typeof e.startedAt==`string`&&typeof e.pid==`number`&&(e.configPath===void 0||typeof e.configPath==`string`)&&(e.runtimeLifecycle===void 0||e.runtimeLifecycle===`manual`||e.runtimeLifecycle===`stdio-http-managed`):!1}function sr(e){return e instanceof Error?e.message:String(e)}function cr(e){try{return process.kill(e,0),!0}catch{return!1}}var K=class e{runtimeDir;logger;constructor(t,n=console){this.runtimeDir=t??e.getDefaultRuntimeDir(),this.logger=n}static getDefaultRuntimeDir(){return i(E(),`.mcp-proxy`,`runtimes`)}getRecordPath(e){return i(this.runtimeDir,`${e}${rr}`)}async write(e){await ir(this.runtimeDir);let t=this.getRecordPath(e.serverId);await T(t,JSON.stringify(e,null,2),{encoding:`utf-8`,mode:384})}async read(e){let t=this.getRecordPath(e);try{let e=await y(t,`utf-8`),n=JSON.parse(e);return or(n)?n:null}catch(n){if(ar(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${sr(n)}`)}}async list(){try{let e=(await b(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(rr));return(await Promise.all(e.map(async e=>{try{let t=await y(i(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return or(n)?n:null}catch(t){return this.logger.debug(`Skipping unreadable runtime state file ${e.name}`,t),null}}))).filter(e=>e!==null)}catch(e){if(ar(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${sr(e)}`)}}async listOrphans(e){return(await this.list()).filter(t=>!e.has(t.serverId))}async pruneStale(){let e=(await this.list()).filter(e=>!cr(e.pid));return await Promise.all(e.map(async e=>this.remove(e.serverId))),e}async remove(e){await S(this.getRecordPath(e),{force:!0})}},lr=class extends Error{filePath;cause;constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function ur(e){try{return await p(e),!0}catch(t){if(t instanceof Error&&`code`in t&&t.code===`ENOENT`)return!1;throw Error(`Failed to check path existence for "${e}": ${t instanceof Error?t.message:`Unknown error`}`)}}var dr=class{cwd;skillPaths;cachedSkills=null;skillsByName=null;watchers=[];pollingTimers=[];onCacheInvalidated;logger;constructor(e,t,n,r=console){this.cwd=e,this.skillPaths=t,this.onCacheInvalidated=n?.onCacheInvalidated,this.logger=r}async getSkills(){if(this.cachedSkills!==null)return this.cachedSkills;let e=[],t=/* @__PURE__ */ new Set,n=await Promise.all(this.skillPaths.map(async e=>{let t=r(e)?e:i(this.cwd,e);return this.loadSkillsFromDirectory(t,`project`)}));for(let r of n)for(let n of r)t.has(n.name)||(e.push(n),t.add(n.name));return this.cachedSkills=e,this.skillsByName=new Map(e.map(e=>[e.name,e])),e}async getSkill(e){return this.skillsByName===null&&await this.getSkills(),this.skillsByName?.get(e)}clearCache(){this.cachedSkills=null,this.skillsByName=null}async startWatching(){this.stopWatching();let e=await Promise.all(this.skillPaths.map(async e=>{let t=r(e)?e:i(this.cwd,e);return{skillsDir:t,exists:await ur(t)}}));for(let{skillsDir:t,exists:n}of e){if(!n)continue;let e=new AbortController;this.watchers.push(e),this.watchDirectory(t,e.signal).catch(n=>{if(n?.name!==`AbortError`){if(this.isWatchResourceLimitError(n)){this.startPollingDirectory(t,e.signal);return}this.logger.warn(`[skill-watcher] Error watching ${t}: ${n instanceof Error?n.message:`Unknown error`}`)}})}}stopWatching(){for(let e of this.watchers)e.abort();this.watchers=[];for(let e of this.pollingTimers)clearInterval(e);this.pollingTimers=[]}async watchDirectory(e,t){let n=te(e,{recursive:!0,signal:t});for await(let e of n)e.filename?.endsWith(`SKILL.md`)&&this.invalidateCache()}invalidateCache(){this.clearCache(),this.onCacheInvalidated?.()}isWatchResourceLimitError(e){return e instanceof Error&&`code`in e&&(e.code===`EMFILE`||e.code===`ENOSPC`)}startPollingDirectory(e,t){this.createSkillSnapshot(e).then(n=>{let r=n,i=setInterval(()=>{t.aborted?clearInterval(i):this.createSkillSnapshot(e).then(e=>{this.snapshotsEqual(r,e)||(r=e,this.invalidateCache())}).catch(t=>{this.logger.warn(`[skill-watcher] Polling failed for ${e}: ${t instanceof Error?t.message:`Unknown error`}`)})},3e3);this.pollingTimers.push(i),t.addEventListener(`abort`,()=>{clearInterval(i),this.pollingTimers=this.pollingTimers.filter(e=>e!==i)},{once:!0})})}async createSkillSnapshot(e){let t=/* @__PURE__ */ new Map;return await this.collectSkillSnapshots(e,t),t}async collectSkillSnapshots(e,t){let n;try{n=await b(e)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(n.map(async n=>{let r=i(e,n),a=await C(r);a.isDirectory()?await this.collectSkillSnapshots(r,t):n===`SKILL.md`&&t.set(r,a.mtimeMs)}))}snapshotsEqual(e,t){if(e.size!==t.size)return!1;for(let[n,r]of e)if(t.get(n)!==r)return!1;return!0}async loadSkillsFromDirectory(e,t){let n=[];try{if(!await ur(e))return n}catch(t){throw new lr(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await b(e)}catch(t){throw new lr(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let a=await Promise.all(r.map(async t=>{let n=i(e,t);try{return{entry:t,entryPath:n,stat:await C(n),error:null}}catch(e){return this.logger.warn(`Skipping entry ${n}: ${e instanceof Error?e.message:`Unknown error`}`),{entry:t,entryPath:n,stat:null,error:e}}})),o=[];for(let{entry:e,entryPath:t,stat:n}of a)if(n){if(n.isDirectory()){let e=i(t,`SKILL.md`);o.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&o.push({filePath:t,isRootLevel:!0})}let s=await Promise.all(o.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await ur(e)?null:await this.loadSkillFile(e,t)}catch(t){return this.logger.warn(`Skipping skill at ${e}: ${t instanceof Error?t.message:`Unknown error`}`),null}}));for(let e of s)e&&n.push(e);return n}async loadSkillFile(e,t){let r;try{r=await y(e,`utf-8`)}catch(t){throw new lr(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:i,content:a}=an(r);return!i||!i.name||!i.description?null:{name:i.name,description:i.description,location:t,content:a,basePath:n(e)}}};const fr=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`::1`]);function pr(e){return e}function mr(e){if(typeof e!=`object`||!e)return!1;let t=pr(e);return`status`in t&&t.status===`ok`&&`transport`in t&&t.transport===`http`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)&&(!(`runtimeLifecycle`in t)||t.runtimeLifecycle===void 0||t.runtimeLifecycle===`manual`||t.runtimeLifecycle===`stdio-http-managed`)}function hr(e){if(typeof e!=`object`||!e)return!1;let t=pr(e);return`ok`in t&&typeof t.ok==`boolean`&&`message`in t&&typeof t.message==`string`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)}function gr(e,t){if(!fr.has(e.host))throw Error(`Refusing to connect to non-loopback host '${e.host}'. Only ${Array.from(fr).join(`, `)} are allowed.`);return`http://${e.host}:${e.port}${t}`}function _r(e){return e instanceof Error?e.message:String(e)}function vr(e){return new Promise(t=>{setTimeout(t,e)})}var yr=class{runtimeStateService;logger;constructor(e=new K,t=console){this.runtimeStateService=e,this.logger=t}async stop(e){let t=e.timeoutMs??5e3;await this.pruneStaleRuntimeRecords();let n=await this.resolveRuntime(e),r=await this.fetchHealth(n,t);if(!r.reachable)throw await this.runtimeStateService.remove(n.serverId),Error(`Runtime '${n.serverId}' is not reachable at http://${n.host}:${n.port}. Removed stale runtime record.`);if(!e.force&&r.payload?.serverId&&r.payload.serverId!==n.serverId)throw Error(`Refusing to stop runtime at http://${n.host}:${n.port}: expected server ID '${n.serverId}' but health endpoint reported '${r.payload.serverId}'. Use --force to override.`);let i=e.token??n.shutdownToken;if(!i)throw Error(`No shutdown token available for runtime '${n.serverId}'.`);let a=await this.requestShutdown(n,i,t);return await this.waitForShutdown(n,t),await this.runtimeStateService.remove(n.serverId),{ok:!0,serverId:n.serverId,host:n.host,port:n.port,message:a.message}}async resolveRuntime(e){if(e.serverId){let t=await this.runtimeStateService.read(e.serverId);if(!t)throw Error(`No runtime record found for server ID '${e.serverId}'. Start the server with 'po-mcp-proxy mcp-serve --type http' first.`);return t}if(e.host===void 0||e.port===void 0)throw Error(`Provide --id or both --host and --port to select a runtime.`);let t=(await this.runtimeStateService.list()).filter(t=>t.host===e.host&&t.port===e.port);if(t.length===0)throw Error(`No runtime record found for http://${e.host}:${e.port}. Start the server with 'po-mcp-proxy mcp-serve --type http' first.`);if(t.length>1)throw Error(`Multiple runtime records match http://${e.host}:${e.port}. Retry with --id to avoid stopping the wrong server.`);return t[0]}async pruneStaleRuntimeRecords(){if(this.runtimeStateService.pruneStale)try{await this.runtimeStateService.pruneStale()}catch(e){this.logger.debug(`Failed to prune stale runtime records before stop resolution`,e)}}async fetchHealth(e,t){try{let n=await this.fetchWithTimeout(gr(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!mr(r))throw Error(`Received invalid health response payload.`);return{reachable:!0,payload:r}}catch(t){return this.logger.debug(`Health check failed for ${e.serverId}`,t),{reachable:!1}}}async requestShutdown(e,t,n){let r=await this.fetchWithTimeout(gr(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!hr(i))throw Error(`Received invalid shutdown response payload.`);if(!r.ok||!i.ok)throw Error(i.message);return i}async waitForShutdown(e,t){let n=Date.now()+t;for(;Date.now()<n;){if(!(await this.fetchHealth(e,Math.max(250,n-Date.now()))).reachable)return;await vr(200)}throw Error(`Timed out waiting for runtime '${e.serverId}' to stop at http://${e.host}:${e.port}.`)}async fetchWithTimeout(e,t,n){let r=new AbortController,i=setTimeout(()=>{r.abort()},n);try{return await fetch(e,{...t,signal:r.signal})}catch(t){throw Error(`Request to '${e}' failed: ${_r(t)}`)}finally{clearTimeout(i)}}};function q(e){return e instanceof Error?e.message:String(e)}function br(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);return n.length===r.length&&d(n,r)}var xr=class{requests=/* @__PURE__ */ new Map;isAllowed(e){let t=Date.now()-6e4,n=(this.requests.get(e)??[]).filter(e=>e>t);return n.length>=5?(this.requests.set(e,n),!1):(n.push(Date.now()),this.requests.set(e,n),!0)}},Sr=class{honoApp=new Me;adminRateLimiter=new xr;config;mcpHandler;nodeMcpHandler;adminOptions;logger;server=null;lastRequestAt=Date.now();activeRequests=0;idleTimer=null;constructor(e,t,n,r=console){this.config={mode:t.mode,host:t.host??`localhost`,port:t.port},this.adminOptions=n,this.logger=r,this.mcpHandler=pe(e,{legacy:`reject`,onerror:e=>this.logger.error(`MCP handler failed: ${e.message}`)}),this.nodeMcpHandler=je(this.mcpHandler,{onerror:e=>this.logger.error(`Failed to adapt MCP request: ${e.message}`)}),this.setupHonoRoutes()}setupHonoRoutes(){this.honoApp.get(`/health`,e=>{let t={status:`ok`,transport:`http`,serverId:this.adminOptions?.serverId,runtimeLifecycle:this.adminOptions?.runtimeLifecycle,protocolVersion:`2026-07-28`,runtimeEpoch:`modern-2026-07-28-v1`};return e.json(t)}),this.honoApp.post(`/admin/shutdown`,async e=>{try{let t=e.req.header(`x-forwarded-for`)??`unknown`;if(!this.adminRateLimiter.isAllowed(t)){let t={ok:!1,message:`Too many shutdown requests. Try again later.`,serverId:this.adminOptions?.serverId};return e.json(t,429)}return await this.handleAdminShutdownRequest(e)}catch(t){this.logger.error(`Failed to process shutdown request: ${q(t)}`);let n={ok:!1,message:`Failed to process shutdown request.`,serverId:this.adminOptions?.serverId};return e.json(n,500)}})}isAuthorizedShutdownRequest(e){let t=this.adminOptions?.shutdownToken;if(!t)return!1;let n=e.authorization;if(typeof n==`string`&&n.startsWith(`Bearer `))return br(n.slice(7),t);let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&br(r,t)}async handleAdminShutdownRequest(e){if(!this.adminOptions?.onShutdownRequested)return e.json({ok:!1,message:`Shutdown endpoint is not enabled for this server instance.`,serverId:this.adminOptions?.serverId},404);if(!this.isAuthorizedShutdownRequest({authorization:e.req.header(`authorization`),"x-mcp-proxy-shutdown-token":e.req.header(`x-mcp-proxy-shutdown-token`)}))return e.json({ok:!1,message:`Unauthorized shutdown request: invalid or missing shutdown token.`,serverId:this.adminOptions?.serverId},401);let t=e.json({ok:!0,message:`Shutdown request accepted. Stopping server gracefully.`,serverId:this.adminOptions?.serverId});return this.adminOptions.onShutdownRequested().catch(e=>{this.logger.error(`Shutdown request failed: ${q(e)}`)}),t}async handleMcpRequest(e,t){this.activeRequests+=1;try{await this.nodeMcpHandler(e,t)}catch(e){this.logger.error(`MCP request failed: ${q(e)}`),t.headersSent||(t.writeHead(500,{"Content-Type":`application/json`}),t.end(JSON.stringify({jsonrpc:`2.0`,error:{code:-32603,message:`MCP request failed.`},id:null})))}finally{--this.activeRequests,this.lastRequestAt=Date.now()}}startIdleShutdownMonitor(){let e=this.adminOptions?.idleShutdownMs??0;e<=0||this.idleTimer||(this.lastRequestAt=Date.now(),this.idleTimer=setInterval(()=>{this.shutdownWhenIdle(e)},Math.min(e,6e4)))}stopIdleShutdownMonitor(){this.idleTimer&&=(clearInterval(this.idleTimer),null)}async shutdownWhenIdle(e){let t=this.adminOptions?.onShutdownRequested;if(!(!t||this.activeRequests>0||Date.now()-this.lastRequestAt<e)){this.stopIdleShutdownMonitor(),this.logger.info(`Stopping idle HTTP runtime after ${e}ms without active requests`);try{await t()}catch(e){this.logger.error(`Failed to stop idle HTTP runtime: ${q(e)}`)}}}async start(){if(this.server)throw Error(`HTTP transport is already running`);let e=Ae(this.honoApp.fetch),t=f((t,n)=>{this.lastRequestAt=Date.now(),new URL(t.url??`/`,`http://${t.headers.host??this.config.host}`).pathname===`/mcp`?this.handleMcpRequest(t,n):e(t,n)});try{t.listen(this.config.port,this.config.host),await Promise.race([De(t,`listening`),De(t,`error`).then(([e])=>Promise.reject(e))]),this.server=t,this.startIdleShutdownMonitor(),this.logger.info(`@agimon-ai/po-mcp-proxy MCP server started on http://${this.config.host}:${this.config.port}/mcp`),this.logger.info(`Health check: http://${this.config.host}:${this.config.port}/health`)}catch(e){throw t.close(),Error(`Failed to start HTTP transport: ${q(e)}`,{cause:e})}}async stop(){this.stopIdleShutdownMonitor();let e=this.server;if(e){this.server=null,await this.mcpHandler.close();try{await ke(e.close.bind(e))()}catch(e){throw Error(`Failed to stop HTTP transport: ${q(e)}`,{cause:e})}}}getPort(){let e=this.server?.address();return e&&typeof e==`object`?e.port:this.config.port}getHost(){return this.config.host}};const Cr=`localhost`,wr=12e4,Tr=`MCP_PROXY_RUNTIME_DETACHED`;function Er(){return process.env[Tr]===`1`}async function Dr(e){return(await new oe(process.env.PROCESS_REGISTRY_PATH).listProcesses({repositoryPath:e,serviceName:`mcp-proxy-http`,liveOnly:!0})).filter(e=>!!(e.host&&e.port)).map(e=>{let t=e.metadata;return{host:e.host,port:e.port,serverId:t?.serverId??`unknown`,runtimeLifecycle:t?.runtimeLifecycle===`stdio-http-managed`||t?.runtimeLifecycle===`manual`?t.runtimeLifecycle:void 0,createdAt:e.createdAt}}).sort((e,t)=>(e.createdAt??``).localeCompare(t.createdAt??``))}async function Or(e){let t=await Dr(e);for(let e of t)if(kr(await Ar(e.host,e.port)))return e;return null}function kr(e){return e.ok&&e.payload?.status===`ok`&&e.payload.transport===`http`&&e.payload.protocolVersion===`2026-07-28`&&e.payload.runtimeEpoch===`modern-2026-07-28-v1`}async function Ar(e,t,n={}){let r=n.timeoutMs??1500,i=n.retries??2,a=n.retryDelayMs??150,o=i+1,s=`unknown error`;for(let n=1;n<=o;n+=1){try{let i=await fetch(`http://${e}:${t}/health`,{signal:AbortSignal.timeout(r)});if(i.ok)return{ok:!0,payload:await i.json().catch(()=>null)??void 0,attempts:n};s=`health endpoint returned status ${i.status}`}catch(e){s=e instanceof Error?e.message:String(e)}n<o&&await new Promise(e=>setTimeout(e,a))}return{ok:!1,error:s,attempts:o}}function jr(){let n=re(import.meta.url),r=t.dirname(n),i=[t.resolve(r,`cli.mjs`),t.resolve(r,`..`,`dist`,`cli.mjs`),t.resolve(r,`..`,`..`,`dist`,`cli.mjs`)],a=[t.resolve(r,`..`,`cli.ts`),t.resolve(r,`..`,`..`,`src`,`cli.ts`)];for(let t of i)if(e(t))return{command:process.execPath,args:[t]};for(let t of a)if(e(t))return{command:process.execPath,args:[`--import`,`tsx`,t]};throw Error(`Unable to locate mcp-proxy CLI entrypoint`)}function Mr(e){if(!e)return wr;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid timeout value: ${e}`);return t}async function Nr(e,t){let n=Date.now()+t;for(;Date.now()<n;){try{await p(e);return}catch{}await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for runtime state file: ${e}`)}async function Pr(e,t){let n=new K,r=Date.now()+t;for(;Date.now()<r;){let t=await n.read(e);if(t&&kr(await Ar(t.host,t.port,{retries:0})))return{host:t.host,port:t.port};await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for HTTP runtime '${e}' to become healthy`)}function Fr(e,t,n){let{command:r,args:i}=jr(),a=D(r,[...i,...e],{detached:!0,cwd:n,stdio:`ignore`,env:t});return a.unref(),a}async function Ir(e){let n=e.id||rn(),r=Mr(e.timeoutMs),i=e.registryPath||e.registryDir,a=k();await new K().pruneStale();let o=await Or(a);if(o)return{host:o.host,port:o.port,serverId:o.serverId,workspaceRoot:a,reusedExistingRuntime:!0,runtimeLifecycle:o.runtimeLifecycle??`manual`};let s=e.port,c=await Dr(a);if(e.id&&c.some(e=>e.serverId===n))throw Error(`Runtime ID '${n}' belongs to an incompatible HTTP runtime; choose a new ID`);if(s!==void 0&&c.some(t=>t.host===(e.host||Cr)&&t.port===s))throw Error(`Port ${s} belongs to a different HTTP runtime; choose a free port`);let l=s,u={...process.env,[Tr]:`1`,...e.runtimeLifecycle?{MCP_PROXY_RUNTIME_LIFECYCLE:e.runtimeLifecycle}:{},...i?{PORT_REGISTRY_PATH:i,PROCESS_REGISTRY_PATH:ce(i,`processes.json`)}:{}},d=Fr([`mcp-serve`,`--type`,`http`,`--id`,n,`--host`,e.host||Cr,...l===void 0?[]:[`--port`,String(l)],...en(e.config).flatMap(e=>[`--config`,e]),...e.cache===!1?[`--no-cache`]:[],...e.definitionsCache?[`--definitions-cache`,e.definitionsCache]:[],...e.clearDefinitionsCache?[`--clear-definitions-cache`]:[],...e.idleShutdownMinutes===void 0?[]:[`--idle-shutdown-minutes`,String(e.idleShutdownMinutes)],`--proxy-mode`,e.proxyMode],u,a),f=new Promise((e,t)=>{d.once(`exit`,(e,n)=>{t(/* @__PURE__ */ Error(`Background runtime exited before becoming healthy (code=${e??`null`}, signal=${n??`null`})`))})}),p=t.join(K.getDefaultRuntimeDir(),`${n}.runtime.json`);try{await Promise.race([Nr(p,r),f]);let{host:t,port:i}=await Promise.race([Pr(n,r),f]);return{host:t,port:i,serverId:n,workspaceRoot:a,reusedExistingRuntime:!1,runtimeLifecycle:e.runtimeLifecycle??`manual`}}catch(e){throw Error(`Failed to prestart HTTP runtime '${n}': ${e instanceof Error?e.message:String(e)}`,{cause:e})}}function Lr(e){process.stdout.write(`mcp-proxy HTTP runtime ready at http://${e.host}:${e.port} (${e.serverId})\n`),process.stdout.write(`runtimeId=${e.serverId}\n`),process.stdout.write(`runtimeUrl=http://${e.host}:${e.port}\n`),process.stdout.write(`workspaceRoot=${e.workspaceRoot}\n`)}var Rr=`0.0.1-alpha.2`,zr=`<toolkit id="{{ serverId }}">
10
- <instruction>
11
- Before you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:
12
- - For tools: Arguments schema needed to pass to use_tool
13
- - For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)
14
-
15
- This tool is optimized for batch queries - you can request multiple capabilities at once for better performance.
16
-
17
- How to invoke:
18
- - For MCP tools: Use use_tool with toolName and toolArgs based on the schema
19
- - For skills: Use this tool with the skill name to get expanded instructions
20
- </instruction>
21
-
22
- <available_capabilities>
23
- {% for server in servers -%}
24
- <group original-mcp-server="{{ server.name }}">
25
- {% if server.instruction -%}
26
- <group_instruction>{{ server.instruction }}</group_instruction>
27
- {% endif -%}
28
- {% if server.omitToolDescription -%}
29
- {% for toolName in server.toolNames -%}
30
- <item name="{{ toolName }}"></item>
31
- {% endfor -%}
32
- {% else -%}
33
- {% for tool in server.tools -%}
34
- <item name="{{ tool.displayName }}"><description>{{ tool.description | default: "No description" }}</description></item>
35
- {% endfor -%}
36
- {% endif -%}
37
- </group>
38
- {% endfor -%}
39
- {% if skills.size > 0 -%}
40
- <group name="skills">
41
- {% for skill in skills -%}
42
- <item name="{{ skill.displayName }}"><description>{{ skill.description }}</description></item>
43
- {% endfor -%}
44
- </group>
45
- {% endif -%}
46
- </available_capabilities>
47
- </toolkit>
48
- `;function Br(e,t){return`<command-message>The "${e}" skill is loading</command-message>\n${t}`}const J=O.object({toolNames:O.array(O.string().min(1)).min(1).describe(`List of tool names to get detailed information about`)});var Y=class e{static TOOL_NAME=`describe_tools`;clientManager;skillService;definitionsCacheService;liquid=new Ne;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.serverId=n||`unknown`,this.definitionsCacheService=r||new U(e,t)}clearAutoDetectedSkillsCache(){this.definitionsCacheService.clearLiveCache()}async collectPromptSkills(){let e=[],t=await this.definitionsCacheService.getServerDefinitions();for(let n of t)for(let t of n.promptSkills)e.push({name:t.skill.name,displayName:t.skill.name,description:t.skill.description});return e}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}async getPromptSkillContent(e){let t=await this.findPromptSkill(e);if(t)try{let e=(await(await this.clientManager.ensureConnected(t.serverName)).getPrompt(t.promptName)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
49
- `)||``;return{name:t.skill.name,location:t.skill.folder||`prompt:${t.serverName}/${t.promptName}`,instructions:Br(t.skill.name,e)}}catch(t){console.error(`Failed to get prompt-based skill '${e}': ${t instanceof Error?t.message:`Unknown error`}`);return}}async buildToolkitDescription(){let e=await this.definitionsCacheService.getServerDefinitions(),t=/* @__PURE__ */ new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=(e,n)=>(t.get(e)||[]).length>1?`${n}__${e}`:e,r=/* @__PURE__ */ new Set,i=e.map(e=>{let t=e.tools.map(t=>({displayName:n(t.name,e.serverName),description:t.description}));for(let e of t)r.add(e.displayName);return{name:e.serverName,instruction:e.serverInstruction,omitToolDescription:e.omitToolDescription||!1,tools:t,toolNames:t.map(e=>e.displayName)}}),[a,o,s]=await Promise.all([this.skillService?this.skillService.getSkills():Promise.resolve([]),this.definitionsCacheService.getCachedFileSkills(),this.collectPromptSkills()]),c=/* @__PURE__ */ new Set,l=[];for(let e of a)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of o)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of s)c.has(e.name)||(c.add(e.name),l.push(e));let u=l.map(e=>{let t=r.has(e.name);return{name:e.name,displayName:t?`skill__${e.name}`:e.name,description:e.description}});return{content:await this.liquid.parseAndRender(zr,{servers:i,skills:u,serverId:this.serverId}),toolNames:r}}getInputSchema(){return J}async getDefinition(){let{content:t}=await this.buildToolkitDescription();return{name:e.TOOL_NAME,description:t,inputSchema:O.toJSONSchema(J,{reused:`inline`})}}async runLookups(e,t){let n=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Map;for(let e of t){let t=e.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));n.set(e.serverName,t);for(let n of t)r.has(n.name)||r.set(n.name,[]),r.get(n.name)?.push(e.serverName)}let i=await Promise.all(e.map(async e=>{let t={tools:[],skills:[],notFound:null};if(e.startsWith(`skill__`)){let n=e.slice(7);if(this.skillService){let e=await this.skillService.getSkill(n);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:Br(e.name,e.content)}),t}let r=await this.getPromptSkillContent(n);return r?(t.skills.push(r),t):(t.notFound=e,t)}let{serverName:i,actualToolName:a}=B(e);if(i){let r=n.get(i);if(!r){try{let n=(await(await this.clientManager.ensureConnected(i)).listTools()).find(e=>e.name===a);n?t.tools.push({server:i,tool:{name:n.name,description:n.description,inputSchema:n.inputSchema}}):t.notFound=e}catch{t.notFound=e}return t}let o=r.find(e=>e.name===a);return o?t.tools.push({server:i,tool:{name:o.name,description:o.description,inputSchema:o.inputSchema}}):t.notFound=e,t}let o=r.get(a);if(!o||o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:Br(e.name,e.content)}),t}let n=await this.getPromptSkillContent(a);return n?(t.skills.push(n),t):(t.notFound=e,t)}for(let e of o){let r=n.get(e).find(e=>e.name===a);t.tools.push({server:e,tool:{name:r.name,description:r.description,inputSchema:r.inputSchema}})}return t})),a=[],o=[],s=[];for(let e of i)a.push(...e.tools),o.push(...e.skills),e.notFound&&s.push(e.notFound);return{foundTools:a,foundSkills:o,notFoundItems:s}}async execute(e){try{let{toolNames:t}=J.parse(e);if(!t||t.length===0)return{content:[{type:`text`,text:`No tool names provided. Please specify at least one tool name.`}],isError:!0};let n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions());n.notFoundItems.length>0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions()));let{foundTools:r,foundSkills:i,notFoundItems:a}=n;if(r.length===0&&i.length===0)return{content:[{type:`text`,text:`None of the requested tools/skills found.\nRequested: ${t.join(`, `)}\nUse describe_tools to see available tools and skills.`}],isError:!0};let o={},s=[];return r.length>0&&(o.tools=r,s.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`)),i.length>0&&(o.skills=i,s.push(`For skill, just follow skill's description to continue.`)),s.length>0&&(o.nextSteps=s),a.length>0&&(o.notFound=a,o.warnings=[`Items not found: ${a.join(`, `)}`]),{content:[{type:`text`,text:JSON.stringify(o,null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error describing tools: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};function Vr(e){let t=e._meta?.[`agiflowai/capabilities`];return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}function Hr(e){return Array.from(new Set(e.flatMap(e=>Vr(e)))).sort()}const Ur=O.object({capability:O.string().optional().describe(`Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions.`),serverName:O.string().optional().describe(`Optional server name filter.`)});var Wr=class e{_clientManager;definitionsCacheService;static TOOL_NAME=`list_tools`;constructor(e,t){this._clientManager=e,this.definitionsCacheService=t}formatToolName(e,t,n){return(n.get(e)||[]).length>1?`${t}__${e}`:e}getInputSchema(){return Ur}async getDefinition(){let t=await this.definitionsCacheService.getServerDefinitions(),n=t.length>0?t.map(e=>{let t=Hr(e.tools),n=t.length>0?t.join(`, `):e.serverInstruction||`No capability summary available`;return`${e.serverName}: ${n}`}).join(`
50
- `):`No proxied servers available.`;return{name:e.TOOL_NAME,description:`Search proxied MCP tools by server capability summary.\n\nAvailable capabilities:\n${n}`,inputSchema:O.toJSONSchema(Ur,{reused:`inline`})}}async execute(e){let t=Ur.parse(e),n=await this.definitionsCacheService.getServerDefinitions(),r=t.capability?.trim().toLowerCase(),i=t.serverName?.trim().toLowerCase(),a=/* @__PURE__ */ new Map;for(let e of n)for(let t of e.tools)a.has(t.name)||a.set(t.name,[]),a.get(t.name)?.push(e.serverName);let o=n.filter(e=>i&&e.serverName.toLowerCase()!==i?!1:!r||(e.serverInstruction?.toLowerCase()||``).includes(r)||Hr(e.tools).some(e=>e.toLowerCase().includes(r))?!0:e.tools.some(t=>{let n=this.formatToolName(t.name,e.serverName,a),i=Vr(t);return n.toLowerCase().includes(r)||(t.description||``).toLowerCase().includes(r)||i.some(e=>e.toLowerCase().includes(r))})).map(e=>({server:e.serverName,capabilities:Hr(e.tools),summary:e.serverInstruction,tools:e.tools.map(t=>({name:this.formatToolName(t.name,e.serverName,a),description:e.omitToolDescription?void 0:t.description,capabilities:Vr(t)}))})).filter(e=>e.tools.length>0);return{content:[{type:`text`,text:JSON.stringify({servers:o},null,2)}],isError:o.length===0||void 0}}};const X=O.object({toolName:O.string().min(1).describe(`Name of the tool to execute`),toolArgs:O.record(O.string(),O.unknown()).optional().describe(`Arguments to pass to the tool, as discovered from describe_tools`)});var Z=class e{static TOOL_NAME=`use_tool`;clientManager;skillService;definitionsCacheService;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.definitionsCacheService=r||new U(e,t),this.serverId=n||`unknown`}getInputSchema(){return X}getDefinition(){return{name:e.TOOL_NAME,description:`Execute an MCP tool (NOT Skill) with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
51
- - Provide toolName and toolArgs based on the schema
52
- - If multiple servers provide the same tool, specify serverName
53
-
54
- IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
55
- `,inputSchema:O.toJSONSchema(X,{reused:`inline`})}}async coerceToolArgs(e,t,n){let r=await this.definitionsCacheService.getToolSchema(e,t);if(!r)return n;let i=Ie(r);return Pe(n,i)}executeSkill(e){return{content:[{type:`text`,text:`Skill "${e.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${e.basePath}\n\nThen follow the skill's instructions directly.`}]}}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}executePromptSkill(e){let t=e.skill.folder||`prompt:${e.serverName}/${e.promptName}`;return{content:[{type:`text`,text:`Skill "${e.skill.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${t}\n\nThen follow the skill's instructions directly.`}]}}async execute(e){try{let{toolName:t,toolArgs:n={}}=X.parse(e);if(t.startsWith(`skill__`)){let e=t.slice(7);if(this.skillService){let t=await this.skillService.getSkill(e);if(t)return this.executeSkill(t)}let n=await this.findPromptSkill(e);return n?this.executePromptSkill(n):{content:[{type:`text`,text:`Skill "${e}" not found. Use describe_tools to see available skills.`}],isError:!0}}let r=this.clientManager.getKnownServerNames(),{serverName:i,actualToolName:a}=B(t);if(i)try{let e=await this.clientManager.ensureConnected(i);if(e.toolBlacklist?.includes(a))return{content:[{type:`text`,text:`Tool "${a}" is blacklisted on server "${i}" and cannot be executed.`}],isError:!0};let t=this.clientManager.getServerRequestTimeout(i),r=await this.coerceToolArgs(i,a,n);return await e.callTool(a,r,t?{timeout:t}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}" on server "${i}". Available servers: ${r.join(`, `)}. ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}let o=await this.definitionsCacheService.getServersForTool(a);if(o.length===0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),o=await this.definitionsCacheService.getServersForTool(a)),o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return this.executeSkill(e)}let e=await this.findPromptSkill(a);return e?this.executePromptSkill(e):{content:[{type:`text`,text:`Tool or skill "${a}" not found. Use describe_tools to see available tools and skills.`}],isError:!0}}if(o.length>1)return{content:[{type:`text`,text:`Tool "${a}" found on multiple servers. Use prefixed format to specify: ${o.map(e=>`${e}__${a}`).join(`, `)}`}],isError:!0};try{let e=o[0],t=await this.clientManager.ensureConnected(e),r=this.clientManager.getServerRequestTimeout(e),i=await this.coerceToolArgs(e,a,n);return await t.callTool(a,i,r?{timeout:r}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}": ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}catch(e){return{content:[{type:`text`,text:`Error executing tool: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},Gr=class{server;handle=null;logger;constructor(e,t=console){this.server=e,this.logger=t}async start(){if(this.handle)throw Error(`MCP stdio server is already running`);this.handle=Le(()=>this.server,{legacy:`reject`}),this.logger.info(`@agimon-ai/po-mcp-proxy MCP server started on stdio`)}async stop(){let e=this.handle;e&&(this.handle=null,await e.close())}};const Kr=[`econnrefused`,`econnreset`,`enotfound`,`connection refused`,`fetch failed`,`socket hang up`,`network error`,`failed to fetch`];function qr(e){if(!(e instanceof Error))return!1;let t=e.message.toLowerCase();return Kr.some(e=>t.includes(e))}function Jr(e){let t=/* @__PURE__ */ new Set,n=[],r=e;for(;r&&!t.has(r);)if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause}else if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:Oe(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause}else{n.push({message:typeof r==`string`?r:Oe(r)});break}return n}function Yr(e){return Jr(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=Xr(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function Xr(e){return typeof e==`string`?e.toLowerCase():void 0}var Zr=class{endpoint;resolveEndpoint;stdioProxyServer=null;stdioHandle=null;httpClient=null;logger;MAX_RECONNECT_ATTEMPTS=5;RECONNECT_BASE_MS=1e3;RECONNECT_MAX_MS=3e4;constructor(e,t=console){this.endpoint=e.endpoint,this.resolveEndpoint=e.resolveEndpoint,this.logger=t}async start(){try{let e=await this.createAndConnectClient();this.httpClient=e,this.stdioProxyServer=this.createProxyServer(),this.stdioHandle=Le(()=>this.stdioProxyServer,{legacy:`reject`}),this.logger.info(`@agimon-ai/po-mcp-proxy MCP stdio proxy connected to ${this.endpoint.toString()}`)}catch(e){throw await this.stop(),Error(`Failed to start stdio-http proxy transport: ${e instanceof Error?e.message:String(e)}`)}}async stop(){let e=this.stdioHandle,t=this.stdioProxyServer,n=this.httpClient;this.stdioHandle=null,this.stdioProxyServer=null,this.httpClient=null;let r=[];if(await Promise.all([(async()=>{try{e&&await e.close()}catch(e){r.push(`failed closing stdio transport: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{t&&await t.close()}catch(e){r.push(`failed closing stdio proxy server: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{n&&await n.close()}catch(e){r.push(`failed closing http client: ${e instanceof Error?e.message:String(e)}`)}})()]),r.length>0)throw Error(`Failed to stop stdio-http proxy transport: ${r.join(`; `)}`)}async createAndConnectClient(){let e=new xe(this.endpoint),t=new _e({name:`@agimon-ai/po-mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{},versionNegotiation:{mode:{pin:`2026-07-28`}}});return await t.connect(e),t}async reconnectWithBackoff(){for(let e=0;e<this.MAX_RECONNECT_ATTEMPTS;e++){let t=Math.min(this.RECONNECT_BASE_MS*2**e,this.RECONNECT_MAX_MS);await new Promise(e=>setTimeout(e,t));try{this.resolveEndpoint&&(this.endpoint=await this.resolveEndpoint()),await this.httpClient?.close().catch(()=>void 0);let t=await this.createAndConnectClient();this.httpClient=t,this.logger.info(`Reconnected to HTTP backend at ${this.endpoint.toString()} (attempt ${e+1})`);return}catch{this.logger.info(`Reconnect attempt ${e+1}/${this.MAX_RECONNECT_ATTEMPTS} to ${this.endpoint.toString()} failed`)}}throw Error(`Failed to reconnect to HTTP backend at ${this.endpoint.toString()} after ${this.MAX_RECONNECT_ATTEMPTS} attempts`)}async withReconnect(e,t=!0){if(!this.httpClient)throw Error(`HTTP client not connected`);try{return await e()}catch(n){if(qr(n)||Yr(n)){if(await this.reconnectWithBackoff(),t)return await e();throw Error(`The connection was recovered, but the prior tool call may have executed; refusing to replay it.`,{cause:n})}throw n}}createProxyServer(){let e=new fe({name:`@agimon-ai/po-mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}}});return e.setRequestHandler(`tools/list`,async()=>{try{return await this.withReconnect(()=>this.httpClient.listTools())}catch(e){throw Error(`Failed forwarding tools/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(`tools/call`,async e=>{try{return await this.withReconnect(()=>this.httpClient.callTool({name:e.params.name,arguments:e.params.arguments}),!1)}catch(t){throw Error(`Failed forwarding tools/call (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(`resources/list`,async()=>{try{return await this.withReconnect(()=>this.httpClient.listResources())}catch(e){throw Error(`Failed forwarding resources/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(`resources/read`,async e=>{try{return await this.withReconnect(()=>this.httpClient.readResource({uri:e.params.uri}))}catch(t){throw Error(`Failed forwarding resources/read (${e.params.uri}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(`prompts/list`,async()=>{try{return await this.withReconnect(()=>this.httpClient.listPrompts())}catch(e){throw Error(`Failed forwarding prompts/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(`prompts/get`,async e=>{try{return await this.withReconnect(()=>this.httpClient.getPrompt({name:e.params.name,arguments:e.params.arguments}))}catch(t){throw Error(`Failed forwarding prompts/get (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e}};function Q(e=console,t,n,r){return{createConfigFetcherService:t=>new Zt(t,e),createClientManagerService:(i,a,o,s)=>t||n||r?new Zn(e,k(t??r),new bn(i),a,t?k(t):void 0,n,r,o,s):new Zn(e,k(),new bn(i),a,void 0,void 0,void 0,o,s),createRuntimeStateService:t=>new K(t,e),createStopServerService:t=>new yr(t,e),createSkillService:(t,n,r)=>new dr(t,n,r,e),createDefinitionsCacheService:(t,n,r)=>new U(t,n,r,e),createPrefetchService:e=>new nr(e),createDescribeToolsTool:(e,t,n,r)=>new Y(e,t,n,r),createUseToolTool:(e,t,n,r)=>new Z(e,t,n,r),createSearchListToolsTool:(e,t)=>new Wr(e,t),createStdioTransportHandler:async t=>new Gr(await t(),e),createHttpTransportHandler:(t,n,r)=>new Sr(t,n,r,e),createStdioHttpTransportHandler:t=>new Zr({endpoint:t},e)}}async function Qr(e,t,n,r){try{return await e.createConfigFetcherService({configSources:t,useCache:!n,env:r}).fetchConfiguration(n)}catch(e){let n=t.map(e=>e.path);throw Error(`Failed to load MCP configuration from '${n.join(`, `)}': ${e instanceof Error?e.message:String(e)}`)}}async function $r(e,t,n){let r=[];return await Promise.all(Object.entries(t).map(async([t,i])=>{try{await e.connectToServer(t,i),n.info(`Connected to MCP server: ${t}`)}catch(e){let i=e instanceof Error?e:Error(String(e));r.push({serverName:t,error:i}),n.warn(`Failed to connect to ${t}`,e)}})),r}async function ei(e){let n=e?.workspaceRoot,r=e?.executionCwd;if(r!==void 0&&!t.isAbsolute(r))throw Error(`executionCwd must be an absolute directory`);let i=e?.environment?{...process.env,...e.environment}:void 0,a=k(n??r),o=await vn({workspaceRoot:a,serviceName:`@agimon-ai/mcp-proxy`,env:i}),s=o,c=Q(s,n?a:void 0,e?.environment,r),l=[],u=!1,d,f=()=>d||(u=!0,d=(async()=>{let e=await Promise.allSettled(l.map(e=>Promise.resolve().then(e)));try{await o.shutdown()}catch(t){e.push({status:`rejected`,reason:t})}let t=e.flatMap(e=>e.status===`rejected`?[e.reason]:[]);if(t.length)throw AggregateError(t,`MCP proxy disposal failed`)})(),d);try{let o,d,p,m,h=!1,g,_=e?.startupMode??`blocking`,v,y=en(e?.configFilePath),b=(e?.configSources?.length?e.configSources:tn(y)).map(e=>n?{...e,path:t.resolve(a,e.path)}:e),x=b.map(e=>e.path),S=b.length>0?await Qr(c,b,e?.noCache===!0,i):void 0,C=c.createClientManagerService(yn(S?.proxy?.outputGuard),e?.auth,e?.outputSchemaValidation,e?.clientCapabilities);if(l.push(()=>C.dispose()),S){if(o=S.skills,d=S.id,p=U.generateConfigHash(S),m=e?.definitionsCachePath||U.getDefaultCachePath(x),C.registerServerConfigs(S.mcpServers),e?.clearDefinitionsCache&&m&&(await U.clearFile(m),s.info(`[definitions-cache] Cleared ${m}`)),m){let e=await U.inspectFile(m,{configHash:p,oneMcpVersion:Rr});e.state===`usable`?(g=e.cache,h=!0,s.info(`[definitions-cache] Cache is usable`,{"definitions_cache.state":e.state,"definitions_cache.path":e.cachePath,"definitions_cache.server_count":Object.keys(e.cache.servers).length})):e.state===`absent`?s.info(`[definitions-cache] Cache is absent; using live discovery`,{"definitions_cache.state":e.state,"definitions_cache.path":e.cachePath}):s.warn(`[definitions-cache] Cache is invalid; using live discovery`,{"definitions_cache.state":e.state,"definitions_cache.path":e.cachePath,"definitions_cache.reason":e.reason,"definitions_cache.error":e.error})}if(h&&s.info(`[definitions-cache] Using cached definitions from ${m}`),_===`background`)v=$r(C,S.mcpServers,s).then(e=>{e.length>0&&s.warn(`MCP server connections failed: ${e.map(e=>e.serverName).join(`, `)}`)},e=>{s.warn(`[mcp-proxy] Background connection pass failed: ${e instanceof Error?e.message:String(e)}`)});else if(_!==`lazy`&&!h){let e=Object.keys(S.mcpServers).length,t=await $r(C,S.mcpServers,s);if(t.length>0&&t.length<e&&s.warn(`Warning: Some MCP server connections failed: ${t.map(e=>e.serverName).join(`, `)}`),t.length>0&&t.length===e)throw Error(`All MCP server connections failed: ${t.map(e=>`${e.serverName}: ${e.error.message}`).join(`, `)}`)}}let w=e?.serverId||d||rn();s.info(`[mcp-proxy] Server ID: ${w}`);let ee=(e?.skills||o)?.paths??[],te={describeTools:null},T=ee.length>0?c.createSkillService(r??(n?a:process.cwd()),ee,{onCacheInvalidated:()=>{te.describeTools?.clearAutoDetectedSkillsCache()}}):void 0,E=c.createDefinitionsCacheService(C,T,g?{cacheData:g}:void 0);g&&E.logCapabilitySummary(g,`cache`);let ne=e?.proxyMode||`meta`,D=c.createDescribeToolsTool(C,T,w,E),re=c.createUseToolTool(C,T,w,E),ie=c.createSearchListToolsTool(C,E);return te.describeTools=D,T&&(l.push(()=>T.stopWatching()),T.startWatching().catch(e=>{s.warn(`[skill-watcher] File watcher failed (non-critical): ${e instanceof Error?e.message:`Unknown error`}`)})),_!==`lazy`&&!h&&m&&x.length>0&&(v??Promise.resolve()).then(()=>u?void 0:E.collectForCache({configPath:x[0],configHash:p,oneMcpVersion:Rr,serverId:w})).then(e=>u||e===void 0?void 0:U.writeToFile(m,e)).then(()=>{s.info(`[definitions-cache] Wrote ${m}`)}).catch(e=>{s.warn(`[definitions-cache] Failed to persist ${m}: ${e instanceof Error?e.message:`Unknown error`}`)}),rt(),l.push(()=>it()),{clientManager:C,definitionsCacheService:E,skillService:T,logger:s,describeTools:D,useTool:re,searchListTools:ie,serverId:w,proxyMode:ne,connectionsSettled:v??Promise.resolve(),dispose:f}}catch(e){try{await f()}catch(t){throw AggregateError([e,t],`MCP proxy startup and cleanup failed`)}throw e}}async function ti(e){let t=await e();return Q().createStdioTransportHandler(()=>Promise.resolve(t))}function ni(e,t,n){return Q().createHttpTransportHandler(e,t,n)}function ri(e){return Q().createStdioHttpTransportHandler(e)}async function ii(e){return ei(e)}function ai(e){let t=e.tools.map(e=>e.name),n=Hr(e.tools),r=n.length>0?`; capabilities: ${n.join(`, `)}`:``;return t.length===0?`${e.serverName} (no tools cached${r})`:`${e.serverName} (${t.join(`, `)})${r}`}function oi(e,t){let n=[`Proxied from server "${e.serverName}" as tool "${t.name}".`];e.serverInstruction&&n.push(`Server summary: ${e.serverInstruction}`),t.description&&!e.omitToolDescription&&n.push(t.description);let r=Vr(t);return r.length>0&&n.push(`Capabilities: ${r.join(`, `)}`),n.join(`
56
-
57
- `)}function si(e){let t=/* @__PURE__ */ new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=[];for(let r of e)for(let e of r.tools){let i=(t.get(e.name)||[]).length>1;n.push({name:i?`${r.serverName}__${e.name}`:e.name,description:oi(r,e),inputSchema:e.inputSchema,_meta:e._meta})}return n}function $(e,t){return`${e}__${t}`}function ci(e){let t=`__${Y.TOOL_NAME}`;if(e.endsWith(t)&&e.length>t.length)return{serverName:e.slice(0,-t.length),metaToolName:Y.TOOL_NAME};let n=`__${Z.TOOL_NAME}`;return e.endsWith(n)&&e.length>n.length?{serverName:e.slice(0,-n.length),metaToolName:Z.TOOL_NAME}:null}function li(e){let t=[`Get detailed schemas for tools proxied by server "${e.serverName}".`,`Call this before using the paired use_tool for this server.`];if(e.serverInstruction&&t.push(`Server summary: ${e.serverInstruction}`),e.tools.length===0)return t.push(`Available tools: none cached.`),t.join(`
58
-
59
- `);let n=e.tools.map(t=>e.omitToolDescription?`- ${t.name}`:`- ${t.name}: ${t.description||`No description`}`);return t.push(`Available tools:\n${n.join(`
60
- `)}`),t.join(`
61
-
62
- `)}function ui(e){let t=[];for(let n of e)t.push({name:$(n.serverName,Y.TOOL_NAME),description:li(n),inputSchema:O.toJSONSchema(J,{reused:`inline`})}),t.push({name:$(n.serverName,Z.TOOL_NAME),description:[`Execute an MCP tool proxied by server "${n.serverName}".`,`Call ${$(n.serverName,Y.TOOL_NAME)} first to discover tool schemas.`,`Pass the downstream tool name without a server prefix in toolName.`].join(`
63
-
64
- `),inputSchema:O.toJSONSchema(X,{reused:`inline`})});return t}function di(e,t){if(!e)return{foundTools:[],notFoundItems:t};let n=[],r=[];for(let i of t){let t=e.tools.find(e=>e.name===i);t?n.push({name:t.name,description:t.description,inputSchema:t.inputSchema}):r.push(i)}return{foundTools:n,notFoundItems:r}}async function fi(e,t){let[n,r]=await Promise.all([t?t.getSkills():e.getCachedFileSkills(),e.getServerDefinitions()]);return n.length>0||r.some(e=>e.promptSkills.length>0)}function pi(e,t){let n=e.length>0?e.map(ai).join(`; `):`No proxied servers available.`;return{name:Y.TOOL_NAME,description:`Get detailed skill instructions for file-based skills and prompt-based skills proxied by mcp-proxy.\n\nProxy summary: ${n}\n\nUse this when you need the full instructions for a skill. For MCP tools, call the flat tool names directly. Only use skills discovered from describe_tools with id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function mi(e,t){let n=e.length>0?e.map(ai).join(`; `):`No proxied servers available.`;return{name:Y.TOOL_NAME,description:`Get detailed schemas and skill instructions for proxied MCP capabilities.\n\nProxy summary: ${n}\n\nUse list_tools first to search capability summaries and discover tool names. Then use describe_tools to fetch full schemas or skill instructions. Only use capabilities discovered from mcp-proxy id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of tool or skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function hi(e,t,n){let r=e.length>0?e.map(ai).join(`; `):`No proxied servers available.`;return t===`flat`?[`mcp-proxy proxies downstream MCP servers and exposes their tools and resources directly.`,`Proxied servers and tools: ${r}`,n?`Skills are still exposed through describe_tools when file-based skills or prompt-backed skills are configured.`:`No skills are currently exposed through describe_tools.`].join(`
65
-
66
- `):t===`search`?[`mcp-proxy proxies downstream MCP servers in search mode.`,`Proxied servers and tools: ${r}`,`Use list_tools to search capability summaries and discover tool names, describe_tools to fetch schemas or skill instructions, and use_tool to execute tools.`].join(`
67
-
68
- `):t===`group`?[`mcp-proxy proxies downstream MCP servers in group mode.`,`Proxied servers and tools: ${r}`,`Use each server-specific describe_tools tool to inspect schemas, then the matching server-specific use_tool tool to execute plain downstream tool names.`].join(`
69
-
70
- `):[`mcp-proxy proxies downstream MCP servers in meta mode.`,`Proxied servers and tools: ${r}`,`Use describe_tools to inspect capabilities and use_tool to execute them.`].join(`
71
-
72
- `)}async function gi(e){let{clientManager:t,definitionsCacheService:n,skillService:r,logger:i,describeTools:a,useTool:o,searchListTools:s,serverId:c,proxyMode:l}=e,u=await n.getServerDefinitions(),d=await fi(n,r),f=async(e,t,n)=>i.runInSpan?i.runInSpan(e,{attributes:t},async()=>n()):await n(),p=new fe({name:`@agimon-ai/po-mcp-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}},instructions:hi(u,l,d)});return p.setRequestHandler(`tools/list`,async()=>f(`mcp.server.list_tools`,{"mcp.service":`@agimon-ai/po-mcp-proxy`},async()=>({tools:(l===`flat`?await(async()=>{let e=await n.getServerDefinitions(),t=await fi(n,r);return[...si(e),...t?[pi(e,c)]:[]]})():l===`search`?await(async()=>[mi(await n.getServerDefinitions(),c),await s.getDefinition(),o.getDefinition()])():l===`group`?ui(await n.getServerDefinitions()):[await a.getDefinition(),o.getDefinition()]).map(e=>{if(e.inputSchema.type!==`object`)throw Error(`Tool ${e.name} must declare an object input schema`);return{...e,inputSchema:{...e.inputSchema,type:`object`}}})}))),p.setRequestHandler(`tools/call`,async e=>{let{name:t,arguments:r}=e.params;return await f(`mcp.server.call_tool`,{"mcp.service":`@agimon-ai/po-mcp-proxy`,"mcp.tool.name":t},async()=>{let e=async(e,t)=>{let n=Pe(r??{},e.getInputSchema());try{return await e.execute(n)}catch(n){if(n instanceof O.ZodError)return{content:[{type:`text`,text:Fe(n,{schemaName:t,schema:e.getInputSchema()})}],isError:!0};throw Error(`Failed to execute ${t}: ${n instanceof Error?n.message:String(n)}`)}};if(t===Y.TOOL_NAME&&l!==`group`)return await e(a,t);if(t===Z.TOOL_NAME&&l!==`group`)return await e(o,t);if(t===Wr.TOOL_NAME&&l===`search`)return await e(s,t);let i=l===`group`?ci(t):null;if(i?.metaToolName===Y.TOOL_NAME){let e=J.safeParse(Pe(r??{},J));if(!e.success)return{content:[{type:`text`,text:Fe(e.error,{schemaName:t,schema:J})}],isError:!0};let a=e.data,o=await n.getServerDefinitions(),s=o.find(e=>e.serverName===i.serverName),c=di(s,a.toolNames);if((c.notFoundItems.length>0||!s)&&(n.clearLiveCache(),await n.collectForCache(),o=await n.getServerDefinitions(),s=o.find(e=>e.serverName===i.serverName),c=di(s,a.toolNames)),!s)return{content:[{type:`text`,text:`Server "${i.serverName}" not found. Available servers: ${o.map(e=>e.serverName).join(`, `)}`}],isError:!0};if(c.foundTools.length===0)return{content:[{type:`text`,text:`None of the requested tools found on server "${i.serverName}". Requested: ${a.toolNames.join(`, `)}`}],isError:!0};let l={server:i.serverName,tools:c.foundTools,nextSteps:[`Use ${$(i.serverName,Z.TOOL_NAME)} with a plain toolName and toolArgs based on the inputSchema above.`]};return c.notFoundItems.length>0&&(l.notFound=c.notFoundItems),{content:[{type:`text`,text:JSON.stringify(l,null,2)}]}}if(i?.metaToolName===Z.TOOL_NAME){let e=X.safeParse(Pe(r??{},X));if(!e.success)return{content:[{type:`text`,text:Fe(e.error,{schemaName:t,schema:X})}],isError:!0};let n=e.data;return B(n.toolName).serverName?{content:[{type:`text`,text:`Tool "${t}" is already scoped to server "${i.serverName}". Pass the downstream tool name without a server prefix.`}],isError:!0}:await o.execute({toolName:$(i.serverName,n.toolName),toolArgs:n.toolArgs||{}})}if(l===`flat`)return await o.execute({toolName:t,toolArgs:r||{}});throw Error(`Unknown tool: ${t}`)})}),p.setRequestHandler(`resources/list`,async()=>{let e=await n.getServerDefinitions(),t=/* @__PURE__ */ new Map;for(let n of e)for(let e of n.resources)t.has(e.uri)||t.set(e.uri,[]),t.get(e.uri)?.push(n.serverName);let r=[];for(let n of e)for(let e of n.resources){let i=(t.get(e.uri)||[]).length>1;r.push({...e,name:e.name??e.uri,uri:i?`${n.serverName}__${e.uri}`:e.uri})}return{resources:r}}),p.setRequestHandler(`resources/read`,async e=>{let{uri:r}=e.params,{serverName:i,actualToolName:a}=B(r);if(i)return await(await t.ensureConnected(i)).readResource(a);let o=await n.getServersForResource(a);if(o.length===0)throw Error(`Resource not found: ${r}`);if(o.length>1)throw Error(`Resource "${a}" exists on multiple servers: ${o.join(`, `)}. Use the prefixed format (e.g., "${o[0]}__${a}") to specify which server to use.`);return await(await t.ensureConnected(o[0])).readResource(a)}),p.setRequestHandler(`prompts/list`,async()=>{let e=await n.getServerDefinitions(),t=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Map;for(let n of e){r.set(n.serverName,n.prompts);for(let e of n.prompts)t.has(e.name)||t.set(e.name,[]),t.get(e.name).push(n.serverName)}let i=[];for(let n of e){let e=r.get(n.serverName)||[];for(let r of e){let e=(t.get(r.name)||[]).length>1;i.push({name:e?`${n.serverName}__${r.name}`:r.name,description:r.description,arguments:r.arguments})}}return{prompts:i}}),p.setRequestHandler(`prompts/get`,async e=>{let{name:r,arguments:i}=e.params,a=await n.getServerDefinitions(),{serverName:o,actualToolName:s}=B(r);if(o)return await(await t.ensureConnected(o)).getPrompt(s,i);let c=[];for(let e of a)e.prompts.some(e=>e.name===r)&&c.push(e.serverName);if(c.length===0)throw Error(`Prompt not found: ${r}`);if(c.length>1)throw Error(`Prompt "${r}" exists on multiple servers: ${c.join(`, `)}. Use the prefixed format (e.g., "${c[0]}__${r}") to specify which server to use.`);let l=t.getClient(c[0]);return l?await l.getPrompt(r,i):await(await t.ensureConnected(c[0])).getPrompt(r,i)}),p}async function _i(e){let t=await ei(e),n=await gi(t);return Object.assign(n,{dispose:t.dispose}),n}const vi={STDIO:`stdio`,HTTP:`http`,SSE:`sse`};export{Je as $,vn as A,vt as B,yr as C,Gn as D,Zn as E,$t as F,pt as G,_t as H,en as I,st as J,ct as K,tn as L,ln as M,rn as N,bn as O,nn as P,Ye as Q,Zt as R,Sr as S,K as T,yt as U,ht as V,ft as W,Ze as X,Xe as Y,Ke as Z,Or as _,ei as a,it as at,Ar as b,ti as c,Be as ct,Gr as d,Ge as et,Z as f,wr as g,Rr as h,ni as i,nt as it,U as j,yn as k,ii as l,Ue as lt,Y as m,_i as n,rt as nt,Q as o,qe as ot,Wr as p,mt as q,gi as r,at as rt,ri as s,We as st,vi as t,tt,Zr as u,k as ut,Er as v,dr as w,Lr as x,Ir as y,qt as z};