@agimon-ai/po-mcp-proxy 0.0.1-alpha.44 → 0.0.1-alpha.46

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.cjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- const e=require("./src-BYSjmDYp.cjs");let t=require("node:fs/promises"),n=require("node:path"),r=require("node:crypto"),i=require("@agimon-ai/foundation-process-registry"),a=require("js-yaml");a=e.mt(a,1);let o=require("@agimon-ai/foundation-port-registry"),s=require("liquidjs"),c=require("commander"),l=require("node:fs");function u(e){return`runtime:${e}`}function d(e){return e instanceof Error?e.message:String(e)}async function f(e){let t=await e.listProcesses({serviceName:`mcp-proxy-http`,liveOnly:!0}),n=/* @__PURE__ */ new Set;for(let e of t){let t=e.metadata?.serverId;typeof t==`string`&&n.add(t)}return n}async function p(e,t){let n=await e.listProcesses({serviceType:`tool`,tags:[`mcp-proxy-stdio-http-bridge`],liveOnly:!0}),r=u(t);return n.filter(e=>e.tags?.includes(r)).length}async function m(t){let n=t.probe??(async(t,n)=>(await e.b(t,n)).ok),r={stopped:[],removedFiles:[],kept:[]},i=await f(t.processRegistry),a=await t.runtimeStateService.listOrphans(i);for(let e of a){let i={serverId:e.serverId,host:e.host,port:e.port,reason:``};if(!await n(e.host,e.port)){i.reason=`unreachable runtime; removed stale state file`,t.dryRun||await t.runtimeStateService.remove(e.serverId),r.removedFiles.push(i);continue}if(e.runtimeLifecycle!==`stdio-http-managed`){i.reason=`manual runtime; left untouched`,r.kept.push(i);continue}let a=await p(t.processRegistry,e.serverId);if(a>0)i.reason=`managed runtime with ${a} live bridge(s); kept`,r.kept.push(i);else{if(i.reason=`orphaned stdio-http-managed runtime (no live bridges); stopped`,!t.dryRun)try{await t.stopServerService.stop({serverId:e.serverId,force:!0}),await t.runtimeStateService.remove(e.serverId).catch(()=>void 0)}catch(e){i.reason=`failed to stop orphaned runtime: ${d(e)}`,r.kept.push(i);continue}r.stopped.push(i)}}return r}function h(e,t){let n=t?`Would stop`:`Stopped`;for(let t of e.stopped)console.log(`${n} orphaned runtime '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);let r=t?`Would remove`:`Removed`;for(let t of e.removedFiles)console.log(`${r} stale state for '${t.serverId}' (http://${t.host}:${t.port})`);for(let t of e.kept)console.log(`Kept '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);console.log(`Summary: ${e.stopped.length} stopped, ${e.removedFiles.length} stale file(s), ${e.kept.length} kept.`)}const g=new c.Command(`cleanup`).description(`Reap orphaned/stale mcp-proxy HTTP runtimes and their leftover state files`).option(`-n, --dry-run`,`Report what would be done without stopping or removing anything`,!1).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{let n=await m({runtimeStateService:new e.T,processRegistry:new i.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH),stopServerService:new e.C,dryRun:t.dryRun});if(t.json){console.log(JSON.stringify({dryRun:t.dryRun,...n},null,2));return}h(n,t.dryRun)}catch(e){let n=`Error executing cleanup: ${d(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function _(e){return e instanceof Error?e.message:String(e)}async function v(e,t){try{return(await fetch(`http://${e}:${t}/health`,{signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}async function y(t,n,r,i,a){let o=n.proxy?.host??`localhost`,s=n.proxy?.port,c=`http://${o}:${s}/mcp`;await v(o,s)||(i.json||console.error(`Starting HTTP proxy server in background...`),await e.y({host:o,port:s,config:r,cache:i.useCache!==!1,clearDefinitionsCache:!1,proxyMode:`flat`}));let l=await t.createClientManagerService();try{await l.connectToServer(`proxy`,{name:`proxy`,transport:`http`,config:{url:c}}),i.json||console.error(`✓ Connected to proxy at ${c}`)}catch(e){throw Error(`Failed to connect to proxy server at ${c}: ${_(e)}`)}try{return await a({container:t,configFilePaths:r,config:n,clientManager:l})}finally{await l.disconnectAll()}}async function b(e,t,n,r,i){let a=await e.createClientManagerService();if(await Promise.all(Object.entries(t.mcpServers).map(async([e,t])=>{try{await a.connectToServer(e,t),r.json||console.error(`✓ Connected to ${e}`)}catch(t){r.json||console.error(`✗ Failed to connect to ${e}: ${_(t)}`)}})),a.getAllClients().length===0)throw Error(`No MCP servers connected`);try{return await i({container:e,configFilePaths:n,config:t,clientManager:a})}finally{await a.disconnectAll()}}async function x(t,n){let r=(e,t)=>{t===void 0?console.error(e):console.error(e,t)},i=t.json?{trace:r,debug:r,info:r,warn:r,error:r}:console,a=e.o(i),o=e.R(t.config),s=o.length>0?null:await e.I(),c=s?[s]:o;if(c.length===0)throw Error(`No config file found. Use --config or create mcp-config.yaml`);let l=await a.createConfigFetcherService({configSources:e.z(c),useCache:t.useCache}).fetchConfiguration();return l.proxy?.port?await y(a,l,c,t,n):await b(a,l,c,t,n)}function S(e){return e instanceof Error?e.message:String(e)}const C=new c.Command(`describe-tools`).description(`Describe specific MCP tools`).argument(`<toolNames...>`,`Tool names to describe`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await x(t,async({container:n,config:r,clientManager:i})=>{let a=t.server?[i.getClient(t.server)].filter(e=>e!==void 0):i.getAllClients();if(t.server&&a.length===0)throw Error(`Server "${t.server}" not found`);let o=process.env.PROJECT_PATH||process.cwd(),s=r.skills?.paths||[],c=s.length>0?n.createSkillService(o,s):void 0,l=[],u=[],d=[...e],f=await Promise.all(a.map(async e=>{try{return{client:e,tools:await e.listTools(),error:null}}catch(t){return{client:e,tools:[],error:t}}}));for(let{client:n,tools:r,error:i}of f)if(i)t.json||console.error(`Failed to list tools from ${n.serverName}:`,i);else for(let t of e){let e=r.find(e=>e.name===t);if(e){l.push({server:n.serverName,name:e.name,description:e.description,inputSchema:e.inputSchema});let r=d.indexOf(t);r>-1&&d.splice(r,1)}}if(c&&d.length>0){let e=await Promise.all([...d].map(async e=>{let t=e.startsWith(`skill__`)?e.slice(7):e;return{toolName:e,skill:await c.getSkill(t)}}));for(let{toolName:t,skill:n}of e)if(n){u.push({name:n.name,location:n.basePath,instructions:n.content});let e=d.indexOf(t);e>-1&&d.splice(e,1)}}let p=[];if(l.length>0&&p.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`),u.length>0&&p.push(`For skill, just follow skill's description to continue.`),t.json){let e={};l.length>0&&(e.tools=l),u.length>0&&(e.skills=u),p.length>0&&(e.nextSteps=p),d.length>0&&(e.notFound=d),console.log(JSON.stringify(e,null,2))}else{if(l.length>0){console.log(`
2
+ const e=require("./src-evq7byCg.cjs");let t=require("node:fs/promises"),n=require("node:path"),r=require("node:crypto"),i=require("@agimon-ai/foundation-process-registry"),a=require("js-yaml");a=e.mt(a,1);let o=require("@agimon-ai/foundation-port-registry"),s=require("liquidjs"),c=require("commander"),l=require("node:fs");function u(e){return`runtime:${e}`}function d(e){return e instanceof Error?e.message:String(e)}async function f(e){let t=await e.listProcesses({serviceName:`mcp-proxy-http`,liveOnly:!0}),n=/* @__PURE__ */ new Set;for(let e of t){let t=e.metadata?.serverId;typeof t==`string`&&n.add(t)}return n}async function p(e,t){let n=await e.listProcesses({serviceType:`tool`,tags:[`mcp-proxy-stdio-http-bridge`],liveOnly:!0}),r=u(t);return n.filter(e=>e.tags?.includes(r)).length}async function m(t){let n=t.probe??(async(t,n)=>(await e.b(t,n)).ok),r={stopped:[],removedFiles:[],kept:[]},i=await f(t.processRegistry),a=await t.runtimeStateService.listOrphans(i);for(let e of a){let i={serverId:e.serverId,host:e.host,port:e.port,reason:``};if(!await n(e.host,e.port)){i.reason=`unreachable runtime; removed stale state file`,t.dryRun||await t.runtimeStateService.remove(e.serverId),r.removedFiles.push(i);continue}if(e.runtimeLifecycle!==`stdio-http-managed`){i.reason=`manual runtime; left untouched`,r.kept.push(i);continue}let a=await p(t.processRegistry,e.serverId);if(a>0)i.reason=`managed runtime with ${a} live bridge(s); kept`,r.kept.push(i);else{if(i.reason=`orphaned stdio-http-managed runtime (no live bridges); stopped`,!t.dryRun)try{await t.stopServerService.stop({serverId:e.serverId,force:!0}),await t.runtimeStateService.remove(e.serverId).catch(()=>void 0)}catch(e){i.reason=`failed to stop orphaned runtime: ${d(e)}`,r.kept.push(i);continue}r.stopped.push(i)}}return r}function h(e,t){let n=t?`Would stop`:`Stopped`;for(let t of e.stopped)console.log(`${n} orphaned runtime '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);let r=t?`Would remove`:`Removed`;for(let t of e.removedFiles)console.log(`${r} stale state for '${t.serverId}' (http://${t.host}:${t.port})`);for(let t of e.kept)console.log(`Kept '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);console.log(`Summary: ${e.stopped.length} stopped, ${e.removedFiles.length} stale file(s), ${e.kept.length} kept.`)}const g=new c.Command(`cleanup`).description(`Reap orphaned/stale mcp-proxy HTTP runtimes and their leftover state files`).option(`-n, --dry-run`,`Report what would be done without stopping or removing anything`,!1).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{let n=await m({runtimeStateService:new e.T,processRegistry:new i.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH),stopServerService:new e.C,dryRun:t.dryRun});if(t.json){console.log(JSON.stringify({dryRun:t.dryRun,...n},null,2));return}h(n,t.dryRun)}catch(e){let n=`Error executing cleanup: ${d(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function _(e){return e instanceof Error?e.message:String(e)}async function v(e,t){try{return(await fetch(`http://${e}:${t}/health`,{signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}async function y(t,n,r,i,a){let o=n.proxy?.host??`localhost`,s=n.proxy?.port,c=`http://${o}:${s}/mcp`;await v(o,s)||(i.json||console.error(`Starting HTTP proxy server in background...`),await e.y({host:o,port:s,config:r,cache:i.useCache!==!1,clearDefinitionsCache:!1,proxyMode:`flat`}));let l=await t.createClientManagerService();try{await l.connectToServer(`proxy`,{name:`proxy`,transport:`http`,config:{url:c}}),i.json||console.error(`✓ Connected to proxy at ${c}`)}catch(e){throw Error(`Failed to connect to proxy server at ${c}: ${_(e)}`)}try{return await a({container:t,configFilePaths:r,config:n,clientManager:l})}finally{await l.disconnectAll()}}async function b(e,t,n,r,i){let a=await e.createClientManagerService();if(await Promise.all(Object.entries(t.mcpServers).map(async([e,t])=>{try{await a.connectToServer(e,t),r.json||console.error(`✓ Connected to ${e}`)}catch(t){r.json||console.error(`✗ Failed to connect to ${e}: ${_(t)}`)}})),a.getAllClients().length===0)throw Error(`No MCP servers connected`);try{return await i({container:e,configFilePaths:n,config:t,clientManager:a})}finally{await a.disconnectAll()}}async function x(t,n){let r=(e,t)=>{t===void 0?console.error(e):console.error(e,t)},i=t.json?{trace:r,debug:r,info:r,warn:r,error:r}:console,a=e.o(i),o=e.R(t.config),s=o.length>0?null:await e.I(),c=s?[s]:o;if(c.length===0)throw Error(`No config file found. Use --config or create mcp-config.yaml`);let l=await a.createConfigFetcherService({configSources:e.z(c),useCache:t.useCache}).fetchConfiguration();return l.proxy?.port?await y(a,l,c,t,n):await b(a,l,c,t,n)}function S(e){return e instanceof Error?e.message:String(e)}const C=new c.Command(`describe-tools`).description(`Describe specific MCP tools`).argument(`<toolNames...>`,`Tool names to describe`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await x(t,async({container:n,config:r,clientManager:i})=>{let a=t.server?[i.getClient(t.server)].filter(e=>e!==void 0):i.getAllClients();if(t.server&&a.length===0)throw Error(`Server "${t.server}" not found`);let o=process.env.PROJECT_PATH||process.cwd(),s=r.skills?.paths||[],c=s.length>0?n.createSkillService(o,s):void 0,l=[],u=[],d=[...e],f=await Promise.all(a.map(async e=>{try{return{client:e,tools:await e.listTools(),error:null}}catch(t){return{client:e,tools:[],error:t}}}));for(let{client:n,tools:r,error:i}of f)if(i)t.json||console.error(`Failed to list tools from ${n.serverName}:`,i);else for(let t of e){let e=r.find(e=>e.name===t);if(e){l.push({server:n.serverName,name:e.name,description:e.description,inputSchema:e.inputSchema});let r=d.indexOf(t);r>-1&&d.splice(r,1)}}if(c&&d.length>0){let e=await Promise.all([...d].map(async e=>{let t=e.startsWith(`skill__`)?e.slice(7):e;return{toolName:e,skill:await c.getSkill(t)}}));for(let{toolName:t,skill:n}of e)if(n){u.push({name:n.name,location:n.basePath,instructions:n.content});let e=d.indexOf(t);e>-1&&d.splice(e,1)}}let p=[];if(l.length>0&&p.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`),u.length>0&&p.push(`For skill, just follow skill's description to continue.`),t.json){let e={};l.length>0&&(e.tools=l),u.length>0&&(e.skills=u),p.length>0&&(e.nextSteps=p),d.length>0&&(e.notFound=d),console.log(JSON.stringify(e,null,2))}else{if(l.length>0){console.log(`
3
3
  Found tools:
4
4
  `);for(let e of l)console.log(`Server: ${e.server}`),console.log(`Tool: ${e.name}`),console.log(`Description: ${e.description||`No description`}`),console.log(`Input Schema:`),console.log(JSON.stringify(e.inputSchema,null,2)),console.log(``)}if(u.length>0){console.log(`
5
5
  Found skills:
package/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{C as e,F as t,I as n,L as r,P as i,R as a,S as o,T as s,_ as c,b as l,d as u,g as d,h as f,j as p,l as m,n as h,o as g,pt as _,r as v,t as y,u as b,v as ee,x,y as S,z as C}from"./src-Cg17E0sw.mjs";import{access as w,readFile as T,writeFile as te}from"node:fs/promises";import{dirname as E,join as D,resolve as O}from"node:path";import{createHash as ne,randomUUID as re}from"node:crypto";import{ProcessRegistryService as k,createProcessLease as ie,normalizeRepositoryPath as ae,withFileLock as oe}from"@agimon-ai/foundation-process-registry";import*as se from"js-yaml";import{DEFAULT_PORT_RANGE as ce,PortRegistryService as le}from"@agimon-ai/foundation-port-registry";import{Liquid as ue}from"liquidjs";import{Command as A}from"commander";import{constants as de}from"node:fs";function fe(e){return`runtime:${e}`}function pe(e){return e instanceof Error?e.message:String(e)}async function me(e){let t=await e.listProcesses({serviceName:`mcp-proxy-http`,liveOnly:!0}),n=/* @__PURE__ */ new Set;for(let e of t){let t=e.metadata?.serverId;typeof t==`string`&&n.add(t)}return n}async function he(e,t){let n=await e.listProcesses({serviceType:`tool`,tags:[`mcp-proxy-stdio-http-bridge`],liveOnly:!0}),r=fe(t);return n.filter(e=>e.tags?.includes(r)).length}async function ge(e){let t=e.probe??(async(e,t)=>(await l(e,t)).ok),n={stopped:[],removedFiles:[],kept:[]},r=await me(e.processRegistry),i=await e.runtimeStateService.listOrphans(r);for(let r of i){let i={serverId:r.serverId,host:r.host,port:r.port,reason:``};if(!await t(r.host,r.port)){i.reason=`unreachable runtime; removed stale state file`,e.dryRun||await e.runtimeStateService.remove(r.serverId),n.removedFiles.push(i);continue}if(r.runtimeLifecycle!==`stdio-http-managed`){i.reason=`manual runtime; left untouched`,n.kept.push(i);continue}let a=await he(e.processRegistry,r.serverId);if(a>0)i.reason=`managed runtime with ${a} live bridge(s); kept`,n.kept.push(i);else{if(i.reason=`orphaned stdio-http-managed runtime (no live bridges); stopped`,!e.dryRun)try{await e.stopServerService.stop({serverId:r.serverId,force:!0}),await e.runtimeStateService.remove(r.serverId).catch(()=>void 0)}catch(e){i.reason=`failed to stop orphaned runtime: ${pe(e)}`,n.kept.push(i);continue}n.stopped.push(i)}}return n}function _e(e,t){let n=t?`Would stop`:`Stopped`;for(let t of e.stopped)console.log(`${n} orphaned runtime '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);let r=t?`Would remove`:`Removed`;for(let t of e.removedFiles)console.log(`${r} stale state for '${t.serverId}' (http://${t.host}:${t.port})`);for(let t of e.kept)console.log(`Kept '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);console.log(`Summary: ${e.stopped.length} stopped, ${e.removedFiles.length} stale file(s), ${e.kept.length} kept.`)}const ve=new A(`cleanup`).description(`Reap orphaned/stale mcp-proxy HTTP runtimes and their leftover state files`).option(`-n, --dry-run`,`Report what would be done without stopping or removing anything`,!1).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{let n=await ge({runtimeStateService:new s,processRegistry:new k(process.env.PROCESS_REGISTRY_PATH),stopServerService:new e,dryRun:t.dryRun});if(t.json){console.log(JSON.stringify({dryRun:t.dryRun,...n},null,2));return}_e(n,t.dryRun)}catch(e){let n=`Error executing cleanup: ${pe(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function j(e){return e instanceof Error?e.message:String(e)}async function ye(e,t){try{return(await fetch(`http://${e}:${t}/health`,{signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}async function be(e,t,n,r,i){let a=t.proxy?.host??`localhost`,o=t.proxy?.port,s=`http://${a}:${o}/mcp`;await ye(a,o)||(r.json||console.error(`Starting HTTP proxy server in background...`),await S({host:a,port:o,config:n,cache:r.useCache!==!1,clearDefinitionsCache:!1,proxyMode:`flat`}));let c=await e.createClientManagerService();try{await c.connectToServer(`proxy`,{name:`proxy`,transport:`http`,config:{url:s}}),r.json||console.error(`✓ Connected to proxy at ${s}`)}catch(e){throw Error(`Failed to connect to proxy server at ${s}: ${j(e)}`)}try{return await i({container:e,configFilePaths:n,config:t,clientManager:c})}finally{await c.disconnectAll()}}async function xe(e,t,n,r,i){let a=await e.createClientManagerService();if(await Promise.all(Object.entries(t.mcpServers).map(async([e,t])=>{try{await a.connectToServer(e,t),r.json||console.error(`✓ Connected to ${e}`)}catch(t){r.json||console.error(`✗ Failed to connect to ${e}: ${j(t)}`)}})),a.getAllClients().length===0)throw Error(`No MCP servers connected`);try{return await i({container:e,configFilePaths:n,config:t,clientManager:a})}finally{await a.disconnectAll()}}async function M(e,t){let r=(e,t)=>{t===void 0?console.error(e):console.error(e,t)},i=e.json?{trace:r,debug:r,info:r,warn:r,error:r}:console,o=g(i),s=a(e.config),c=s.length>0?null:await n(),l=c?[c]:s;if(l.length===0)throw Error(`No config file found. Use --config or create mcp-config.yaml`);let u=await o.createConfigFetcherService({configSources:C(l),useCache:e.useCache}).fetchConfiguration();return u.proxy?.port?await be(o,u,l,e,t):await xe(o,u,l,e,t)}function Se(e){return e instanceof Error?e.message:String(e)}const Ce=new A(`describe-tools`).description(`Describe specific MCP tools`).argument(`<toolNames...>`,`Tool names to describe`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await M(t,async({container:n,config:r,clientManager:i})=>{let a=t.server?[i.getClient(t.server)].filter(e=>e!==void 0):i.getAllClients();if(t.server&&a.length===0)throw Error(`Server "${t.server}" not found`);let o=process.env.PROJECT_PATH||process.cwd(),s=r.skills?.paths||[],c=s.length>0?n.createSkillService(o,s):void 0,l=[],u=[],d=[...e],f=await Promise.all(a.map(async e=>{try{return{client:e,tools:await e.listTools(),error:null}}catch(t){return{client:e,tools:[],error:t}}}));for(let{client:n,tools:r,error:i}of f)if(i)t.json||console.error(`Failed to list tools from ${n.serverName}:`,i);else for(let t of e){let e=r.find(e=>e.name===t);if(e){l.push({server:n.serverName,name:e.name,description:e.description,inputSchema:e.inputSchema});let r=d.indexOf(t);r>-1&&d.splice(r,1)}}if(c&&d.length>0){let e=await Promise.all([...d].map(async e=>{let t=e.startsWith(`skill__`)?e.slice(7):e;return{toolName:e,skill:await c.getSkill(t)}}));for(let{toolName:t,skill:n}of e)if(n){u.push({name:n.name,location:n.basePath,instructions:n.content});let e=d.indexOf(t);e>-1&&d.splice(e,1)}}let p=[];if(l.length>0&&p.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`),u.length>0&&p.push(`For skill, just follow skill's description to continue.`),t.json){let e={};l.length>0&&(e.tools=l),u.length>0&&(e.skills=u),p.length>0&&(e.nextSteps=p),d.length>0&&(e.notFound=d),console.log(JSON.stringify(e,null,2))}else{if(l.length>0){console.log(`
2
+ import{C as e,F as t,I as n,L as r,P as i,R as a,S as o,T as s,_ as c,b as l,d as u,g as d,h as f,j as p,l as m,n as h,o as g,pt as _,r as v,t as y,u as b,v as ee,x,y as S,z as C}from"./src-DvnUcwXu.mjs";import{access as w,readFile as T,writeFile as te}from"node:fs/promises";import{dirname as E,join as D,resolve as O}from"node:path";import{createHash as ne,randomUUID as re}from"node:crypto";import{ProcessRegistryService as k,createProcessLease as ie,normalizeRepositoryPath as ae,withFileLock as oe}from"@agimon-ai/foundation-process-registry";import*as se from"js-yaml";import{DEFAULT_PORT_RANGE as ce,PortRegistryService as le}from"@agimon-ai/foundation-port-registry";import{Liquid as ue}from"liquidjs";import{Command as A}from"commander";import{constants as de}from"node:fs";function fe(e){return`runtime:${e}`}function pe(e){return e instanceof Error?e.message:String(e)}async function me(e){let t=await e.listProcesses({serviceName:`mcp-proxy-http`,liveOnly:!0}),n=/* @__PURE__ */ new Set;for(let e of t){let t=e.metadata?.serverId;typeof t==`string`&&n.add(t)}return n}async function he(e,t){let n=await e.listProcesses({serviceType:`tool`,tags:[`mcp-proxy-stdio-http-bridge`],liveOnly:!0}),r=fe(t);return n.filter(e=>e.tags?.includes(r)).length}async function ge(e){let t=e.probe??(async(e,t)=>(await l(e,t)).ok),n={stopped:[],removedFiles:[],kept:[]},r=await me(e.processRegistry),i=await e.runtimeStateService.listOrphans(r);for(let r of i){let i={serverId:r.serverId,host:r.host,port:r.port,reason:``};if(!await t(r.host,r.port)){i.reason=`unreachable runtime; removed stale state file`,e.dryRun||await e.runtimeStateService.remove(r.serverId),n.removedFiles.push(i);continue}if(r.runtimeLifecycle!==`stdio-http-managed`){i.reason=`manual runtime; left untouched`,n.kept.push(i);continue}let a=await he(e.processRegistry,r.serverId);if(a>0)i.reason=`managed runtime with ${a} live bridge(s); kept`,n.kept.push(i);else{if(i.reason=`orphaned stdio-http-managed runtime (no live bridges); stopped`,!e.dryRun)try{await e.stopServerService.stop({serverId:r.serverId,force:!0}),await e.runtimeStateService.remove(r.serverId).catch(()=>void 0)}catch(e){i.reason=`failed to stop orphaned runtime: ${pe(e)}`,n.kept.push(i);continue}n.stopped.push(i)}}return n}function _e(e,t){let n=t?`Would stop`:`Stopped`;for(let t of e.stopped)console.log(`${n} orphaned runtime '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);let r=t?`Would remove`:`Removed`;for(let t of e.removedFiles)console.log(`${r} stale state for '${t.serverId}' (http://${t.host}:${t.port})`);for(let t of e.kept)console.log(`Kept '${t.serverId}' (http://${t.host}:${t.port}) — ${t.reason}`);console.log(`Summary: ${e.stopped.length} stopped, ${e.removedFiles.length} stale file(s), ${e.kept.length} kept.`)}const ve=new A(`cleanup`).description(`Reap orphaned/stale mcp-proxy HTTP runtimes and their leftover state files`).option(`-n, --dry-run`,`Report what would be done without stopping or removing anything`,!1).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{let n=await ge({runtimeStateService:new s,processRegistry:new k(process.env.PROCESS_REGISTRY_PATH),stopServerService:new e,dryRun:t.dryRun});if(t.json){console.log(JSON.stringify({dryRun:t.dryRun,...n},null,2));return}_e(n,t.dryRun)}catch(e){let n=`Error executing cleanup: ${pe(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function j(e){return e instanceof Error?e.message:String(e)}async function ye(e,t){try{return(await fetch(`http://${e}:${t}/health`,{signal:AbortSignal.timeout(3e3)})).ok}catch{return!1}}async function be(e,t,n,r,i){let a=t.proxy?.host??`localhost`,o=t.proxy?.port,s=`http://${a}:${o}/mcp`;await ye(a,o)||(r.json||console.error(`Starting HTTP proxy server in background...`),await S({host:a,port:o,config:n,cache:r.useCache!==!1,clearDefinitionsCache:!1,proxyMode:`flat`}));let c=await e.createClientManagerService();try{await c.connectToServer(`proxy`,{name:`proxy`,transport:`http`,config:{url:s}}),r.json||console.error(`✓ Connected to proxy at ${s}`)}catch(e){throw Error(`Failed to connect to proxy server at ${s}: ${j(e)}`)}try{return await i({container:e,configFilePaths:n,config:t,clientManager:c})}finally{await c.disconnectAll()}}async function xe(e,t,n,r,i){let a=await e.createClientManagerService();if(await Promise.all(Object.entries(t.mcpServers).map(async([e,t])=>{try{await a.connectToServer(e,t),r.json||console.error(`✓ Connected to ${e}`)}catch(t){r.json||console.error(`✗ Failed to connect to ${e}: ${j(t)}`)}})),a.getAllClients().length===0)throw Error(`No MCP servers connected`);try{return await i({container:e,configFilePaths:n,config:t,clientManager:a})}finally{await a.disconnectAll()}}async function M(e,t){let r=(e,t)=>{t===void 0?console.error(e):console.error(e,t)},i=e.json?{trace:r,debug:r,info:r,warn:r,error:r}:console,o=g(i),s=a(e.config),c=s.length>0?null:await n(),l=c?[c]:s;if(l.length===0)throw Error(`No config file found. Use --config or create mcp-config.yaml`);let u=await o.createConfigFetcherService({configSources:C(l),useCache:e.useCache}).fetchConfiguration();return u.proxy?.port?await be(o,u,l,e,t):await xe(o,u,l,e,t)}function Se(e){return e instanceof Error?e.message:String(e)}const Ce=new A(`describe-tools`).description(`Describe specific MCP tools`).argument(`<toolNames...>`,`Tool names to describe`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await M(t,async({container:n,config:r,clientManager:i})=>{let a=t.server?[i.getClient(t.server)].filter(e=>e!==void 0):i.getAllClients();if(t.server&&a.length===0)throw Error(`Server "${t.server}" not found`);let o=process.env.PROJECT_PATH||process.cwd(),s=r.skills?.paths||[],c=s.length>0?n.createSkillService(o,s):void 0,l=[],u=[],d=[...e],f=await Promise.all(a.map(async e=>{try{return{client:e,tools:await e.listTools(),error:null}}catch(t){return{client:e,tools:[],error:t}}}));for(let{client:n,tools:r,error:i}of f)if(i)t.json||console.error(`Failed to list tools from ${n.serverName}:`,i);else for(let t of e){let e=r.find(e=>e.name===t);if(e){l.push({server:n.serverName,name:e.name,description:e.description,inputSchema:e.inputSchema});let r=d.indexOf(t);r>-1&&d.splice(r,1)}}if(c&&d.length>0){let e=await Promise.all([...d].map(async e=>{let t=e.startsWith(`skill__`)?e.slice(7):e;return{toolName:e,skill:await c.getSkill(t)}}));for(let{toolName:t,skill:n}of e)if(n){u.push({name:n.name,location:n.basePath,instructions:n.content});let e=d.indexOf(t);e>-1&&d.splice(e,1)}}let p=[];if(l.length>0&&p.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`),u.length>0&&p.push(`For skill, just follow skill's description to continue.`),t.json){let e={};l.length>0&&(e.tools=l),u.length>0&&(e.skills=u),p.length>0&&(e.nextSteps=p),d.length>0&&(e.notFound=d),console.log(JSON.stringify(e,null,2))}else{if(l.length>0){console.log(`
3
3
  Found tools:
4
4
  `);for(let e of l)console.log(`Server: ${e.server}`),console.log(`Tool: ${e.name}`),console.log(`Description: ${e.description||`No description`}`),console.log(`Input Schema:`),console.log(JSON.stringify(e.inputSchema,null,2)),console.log(``)}if(u.length>0){console.log(`
5
5
  Found skills:
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src-BYSjmDYp.cjs");exports.CALLBACK_BIND_WAIT_MS=e.Q,exports.CALLBACK_POLL_INTERVAL_MS=e.$,exports.CALLBACK_PORT_SPAN=e.et,exports.CALLBACK_TIMEOUT_MS=e.tt,exports.CallbackRendezvous=e.ut,exports.ConfigFetcherService=e.B,exports.DEFAULT_CALLBACK_PATH=e.nt,exports.DEFAULT_CALLBACK_PORT=e.rt,exports.DEFAULT_HTTP_RUNTIME_TIMEOUT_MS=e.g,exports.DefinitionsCacheService=e.j,exports.DescribeToolsTool=e.m,exports.FileTokenStore=e.q,exports.HttpTransportHandler=e.S,exports.McpClientManagerService=e.E,exports.McpOAuthProvider=e.K,exports.MemoryTokenStore=e.J,exports.OAuthCallbackServer=e.it,exports.OutputGuardService=e.O,exports.RESERVATION_STALE_MS=e.dt,exports.RuntimeStateService=e.T,exports.SearchListToolsTool=e.p,exports.SkillService=e.w,exports.StdioHttpTransportHandler=e.u,exports.StdioTransportHandler=e.d,exports.StopServerService=e.C,exports.TRANSPORT_MODE=e.t,exports.UseToolTool=e.f,exports.VAULT_REF_ERROR_MESSAGE=e.M,exports.acquireSharedCallbackServer=e.at,exports.cleanupStaleRegistries=e.P,exports.closeSharedCallbackServer=e.ot,exports.collectConfigPath=e.L,exports.createHttpTransportHandler=e.i,exports.createOAuthProvider=e.H,exports.createProxyContainer=e.a,exports.createProxyIoCContainer=e.o,exports.createProxyLogger=e.A,exports.createServer=e.n,exports.createSessionServer=e.r,exports.createStdioHttpTransportHandler=e.s,exports.createStdioTransportHandler=e.c,exports.findConfigFile=e.I,exports.findHealthyExistingRuntime=e._,exports.generateServerId=e.F,exports.getDefaultRendezvousRoot=e.ft,exports.getDefaultTokenStoreDir=e.Y,exports.getSharedCallbackServer=e.st,exports.hasVaultRef=e.N,exports.initializeSharedServices=e.l,exports.isAuthError=e.D,exports.parseMcpConfig=e.V,exports.prestartHttpRuntime=e.y,exports.probeRuntimeHealth=e.b,exports.readAuthEntryForUrl=e.X,exports.releaseSharedCallbackServer=e.ct,exports.resolveAuthScheme=e.U,exports.resolveBearerToken=e.W,exports.resolveCallbackPort=e.G,exports.resolveOutputGuardOptions=e.k,exports.resolveWorkspaceRoot=e.pt,exports.toConfigPaths=e.R,exports.toConfigSources=e.z,exports.withTokenStoreLock=e.Z,exports.workspaceCallbackPort=e.lt;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src-evq7byCg.cjs");exports.CALLBACK_BIND_WAIT_MS=e.Q,exports.CALLBACK_POLL_INTERVAL_MS=e.$,exports.CALLBACK_PORT_SPAN=e.et,exports.CALLBACK_TIMEOUT_MS=e.tt,exports.CallbackRendezvous=e.ut,exports.ConfigFetcherService=e.B,exports.DEFAULT_CALLBACK_PATH=e.nt,exports.DEFAULT_CALLBACK_PORT=e.rt,exports.DEFAULT_HTTP_RUNTIME_TIMEOUT_MS=e.g,exports.DefinitionsCacheService=e.j,exports.DescribeToolsTool=e.m,exports.FileTokenStore=e.q,exports.HttpTransportHandler=e.S,exports.McpClientManagerService=e.E,exports.McpOAuthProvider=e.K,exports.MemoryTokenStore=e.J,exports.OAuthCallbackServer=e.it,exports.OutputGuardService=e.O,exports.RESERVATION_STALE_MS=e.dt,exports.RuntimeStateService=e.T,exports.SearchListToolsTool=e.p,exports.SkillService=e.w,exports.StdioHttpTransportHandler=e.u,exports.StdioTransportHandler=e.d,exports.StopServerService=e.C,exports.TRANSPORT_MODE=e.t,exports.UseToolTool=e.f,exports.VAULT_REF_ERROR_MESSAGE=e.M,exports.acquireSharedCallbackServer=e.at,exports.cleanupStaleRegistries=e.P,exports.closeSharedCallbackServer=e.ot,exports.collectConfigPath=e.L,exports.createHttpTransportHandler=e.i,exports.createOAuthProvider=e.H,exports.createProxyContainer=e.a,exports.createProxyIoCContainer=e.o,exports.createProxyLogger=e.A,exports.createServer=e.n,exports.createSessionServer=e.r,exports.createStdioHttpTransportHandler=e.s,exports.createStdioTransportHandler=e.c,exports.findConfigFile=e.I,exports.findHealthyExistingRuntime=e._,exports.generateServerId=e.F,exports.getDefaultRendezvousRoot=e.ft,exports.getDefaultTokenStoreDir=e.Y,exports.getSharedCallbackServer=e.st,exports.hasVaultRef=e.N,exports.initializeSharedServices=e.l,exports.isAuthError=e.D,exports.parseMcpConfig=e.V,exports.prestartHttpRuntime=e.y,exports.probeRuntimeHealth=e.b,exports.readAuthEntryForUrl=e.X,exports.releaseSharedCallbackServer=e.ct,exports.resolveAuthScheme=e.U,exports.resolveBearerToken=e.W,exports.resolveCallbackPort=e.G,exports.resolveOutputGuardOptions=e.k,exports.resolveWorkspaceRoot=e.pt,exports.toConfigPaths=e.R,exports.toConfigSources=e.z,exports.withTokenStoreLock=e.Z,exports.workspaceCallbackPort=e.lt;
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- export{Q as CALLBACK_BIND_WAIT_MS,$ as CALLBACK_POLL_INTERVAL_MS,et as CALLBACK_PORT_SPAN,tt as CALLBACK_TIMEOUT_MS,ut as CallbackRendezvous,B as ConfigFetcherService,nt as DEFAULT_CALLBACK_PATH,rt as DEFAULT_CALLBACK_PORT,g as DEFAULT_HTTP_RUNTIME_TIMEOUT_MS,j as DefinitionsCacheService,m as DescribeToolsTool,q as FileTokenStore,S as HttpTransportHandler,E as McpClientManagerService,K as McpOAuthProvider,J as MemoryTokenStore,it as OAuthCallbackServer,O as OutputGuardService,dt as RESERVATION_STALE_MS,T as RuntimeStateService,p as SearchListToolsTool,w as SkillService,u as StdioHttpTransportHandler,d as StdioTransportHandler,C as StopServerService,t as TRANSPORT_MODE,f as UseToolTool,M as VAULT_REF_ERROR_MESSAGE,at as acquireSharedCallbackServer,P as cleanupStaleRegistries,ot as closeSharedCallbackServer,L as collectConfigPath,i as createHttpTransportHandler,H as createOAuthProvider,a as createProxyContainer,o as createProxyIoCContainer,A as createProxyLogger,n as createServer,r as createSessionServer,s as createStdioHttpTransportHandler,c as createStdioTransportHandler,I as findConfigFile,_ as findHealthyExistingRuntime,F as generateServerId,ft as getDefaultRendezvousRoot,Y as getDefaultTokenStoreDir,st as getSharedCallbackServer,N as hasVaultRef,l as initializeSharedServices,D as isAuthError,V as parseMcpConfig,y as prestartHttpRuntime,b as probeRuntimeHealth,X as readAuthEntryForUrl,ct as releaseSharedCallbackServer,U as resolveAuthScheme,W as resolveBearerToken,G as resolveCallbackPort,k as resolveOutputGuardOptions,pt as resolveWorkspaceRoot,R as toConfigPaths,z as toConfigSources,Z as withTokenStoreLock,lt as workspaceCallbackPort}from"./src-Cg17E0sw.mjs";
1
+ export{Q as CALLBACK_BIND_WAIT_MS,$ as CALLBACK_POLL_INTERVAL_MS,et as CALLBACK_PORT_SPAN,tt as CALLBACK_TIMEOUT_MS,ut as CallbackRendezvous,B as ConfigFetcherService,nt as DEFAULT_CALLBACK_PATH,rt as DEFAULT_CALLBACK_PORT,g as DEFAULT_HTTP_RUNTIME_TIMEOUT_MS,j as DefinitionsCacheService,m as DescribeToolsTool,q as FileTokenStore,S as HttpTransportHandler,E as McpClientManagerService,K as McpOAuthProvider,J as MemoryTokenStore,it as OAuthCallbackServer,O as OutputGuardService,dt as RESERVATION_STALE_MS,T as RuntimeStateService,p as SearchListToolsTool,w as SkillService,u as StdioHttpTransportHandler,d as StdioTransportHandler,C as StopServerService,t as TRANSPORT_MODE,f as UseToolTool,M as VAULT_REF_ERROR_MESSAGE,at as acquireSharedCallbackServer,P as cleanupStaleRegistries,ot as closeSharedCallbackServer,L as collectConfigPath,i as createHttpTransportHandler,H as createOAuthProvider,a as createProxyContainer,o as createProxyIoCContainer,A as createProxyLogger,n as createServer,r as createSessionServer,s as createStdioHttpTransportHandler,c as createStdioTransportHandler,I as findConfigFile,_ as findHealthyExistingRuntime,F as generateServerId,ft as getDefaultRendezvousRoot,Y as getDefaultTokenStoreDir,st as getSharedCallbackServer,N as hasVaultRef,l as initializeSharedServices,D as isAuthError,V as parseMcpConfig,y as prestartHttpRuntime,b as probeRuntimeHealth,X as readAuthEntryForUrl,ct as releaseSharedCallbackServer,U as resolveAuthScheme,W as resolveBearerToken,G as resolveCallbackPort,k as resolveOutputGuardOptions,pt as resolveWorkspaceRoot,R as toConfigPaths,z as toConfigSources,Z as withTokenStoreLock,lt as workspaceCallbackPort}from"./src-DvnUcwXu.mjs";
@@ -6,7 +6,7 @@ import{access as e,chmod as t,lstat as n,mkdir as r,mkdtemp as i,open as a,readF
6
6
  `),a=Zn(i);if(a.bytes<=this.maxBytes&&a.lines<=this.maxLines)return e;let{path:o,error:s}=await Jn(`output`,i),c=Un(a,o,s),l=Bn(this.maxBytes,this.maxLines,c),u=`${Vn(i,l.maxBytes,l.maxLines)}\n\n${c}`,d=Zn(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=Xn(e.structuredContent),n=Qn(t);if(n<=this.structuredMaxBytes)return e;let{path:r,error:i}=await Jn(`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:Wn(e.structuredContent),...r?{fullResultPath:r}:{},...i?{resultWriteError:i}:{}}}}};function Bn(e,t,n){let r=Zn(`\n\n${n}`);return{maxBytes:Math.max(0,e-r.bytes),maxLines:Math.max(0,t-r.lines)}}function Vn(e,t,n){let r=e.split(`
7
7
  `),i=[],a=0;for(let e of r){if(i.length>=n)break;let r=+(i.length>0),o=Qn(e);if(a+r+o>t){let n=t-a-r;n>0&&i.push(Hn(e,n));break}i.push(e),a+=r+o}return i.join(`
8
8
  `)}function Hn(e,t){if(Qn(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 Un(e,t,n){let r=`[MCP tool output truncated: original ${e.lines.toLocaleString()} lines / ${tr(e.bytes)}.`;return t?`${r} Full text saved to: ${t}]`:`${r} Full output could not be saved: ${n??`unknown error`}]`}function Wn(e){let t=Yn(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(Gn),...Array.isArray(e)&&e.length>20?{itemsOmitted:e.length-20}:{},omitted:!0}}function Gn(e){return e.length<=120?e:`${e.slice(0,119)}…`}let Kn;function qn(){return Kn??=i(v(E(),`mcp-proxy-output-`)),Kn}async function Jn(e,t){try{let n=await qn(),r=v(n,`${e}-${C(8).toString(`hex`)}.txt`);return await m(r,t,{encoding:`utf8`,mode:384}),{path:r}}catch(e){return Kn=void 0,{error:e instanceof Error?e.message:String(e)}}}function Yn(e){return typeof e==`object`&&e?e:void 0}function Xn(e){try{return JSON.stringify(e)??``}catch{return``}}function Zn(e){return{bytes:Qn(e),lines:e.length===0?0:e.split(`
9
- `).length}}function Qn(e){return Buffer.byteLength(e,`utf8`)}function $n(e){if(typeof e!=`number`||!Number.isFinite(e))return;let t=Math.floor(e);return t>0?t:void 0}function er(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 tr(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 nr(e){return Array.from(e.slice(0,256)).filter(e=>{let t=e.charCodeAt(0);return t>=32&&t<=126||t>=160}).join(``)}var rr=class extends _e{serverName;compatibility;calls;constructor(e,t,n,r){let i=new ke,a=new Ae;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:nr(this.serverName),toolName:nr(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 ye)||t.code!==be.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 ir=`mcp-proxy-client-manager`,ar=[0,100];function or(e){return e===`reconnecting`?`connecting`:e}function sr(e){if(e.transport===`stdio`)return wn(e.config.env);let t=e.config;return wn(t.headers)||B(t.bearerToken)}function cr(e){return!e.username&&!e.password&&(e.protocol===`https:`||e.protocol===`http:`&&[`localhost`,`127.0.0.1`,`[::1]`].includes(e.hostname))}function lr(e){if(!(`url`in e))throw Error(`Local-only MCP connections require a URL transport.`);let t=new URL(e.url);if(t.protocol!==`http:`||![`127.0.0.1`,`[::1]`,`localhost`].includes(t.hostname)||!t.port||t.username||t.password||t.hash||e.oauth!==!1||e.auth!==void 0||e.headers!==void 0||e.bearerToken!==void 0||e.bearerTokenEnv!==void 0)throw Error(`Local-only MCP connections require credential-free HTTP on an explicit loopback port, with OAuth disabled.`);return t}function ur(e){return async(t,n)=>{let r=new URL(typeof t==`string`?t:t instanceof URL?t.href:t.url);if(r.origin!==e.origin||r.username||r.password)throw Error(`MCP credential destination was rejected.`);return fetch(t,{...n,redirect:`error`})}}var dr=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 fr(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 pr(e){return vr(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=gr(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 mr(e){return e instanceof k||vr(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 hr(e){return vr(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=gr(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 gr(e){return typeof e==`string`?e.toLowerCase():void 0}function _r(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 vr(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:_r(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause}else{n.push({message:_r(r)});break}return n}var yr=class{outputGuard;serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;stdioTransport;processLease;connected=!1;lifecycleState=`closed`;recoveryError;reconnectFn;reconnectPromise;recoverAuthorization;authorizationRecovery;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}setAuthorizationRecovery(e){this.recoverAuthorization=e}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 ar.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 fr(n),this.lifetime.signal.throwIfAborted()),this.client=n.client,this.recoverAuthorization=n.recoverAuthorization,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 dr(this.serverName,ar.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":ar.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(),(n instanceof k||n instanceof ve)&&this.recoverAuthorization)return this.authorizationRecovery??=this.recoverAuthorization(n,t?AbortSignal.any([t,this.lifetime.signal]):this.lifetime.signal).then(()=>this.reconnectClient(`authorization recovered`)).finally(()=>{this.authorizationRecovery=void 0}),await this.authorizationRecovery,t?.throwIfAborted(),e();if(!this.reconnectFn||!pr(n)&&!hr(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(!Ee(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}},br=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=w();outputGuard;stateListeners=/* @__PURE__ */ new Set;serverStates=/* @__PURE__ */ new Map;tokenStore;serverTokenStores=/* @__PURE__ */ new Map;localOnlyOrigins=/* @__PURE__ */ new Map;serverRemovals=/* @__PURE__ */ new Map;onAuthorizationUrl;callbackTimeoutMs;callbackServer;resolveUrlCredentials;resolveSecret;constructor(e=console,t=process.cwd(),n=new zn,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,this.resolveSecret=r.resolveSecret}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,n){if(await this.serverRemovals.get(e),n?.signal?.throwIfAborted(),this.disposed)throw Error(`The MCP client manager is disposed`);if(n?.localOnly||this.localOnlyOrigins.has(e)){if(t.transport!==`http`)throw Error(`Local-only MCP connections require HTTP.`);let n=lr(t.config),r=this.localOnlyOrigins.get(e);if(r&&r!==n.origin||!r&&(this.clients.has(e)||this.connectionPromises.has(e)))throw Error(`Remove the existing MCP connection before changing its local-only policy.`);this.localOnlyOrigins.set(e,n.origin)}n?.tokenStore&&this.serverTokenStores.set(e,n.tokenStore),this.serverConfigs.set(e,t);let r=()=>{this.removeServer(e).catch(()=>this.logger.warn(`Failed to remove cancelled MCP server '${e}'.`))};n?.signal?.addEventListener(`abort`,r,{once:!0});try{await this.ensureConnected(e),n?.signal?.throwIfAborted()}finally{n?.signal?.removeEventListener(`abort`,r)}}async removeServer(e){let t=this.serverRemovals.get(e);if(t)return t;let n=this.serverTokenStores.get(e);this.serverConfigs.delete(e);let r=(async()=>{try{await this.disconnectServer(e)}finally{this.serverTokenStores.get(e)===n&&this.serverTokenStores.delete(e),this.localOnlyOrigins.delete(e),await n?.clear(e),this.serverStates.delete(e)}})();this.serverRemovals.set(e,r);try{await r}finally{this.serverRemovals.get(e)===r&&this.serverRemovals.delete(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=sr(t),s=n instanceof Error&&[`Invalid MCP API-key configuration.`,`MCP API-key credential is unavailable.`,`MCP credential destination was rejected.`,`MCP secret reference could not be resolved.`].includes(n.message),c=(a||o)&&!s?/* @__PURE__ */ Error(a?`MCP API-key connection failed.`:`MCP connection with a vault secret failed.`):n;throw this.emitServerState({serverName:e,state:this.disposed||r.signal.aborted&&!String(r.signal.reason).includes(`timeout`)?`closed`:mr(c)?`needs-auth`:`failed`,error:c instanceof Error?c.message:String(c)}),c}finally{s=void 0,clearTimeout(o),r.signal.removeEventListener(`abort`,i),this.connectionControllers.get(e)===r&&this.connectionControllers.delete(e)}let u=new yr(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.setAuthorizationRecovery(l.recoverAuthorization),u.setLifecycleChangeCallback((t,n)=>{this.emitServerState({serverName:e,state:or(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(n){throw this.logger.warn(`Failed to reconnect to ${e}`,sr(t)?`connection with a vault secret failed`:n),n}}),!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 rr(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 fr(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=this.localOnlyOrigins.get(e);if(o&&(t!==`http`||lr(n).origin!==o))throw Error(`Local-only MCP destination changed. Remove and reattach the server.`);let s=n.auth,c=typeof s==`object`&&s?.type===`api-key`?s:void 0;Tn([n.url]);let l=wn(n.headers)||B(n.bearerToken),u=n;if(l){let r=new URL(n.url);if(!cr(r))throw Error(`MCP credential destination was rejected.`);let a={serverName:e,transport:t,origin:r.origin,signal:i},o=await Dn(n.headers,{...a,field:`header`},this.resolveSecret),s=n.bearerToken===void 0?void 0:await En(n.bearerToken,{...a,field:`bearerToken`},this.resolveSecret);u={...n,...o?{headers:o}:{},...s===void 0?{}:{bearerToken:s}}}let d=this.resolveAuthHeaders(u),f=o?ur(new URL(o)):void 0;if(c){let r=new URL(n.url),a=c.mode===`bearer`?`Authorization`:c.name;if(c.mode!==`bearer`&&c.mode!==`header`||!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(a)||c.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))||!cr(r)||n.bearerToken||n.bearerTokenEnv||n.oauth!==void 0||Object.keys(d??{}).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:c,signal:i})}catch{throw Error(`MCP API-key credential is unavailable.`)}i?.throwIfAborted();let s=o?.[a];if(!s||Object.keys(o??{}).length!==1||Array.from(s).some(e=>e.charCodeAt(0)<=31||e.charCodeAt(0)===127)||c.mode===`bearer`&&!/^Bearer [^\s]+$/.test(s))throw Error(`MCP API-key credential is unavailable.`);d={...d,[a]:s},f=ur(r)}l&&!f&&(f=ur(new URL(n.url)));let p=!!c||l,m=this.createSdkClient(e,t===`sse`?`legacy`:`auto`),h=d?{headers:d}:void 0,g=await this.createAuthProvider(e,n);await g?.prepareCallback(),i?.throwIfAborted();let _=g?new Ln(g,n.url,i):void 0,v={requestInit:h,authProvider:_,...f?{fetch:f}:{}},y=t===`http`?new Se(new URL(n.url),v):new xe(new URL(n.url),v),b=()=>{g?.cancelAuthorization(),m.close().catch(t=>this.logger.warn(`Failed to close cancelled client ${e}`,p?`credential connection closed`:t))};i?.addEventListener(`abort`,b,{once:!0});let x=!1;try{return await m.connect(y),i?.throwIfAborted(),x=!0,{client:m,..._?{recoverAuthorization:(e,t)=>_.recover(e,t)}:{}}}catch(o){if(i?.throwIfAborted(),c)throw Error(`MCP API-key connection failed.`);if(!g||!_||!r||!(o instanceof ve)&&(!mr(o)||!g.hasPendingAuthorization()))throw o;return this.logger.info(`[oauth] Waiting for authorization of MCP server "${e}"`),a?.(!0),await _.recover(o,i,()=>{a?.(!1),this.emitServerState({serverName:e,state:`connecting`})}),i?.throwIfAborted(),await this.connectUrlSdkClient(e,t,n,!1,i,a)}finally{i?.removeEventListener(`abort`,b),x||(g?.cancelAuthorization(),await m.close().catch(t=>this.logger.warn(`Failed to close client ${e}`,p?`credential connection closed`:t)))}}resolveAuthHeaders(e){let t={...e.headers};if(wt(e)===`bearer`){let n=e.bearerTokenEnv?this.env?.[e.bearerTokenEnv]??Et(e):Et(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}async createAuthProvider(e,t){return Dt({serverName:e,config:t,store:this.serverTokenStores.get(e)??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){Tn([n.command,...n.args??[],n.cwd]);let i=await Dn(n.env,{serverName:e,field:`env`,transport:`stdio`,command:n.command,args:[...n.args??[]],signal:r},this.resolveSecret);r?.throwIfAborted();let a=new Oe({command:n.command,args:n.args,cwd:this.executionCwd?y(this.executionCwd,n.cwd??`.`):this.workspaceRoot?y(this.workspaceRoot,n.cwd??`.`):n.cwd,env:{...process.env,...this.env,...i,PROJECT_PATH:this.repositoryPath,[ae]:ir,[ie]:this.processOwnerId},stderr:`pipe`}),o=()=>{fr({client:t,stdioTransport:a}).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(a),r?.throwIfAborted(),this.relayChildStderr(e,a.stderr);let i=a.pid;if(typeof i!=`number`||i<=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:i,command:n.command,args:n.args,metadata:{transport:`stdio`},ownerKind:ir,ownerId:this.processOwnerId,resourceKey:e});return t.onclose=()=>{let t=this.clients.get(e);t instanceof yr&&t.handleStdioClosed(a)},{client:t,processLease:o,stdioTransport:a}}catch(n){try{await fr({client:t,stdioTransport:a})}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 xr=`install`,Sr=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,Cr=`pipe`;function wr(e){return typeof e==`object`&&!!e&&`command`in e}var Tr=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`||!wr(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 Sr.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`,xr,`-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`,xr,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`,Cr,Cr],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 Er=`.runtime.json`;async function Dr(e){await r(e,{recursive:!0,mode:448});try{await t(e,448)}catch{}}function Or(e){return typeof e==`object`&&!!e}function kr(e){return Or(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 Ar(e){return e instanceof Error?e.message:String(e)}function jr(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 v(T(),`.mcp-proxy`,`runtimes`)}getRecordPath(e){return v(this.runtimeDir,`${e}${Er}`)}async write(e){await Dr(this.runtimeDir);let t=this.getRecordPath(e.serverId);await m(t,JSON.stringify(e,null,2),{encoding:`utf-8`,mode:384})}async read(e){let t=this.getRecordPath(e);try{let e=await o(t,`utf-8`),n=JSON.parse(e);return kr(n)?n:null}catch(n){if(Or(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${Ar(n)}`)}}async list(){try{let e=(await s(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(Er));return(await Promise.all(e.map(async e=>{try{let t=await o(v(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return kr(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(Or(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${Ar(e)}`)}}async listOrphans(e){return(await this.list()).filter(t=>!e.has(t.serverId))}async pruneStale(){let e=(await this.list()).filter(e=>!jr(e.pid));return await Promise.all(e.map(async e=>this.remove(e.serverId))),e}async remove(e){await l(this.getRecordPath(e),{force:!0})}},Mr=class extends Error{filePath;cause;constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function Nr(t){try{return await e(t),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw Error(`Failed to check path existence for "${t}": ${e instanceof Error?e.message:`Unknown error`}`)}}var Pr=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=_(e)?e:v(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=_(e)?e:v(this.cwd,e);return{skillsDir:t,exists:await Nr(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=p(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 s(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=v(e,n),i=await u(r);i.isDirectory()?await this.collectSkillSnapshots(r,t):n===`SKILL.md`&&t.set(r,i.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 Nr(e))return n}catch(t){throw new Mr(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await s(e)}catch(t){throw new Mr(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let i=await Promise.all(r.map(async t=>{let n=v(e,t);try{return{entry:t,entryPath:n,stat:await u(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}}})),a=[];for(let{entry:e,entryPath:t,stat:n}of i)if(n){if(n.isDirectory()){let e=v(t,`SKILL.md`);a.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&a.push({filePath:t,isRootLevel:!0})}let o=await Promise.all(a.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await Nr(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 o)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await o(e,`utf-8`)}catch(t){throw new Mr(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:r,content:i}=hn(n);return!r||!r.name||!r.description?null:{name:r.name,description:r.description,location:t,content:i,basePath:g(e)}}};const Fr=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`::1`]);function Ir(e){return e}function Lr(e){if(typeof e!=`object`||!e)return!1;let t=Ir(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 Rr(e){if(typeof e!=`object`||!e)return!1;let t=Ir(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 zr(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 Br(e){return e instanceof Error?e.message:String(e)}function Vr(e){return new Promise(t=>{setTimeout(t,e)})}var Hr=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(zr(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!Lr(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(zr(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!Rr(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: ${Br(t)}`)}finally{clearTimeout(i)}}};function q(e){return e instanceof Error?e.message:String(e)}function Ur(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);return n.length===r.length&&ee(n,r)}var Wr=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)}},Gr=class{honoApp=new Ie;adminRateLimiter=new Wr;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=Fe(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 Ur(n.slice(7),t);let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&Ur(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=Pe(this.honoApp.fetch),t=te((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([je(t,`listening`),je(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 Ne(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 Kr=`localhost`,qr=12e4,Jr=`MCP_PROXY_RUNTIME_DETACHED`;function Yr(){return process.env[Jr]===`1`}async function Xr(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 Zr(e){let t=await Xr(e);for(let e of t)if(Qr(await $r(e.host,e.port)))return e;return null}function Qr(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 $r(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}}async function ei(){let t=re(import.meta.url),n=h.dirname(t),r=[h.resolve(n,`cli.mjs`),h.resolve(n,`..`,`dist`,`cli.mjs`),h.resolve(n,`..`,`..`,`dist`,`cli.mjs`)],i=[h.resolve(n,`..`,`cli.ts`),h.resolve(n,`..`,`..`,`src`,`cli.ts`)];for(let t of r)try{return await e(t),{command:process.execPath,args:[t]}}catch{continue}for(let t of i)try{return await e(t),{command:process.execPath,args:[`--import`,`tsx`,t]}}catch{continue}throw Error(`Unable to locate mcp-proxy CLI entrypoint`)}function ti(e){if(!e)return qr;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid timeout value: ${e}`);return t}async function ni(t,n){let r=Date.now()+n;for(;Date.now()<r;){try{await e(t);return}catch{}await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for runtime state file: ${t}`)}async function ri(e,t){let n=new K,r=Date.now()+t;for(;Date.now()<r;){let t=await n.read(e);if(t&&Qr(await $r(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`)}async function ii(e,t,n){let{command:r,args:i}=await ei(),a=D(r,[...i,...e],{detached:!0,cwd:n,stdio:`ignore`,env:t});return a.unref(),a}async function ai(e){let t=e.id||mn(),n=ti(e.timeoutMs),r=e.registryPath||e.registryDir,i=await j();await new K().pruneStale();let a=await Zr(i);if(a)return{host:a.host,port:a.port,serverId:a.serverId,workspaceRoot:i,reusedExistingRuntime:!0,runtimeLifecycle:a.runtimeLifecycle??`manual`};let o=e.port,s=await Xr(i);if(e.id&&s.some(e=>e.serverId===t))throw Error(`Runtime ID '${t}' belongs to an incompatible HTTP runtime; choose a new ID`);if(o!==void 0&&s.some(t=>t.host===(e.host||Kr)&&t.port===o))throw Error(`Port ${o} belongs to a different HTTP runtime; choose a free port`);let c=o,l={...process.env,[Jr]:`1`,...e.runtimeLifecycle?{MCP_PROXY_RUNTIME_LIFECYCLE:e.runtimeLifecycle}:{},...r?{PORT_REGISTRY_PATH:r,PROCESS_REGISTRY_PATH:ce(r,`processes.json`)}:{}},u=await ii([`mcp-serve`,`--type`,`http`,`--id`,t,`--host`,e.host||Kr,...c===void 0?[]:[`--port`,String(c)],...dn(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],l,i),d=new Promise((e,t)=>{u.once(`exit`,(e,n)=>{t(/* @__PURE__ */ Error(`Background runtime exited before becoming healthy (code=${e??`null`}, signal=${n??`null`})`))})}),f=h.join(K.getDefaultRuntimeDir(),`${t}.runtime.json`);try{await Promise.race([ni(f,n),d]);let{host:r,port:a}=await Promise.race([ri(t,n),d]);return{host:r,port:a,serverId:t,workspaceRoot:i,reusedExistingRuntime:!1,runtimeLifecycle:e.runtimeLifecycle??`manual`}}catch(e){throw Error(`Failed to prestart HTTP runtime '${t}': ${e instanceof Error?e.message:String(e)}`,{cause:e})}}function oi(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 si=`0.0.1-alpha.44`,ci=`<toolkit id="{{ serverId }}">
9
+ `).length}}function Qn(e){return Buffer.byteLength(e,`utf8`)}function $n(e){if(typeof e!=`number`||!Number.isFinite(e))return;let t=Math.floor(e);return t>0?t:void 0}function er(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 tr(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 nr(e){return Array.from(e.slice(0,256)).filter(e=>{let t=e.charCodeAt(0);return t>=32&&t<=126||t>=160}).join(``)}var rr=class extends _e{serverName;compatibility;calls;constructor(e,t,n,r){let i=new ke,a=new Ae;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:nr(this.serverName),toolName:nr(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 ye)||t.code!==be.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 ir=`mcp-proxy-client-manager`,ar=[0,100];function or(e){return e===`reconnecting`?`connecting`:e}function sr(e){if(e.transport===`stdio`)return wn(e.config.env);let t=e.config;return wn(t.headers)||B(t.bearerToken)}function cr(e){return!e.username&&!e.password&&(e.protocol===`https:`||e.protocol===`http:`&&[`localhost`,`127.0.0.1`,`[::1]`].includes(e.hostname))}function lr(e){if(!(`url`in e))throw Error(`Local-only MCP connections require a URL transport.`);let t=new URL(e.url);if(t.protocol!==`http:`||![`127.0.0.1`,`[::1]`,`localhost`].includes(t.hostname)||!t.port||t.username||t.password||t.hash||e.oauth!==!1||e.auth!==void 0||e.headers!==void 0||e.bearerToken!==void 0||e.bearerTokenEnv!==void 0)throw Error(`Local-only MCP connections require credential-free HTTP on an explicit loopback port, with OAuth disabled.`);return t}function ur(e){return async(t,n)=>{let r=new URL(typeof t==`string`?t:t instanceof URL?t.href:t.url);if(r.origin!==e.origin||r.username||r.password)throw Error(`MCP credential destination was rejected.`);return fetch(t,{...n,redirect:`error`})}}var dr=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 fr(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 pr(e){return vr(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=gr(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 mr(e){return e instanceof k||vr(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 hr(e){return vr(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=gr(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 gr(e){return typeof e==`string`?e.toLowerCase():void 0}function _r(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 vr(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:_r(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause}else{n.push({message:_r(r)});break}return n}var yr=class{outputGuard;serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;stdioTransport;processLease;connected=!1;lifecycleState=`closed`;recoveryError;reconnectFn;reconnectPromise;recoverAuthorization;authorizationRecovery;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}setAuthorizationRecovery(e){this.recoverAuthorization=e}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 ar.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 fr(n),this.lifetime.signal.throwIfAborted()),this.client=n.client,this.recoverAuthorization=n.recoverAuthorization,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 dr(this.serverName,ar.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":ar.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(),(n instanceof k||n instanceof ve)&&this.recoverAuthorization)return this.authorizationRecovery??=this.recoverAuthorization(n,t?AbortSignal.any([t,this.lifetime.signal]):this.lifetime.signal).then(()=>this.reconnectClient(`authorization recovered`)).finally(()=>{this.authorizationRecovery=void 0}),await this.authorizationRecovery,t?.throwIfAborted(),e();if(!this.reconnectFn||!pr(n)&&!hr(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(!Ee(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}},br=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=w();outputGuard;stateListeners=/* @__PURE__ */ new Set;serverStates=/* @__PURE__ */ new Map;tokenStore;serverTokenStores=/* @__PURE__ */ new Map;localOnlyOrigins=/* @__PURE__ */ new Map;serverRemovals=/* @__PURE__ */ new Map;onAuthorizationUrl;callbackTimeoutMs;callbackServer;resolveUrlCredentials;resolveSecret;constructor(e=console,t=process.cwd(),n=new zn,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,this.resolveSecret=r.resolveSecret}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,n){if(await this.serverRemovals.get(e),n?.signal?.throwIfAborted(),this.disposed)throw Error(`The MCP client manager is disposed`);if(n?.localOnly||this.localOnlyOrigins.has(e)){if(t.transport!==`http`)throw Error(`Local-only MCP connections require HTTP.`);let n=lr(t.config),r=this.localOnlyOrigins.get(e);if(r&&r!==n.origin||!r&&(this.clients.has(e)||this.connectionPromises.has(e)))throw Error(`Remove the existing MCP connection before changing its local-only policy.`);this.localOnlyOrigins.set(e,n.origin)}n?.tokenStore&&this.serverTokenStores.set(e,n.tokenStore),this.serverConfigs.set(e,t);let r=()=>{this.removeServer(e).catch(()=>this.logger.warn(`Failed to remove cancelled MCP server '${e}'.`))};n?.signal?.addEventListener(`abort`,r,{once:!0});try{await this.ensureConnected(e),n?.signal?.throwIfAborted()}finally{n?.signal?.removeEventListener(`abort`,r)}}async removeServer(e){let t=this.serverRemovals.get(e);if(t)return t;let n=this.serverTokenStores.get(e);this.serverConfigs.delete(e);let r=(async()=>{try{await this.disconnectServer(e)}finally{this.serverTokenStores.get(e)===n&&this.serverTokenStores.delete(e),this.localOnlyOrigins.delete(e),await n?.clear(e),this.serverStates.delete(e)}})();this.serverRemovals.set(e,r);try{await r}finally{this.serverRemovals.get(e)===r&&this.serverRemovals.delete(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=sr(t),s=n instanceof Error&&[`Invalid MCP API-key configuration.`,`MCP API-key credential is unavailable.`,`MCP credential destination was rejected.`,`MCP secret reference could not be resolved.`].includes(n.message),c=(a||o)&&!s?/* @__PURE__ */ Error(a?`MCP API-key connection failed.`:`MCP connection with a vault secret failed.`):n;throw this.emitServerState({serverName:e,state:this.disposed||r.signal.aborted&&!String(r.signal.reason).includes(`timeout`)?`closed`:mr(c)?`needs-auth`:`failed`,error:c instanceof Error?c.message:String(c)}),c}finally{s=void 0,clearTimeout(o),r.signal.removeEventListener(`abort`,i),this.connectionControllers.get(e)===r&&this.connectionControllers.delete(e)}let u=new yr(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.setAuthorizationRecovery(l.recoverAuthorization),u.setLifecycleChangeCallback((t,n)=>{this.emitServerState({serverName:e,state:or(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(n){throw this.logger.warn(`Failed to reconnect to ${e}`,sr(t)?`connection with a vault secret failed`:n),n}}),!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 rr(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 fr(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=this.localOnlyOrigins.get(e);if(o&&(t!==`http`||lr(n).origin!==o))throw Error(`Local-only MCP destination changed. Remove and reattach the server.`);let s=n.auth,c=typeof s==`object`&&s?.type===`api-key`?s:void 0;Tn([n.url]);let l=wn(n.headers)||B(n.bearerToken),u=n;if(l){let r=new URL(n.url);if(!cr(r))throw Error(`MCP credential destination was rejected.`);let a={serverName:e,transport:t,origin:r.origin,signal:i},o=await Dn(n.headers,{...a,field:`header`},this.resolveSecret),s=n.bearerToken===void 0?void 0:await En(n.bearerToken,{...a,field:`bearerToken`},this.resolveSecret);u={...n,...o?{headers:o}:{},...s===void 0?{}:{bearerToken:s}}}let d=this.resolveAuthHeaders(u),f=o?ur(new URL(o)):void 0;if(c){let r=new URL(n.url),a=c.mode===`bearer`?`Authorization`:c.name;if(c.mode!==`bearer`&&c.mode!==`header`||!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(a)||c.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))||!cr(r)||n.bearerToken||n.bearerTokenEnv||n.oauth!==void 0||Object.keys(d??{}).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:c,signal:i})}catch{throw Error(`MCP API-key credential is unavailable.`)}i?.throwIfAborted();let s=o?.[a];if(!s||Object.keys(o??{}).length!==1||Array.from(s).some(e=>e.charCodeAt(0)<=31||e.charCodeAt(0)===127)||c.mode===`bearer`&&!/^Bearer [^\s]+$/.test(s))throw Error(`MCP API-key credential is unavailable.`);d={...d,[a]:s},f=ur(r)}l&&!f&&(f=ur(new URL(n.url)));let p=!!c||l,m=this.createSdkClient(e,t===`sse`?`legacy`:`auto`),h=d?{headers:d}:void 0,g=await this.createAuthProvider(e,n);await g?.prepareCallback(),i?.throwIfAborted();let _=g?new Ln(g,n.url,i):void 0,v={requestInit:h,authProvider:_,...f?{fetch:f}:{}},y=t===`http`?new Se(new URL(n.url),v):new xe(new URL(n.url),v),b=()=>{g?.cancelAuthorization(),m.close().catch(t=>this.logger.warn(`Failed to close cancelled client ${e}`,p?`credential connection closed`:t))};i?.addEventListener(`abort`,b,{once:!0});let x=!1;try{return await m.connect(y),i?.throwIfAborted(),x=!0,{client:m,..._?{recoverAuthorization:(e,t)=>_.recover(e,t)}:{}}}catch(o){if(i?.throwIfAborted(),c)throw Error(`MCP API-key connection failed.`);if(!g||!_||!r||!(o instanceof ve)&&(!mr(o)||!g.hasPendingAuthorization()))throw o;return this.logger.info(`[oauth] Waiting for authorization of MCP server "${e}"`),a?.(!0),await _.recover(o,i,()=>{a?.(!1),this.emitServerState({serverName:e,state:`connecting`})}),i?.throwIfAborted(),await this.connectUrlSdkClient(e,t,n,!1,i,a)}finally{i?.removeEventListener(`abort`,b),x||(g?.cancelAuthorization(),await m.close().catch(t=>this.logger.warn(`Failed to close client ${e}`,p?`credential connection closed`:t)))}}resolveAuthHeaders(e){let t={...e.headers};if(wt(e)===`bearer`){let n=e.bearerTokenEnv?this.env?.[e.bearerTokenEnv]??Et(e):Et(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}async createAuthProvider(e,t){return Dt({serverName:e,config:t,store:this.serverTokenStores.get(e)??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){Tn([n.command,...n.args??[],n.cwd]);let i=await Dn(n.env,{serverName:e,field:`env`,transport:`stdio`,command:n.command,args:[...n.args??[]],signal:r},this.resolveSecret);r?.throwIfAborted();let a=new Oe({command:n.command,args:n.args,cwd:this.executionCwd?y(this.executionCwd,n.cwd??`.`):this.workspaceRoot?y(this.workspaceRoot,n.cwd??`.`):n.cwd,env:{...process.env,...this.env,...i,PROJECT_PATH:this.repositoryPath,[ae]:ir,[ie]:this.processOwnerId},stderr:`pipe`}),o=()=>{fr({client:t,stdioTransport:a}).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(a),r?.throwIfAborted(),this.relayChildStderr(e,a.stderr);let i=a.pid;if(typeof i!=`number`||i<=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:i,command:n.command,args:n.args,metadata:{transport:`stdio`},ownerKind:ir,ownerId:this.processOwnerId,resourceKey:e});return t.onclose=()=>{let t=this.clients.get(e);t instanceof yr&&t.handleStdioClosed(a)},{client:t,processLease:o,stdioTransport:a}}catch(n){try{await fr({client:t,stdioTransport:a})}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 xr=`install`,Sr=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,Cr=`pipe`;function wr(e){return typeof e==`object`&&!!e&&`command`in e}var Tr=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`||!wr(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 Sr.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`,xr,`-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`,xr,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`,Cr,Cr],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 Er=`.runtime.json`;async function Dr(e){await r(e,{recursive:!0,mode:448});try{await t(e,448)}catch{}}function Or(e){return typeof e==`object`&&!!e}function kr(e){return Or(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 Ar(e){return e instanceof Error?e.message:String(e)}function jr(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 v(T(),`.mcp-proxy`,`runtimes`)}getRecordPath(e){return v(this.runtimeDir,`${e}${Er}`)}async write(e){await Dr(this.runtimeDir);let t=this.getRecordPath(e.serverId);await m(t,JSON.stringify(e,null,2),{encoding:`utf-8`,mode:384})}async read(e){let t=this.getRecordPath(e);try{let e=await o(t,`utf-8`),n=JSON.parse(e);return kr(n)?n:null}catch(n){if(Or(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${Ar(n)}`)}}async list(){try{let e=(await s(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(Er));return(await Promise.all(e.map(async e=>{try{let t=await o(v(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return kr(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(Or(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${Ar(e)}`)}}async listOrphans(e){return(await this.list()).filter(t=>!e.has(t.serverId))}async pruneStale(){let e=(await this.list()).filter(e=>!jr(e.pid));return await Promise.all(e.map(async e=>this.remove(e.serverId))),e}async remove(e){await l(this.getRecordPath(e),{force:!0})}},Mr=class extends Error{filePath;cause;constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function Nr(t){try{return await e(t),!0}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return!1;throw Error(`Failed to check path existence for "${t}": ${e instanceof Error?e.message:`Unknown error`}`)}}var Pr=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=_(e)?e:v(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=_(e)?e:v(this.cwd,e);return{skillsDir:t,exists:await Nr(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=p(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 s(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=v(e,n),i=await u(r);i.isDirectory()?await this.collectSkillSnapshots(r,t):n===`SKILL.md`&&t.set(r,i.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 Nr(e))return n}catch(t){throw new Mr(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await s(e)}catch(t){throw new Mr(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let i=await Promise.all(r.map(async t=>{let n=v(e,t);try{return{entry:t,entryPath:n,stat:await u(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}}})),a=[];for(let{entry:e,entryPath:t,stat:n}of i)if(n){if(n.isDirectory()){let e=v(t,`SKILL.md`);a.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&a.push({filePath:t,isRootLevel:!0})}let o=await Promise.all(a.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await Nr(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 o)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await o(e,`utf-8`)}catch(t){throw new Mr(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:r,content:i}=hn(n);return!r||!r.name||!r.description?null:{name:r.name,description:r.description,location:t,content:i,basePath:g(e)}}};const Fr=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`::1`]);function Ir(e){return e}function Lr(e){if(typeof e!=`object`||!e)return!1;let t=Ir(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 Rr(e){if(typeof e!=`object`||!e)return!1;let t=Ir(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 zr(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 Br(e){return e instanceof Error?e.message:String(e)}function Vr(e){return new Promise(t=>{setTimeout(t,e)})}var Hr=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(zr(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!Lr(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(zr(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!Rr(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: ${Br(t)}`)}finally{clearTimeout(i)}}};function q(e){return e instanceof Error?e.message:String(e)}function Ur(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);return n.length===r.length&&ee(n,r)}var Wr=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)}},Gr=class{honoApp=new Ie;adminRateLimiter=new Wr;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=Fe(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 Ur(n.slice(7),t);let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&Ur(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=Pe(this.honoApp.fetch),t=te((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([je(t,`listening`),je(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 Ne(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 Kr=`localhost`,qr=12e4,Jr=`MCP_PROXY_RUNTIME_DETACHED`;function Yr(){return process.env[Jr]===`1`}async function Xr(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 Zr(e){let t=await Xr(e);for(let e of t)if(Qr(await $r(e.host,e.port)))return e;return null}function Qr(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 $r(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}}async function ei(){let t=re(import.meta.url),n=h.dirname(t),r=[h.resolve(n,`cli.mjs`),h.resolve(n,`..`,`dist`,`cli.mjs`),h.resolve(n,`..`,`..`,`dist`,`cli.mjs`)],i=[h.resolve(n,`..`,`cli.ts`),h.resolve(n,`..`,`..`,`src`,`cli.ts`)];for(let t of r)try{return await e(t),{command:process.execPath,args:[t]}}catch{continue}for(let t of i)try{return await e(t),{command:process.execPath,args:[`--import`,`tsx`,t]}}catch{continue}throw Error(`Unable to locate mcp-proxy CLI entrypoint`)}function ti(e){if(!e)return qr;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid timeout value: ${e}`);return t}async function ni(t,n){let r=Date.now()+n;for(;Date.now()<r;){try{await e(t);return}catch{}await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for runtime state file: ${t}`)}async function ri(e,t){let n=new K,r=Date.now()+t;for(;Date.now()<r;){let t=await n.read(e);if(t&&Qr(await $r(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`)}async function ii(e,t,n){let{command:r,args:i}=await ei(),a=D(r,[...i,...e],{detached:!0,cwd:n,stdio:`ignore`,env:t});return a.unref(),a}async function ai(e){let t=e.id||mn(),n=ti(e.timeoutMs),r=e.registryPath||e.registryDir,i=await j();await new K().pruneStale();let a=await Zr(i);if(a)return{host:a.host,port:a.port,serverId:a.serverId,workspaceRoot:i,reusedExistingRuntime:!0,runtimeLifecycle:a.runtimeLifecycle??`manual`};let o=e.port,s=await Xr(i);if(e.id&&s.some(e=>e.serverId===t))throw Error(`Runtime ID '${t}' belongs to an incompatible HTTP runtime; choose a new ID`);if(o!==void 0&&s.some(t=>t.host===(e.host||Kr)&&t.port===o))throw Error(`Port ${o} belongs to a different HTTP runtime; choose a free port`);let c=o,l={...process.env,[Jr]:`1`,...e.runtimeLifecycle?{MCP_PROXY_RUNTIME_LIFECYCLE:e.runtimeLifecycle}:{},...r?{PORT_REGISTRY_PATH:r,PROCESS_REGISTRY_PATH:ce(r,`processes.json`)}:{}},u=await ii([`mcp-serve`,`--type`,`http`,`--id`,t,`--host`,e.host||Kr,...c===void 0?[]:[`--port`,String(c)],...dn(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],l,i),d=new Promise((e,t)=>{u.once(`exit`,(e,n)=>{t(/* @__PURE__ */ Error(`Background runtime exited before becoming healthy (code=${e??`null`}, signal=${n??`null`})`))})}),f=h.join(K.getDefaultRuntimeDir(),`${t}.runtime.json`);try{await Promise.race([ni(f,n),d]);let{host:r,port:a}=await Promise.race([ri(t,n),d]);return{host:r,port:a,serverId:t,workspaceRoot:i,reusedExistingRuntime:!1,runtimeLifecycle:e.runtimeLifecycle??`manual`}}catch(e){throw Error(`Failed to prestart HTTP runtime '${t}': ${e instanceof Error?e.message:String(e)}`,{cause:e})}}function oi(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 si=`0.0.1-alpha.46`,ci=`<toolkit id="{{ serverId }}">
10
10
  <instruction>
11
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
12
  - For tools: Arguments schema needed to pass to use_tool
@@ -6,7 +6,7 @@ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=
6
6
  `),a=dn(i);if(a.bytes<=this.maxBytes&&a.lines<=this.maxLines)return e;let{path:o,error:s}=await cn(`output`,i),c=nn(a,o,s),l=$t(this.maxBytes,this.maxLines,c),u=`${en(i,l.maxBytes,l.maxLines)}\n\n${c}`,d=dn(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=un(e.structuredContent),n=fn(t);if(n<=this.structuredMaxBytes)return e;let{path:r,error:i}=await cn(`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:rn(e.structuredContent),...r?{fullResultPath:r}:{},...i?{resultWriteError:i}:{}}}}};function $t(e,t,n){let r=dn(`\n\n${n}`);return{maxBytes:Math.max(0,e-r.bytes),maxLines:Math.max(0,t-r.lines)}}function en(e,t,n){let r=e.split(`
7
7
  `),i=[],a=0;for(let e of r){if(i.length>=n)break;let r=+(i.length>0),o=fn(e);if(a+r+o>t){let n=t-a-r;n>0&&i.push(tn(e,n));break}i.push(e),a+=r+o}return i.join(`
8
8
  `)}function tn(e,t){if(fn(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 nn(e,t,n){let r=`[MCP tool output truncated: original ${e.lines.toLocaleString()} lines / ${hn(e.bytes)}.`;return t?`${r} Full text saved to: ${t}]`:`${r} Full output could not be saved: ${n??`unknown error`}]`}function rn(e){let t=ln(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(an),...Array.isArray(e)&&e.length>20?{itemsOmitted:e.length-20}:{},omitted:!0}}function an(e){return e.length<=120?e:`${e.slice(0,119)}…`}let on;function sn(){return on??=(0,c.mkdtemp)((0,l.join)((0,f.tmpdir)(),`mcp-proxy-output-`)),on}async function cn(e,t){try{let n=await sn(),r=(0,l.join)(n,`${e}-${(0,u.randomBytes)(8).toString(`hex`)}.txt`);return await(0,c.writeFile)(r,t,{encoding:`utf8`,mode:384}),{path:r}}catch(e){return on=void 0,{error:e instanceof Error?e.message:String(e)}}}function ln(e){return typeof e==`object`&&e?e:void 0}function un(e){try{return JSON.stringify(e)??``}catch{return``}}function dn(e){return{bytes:fn(e),lines:e.length===0?0:e.split(`
9
- `).length}}function fn(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 mn(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 hn(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 gn(e){return Array.from(e.slice(0,256)).filter(e=>{let t=e.charCodeAt(0);return t>=32&&t<=126||t>=160}).join(``)}var _n=class extends C.Client{serverName;compatibility;calls;constructor(e,t,n,r){let i=new ee.AsyncLocalStorage,a=new te.AjvJsonSchemaValidator;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:gn(this.serverName),toolName:gn(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 C.ProtocolError)||t.code!==C.ProtocolErrorCode.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 vn=`mcp-proxy-client-manager`,yn=[0,100];function bn(e){return e===`reconnecting`?`connecting`:e}function xn(e){if(e.transport===`stdio`)return It(e.config.env);let t=e.config;return It(t.headers)||V(t.bearerToken)}function Sn(e){return!e.username&&!e.password&&(e.protocol===`https:`||e.protocol===`http:`&&[`localhost`,`127.0.0.1`,`[::1]`].includes(e.hostname))}function Cn(e){if(!(`url`in e))throw Error(`Local-only MCP connections require a URL transport.`);let t=new URL(e.url);if(t.protocol!==`http:`||![`127.0.0.1`,`[::1]`,`localhost`].includes(t.hostname)||!t.port||t.username||t.password||t.hash||e.oauth!==!1||e.auth!==void 0||e.headers!==void 0||e.bearerToken!==void 0||e.bearerTokenEnv!==void 0)throw Error(`Local-only MCP connections require credential-free HTTP on an explicit loopback port, with OAuth disabled.`);return t}function wn(e){return async(t,n)=>{let r=new URL(typeof t==`string`?t:t instanceof URL?t.href:t.url);if(r.origin!==e.origin||r.username||r.password)throw Error(`MCP credential destination was rejected.`);return fetch(t,{...n,redirect:`error`})}}var Tn=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 En(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 Dn(e){return Mn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=An(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 On(e){return e instanceof C.UnauthorizedError||Mn(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 Mn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=An(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 An(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 Mn(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 Nn=class{outputGuard;serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;stdioTransport;processLease;connected=!1;lifecycleState=`closed`;recoveryError;reconnectFn;reconnectPromise;recoverAuthorization;authorizationRecovery;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}setAuthorizationRecovery(e){this.recoverAuthorization=e}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 yn.entries()){i>0&&await(0,S.setTimeout)(i,void 0,{signal:this.lifetime.signal}),this.lifetime.signal.throwIfAborted();try{let n=await t(this.lifetime.signal);this.closing&&(await En(n),this.lifetime.signal.throwIfAborted()),this.client=n.client,this.recoverAuthorization=n.recoverAuthorization,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 Tn(this.serverName,yn.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":yn.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(),(n instanceof C.UnauthorizedError||n instanceof C.InsufficientScopeError)&&this.recoverAuthorization)return this.authorizationRecovery??=this.recoverAuthorization(n,t?AbortSignal.any([t,this.lifetime.signal]):this.lifetime.signal).then(()=>this.reconnectClient(`authorization recovered`)).finally(()=>{this.authorizationRecovery=void 0}),await this.authorizationRecovery,t?.throwIfAborted(),e();if(!this.reconnectFn||!Dn(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(!(0,C.isCallToolResult)(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}},Pn=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=(0,u.randomUUID)();outputGuard;stateListeners=/* @__PURE__ */ new Set;serverStates=/* @__PURE__ */ new Map;tokenStore;serverTokenStores=/* @__PURE__ */ new Map;localOnlyOrigins=/* @__PURE__ */ new Map;serverRemovals=/* @__PURE__ */ new Map;onAuthorizationUrl;callbackTimeoutMs;callbackServer;resolveUrlCredentials;resolveSecret;constructor(e=console,t=process.cwd(),n=new Qt,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,this.resolveSecret=r.resolveSecret}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,n){if(await this.serverRemovals.get(e),n?.signal?.throwIfAborted(),this.disposed)throw Error(`The MCP client manager is disposed`);if(n?.localOnly||this.localOnlyOrigins.has(e)){if(t.transport!==`http`)throw Error(`Local-only MCP connections require HTTP.`);let n=Cn(t.config),r=this.localOnlyOrigins.get(e);if(r&&r!==n.origin||!r&&(this.clients.has(e)||this.connectionPromises.has(e)))throw Error(`Remove the existing MCP connection before changing its local-only policy.`);this.localOnlyOrigins.set(e,n.origin)}n?.tokenStore&&this.serverTokenStores.set(e,n.tokenStore),this.serverConfigs.set(e,t);let r=()=>{this.removeServer(e).catch(()=>this.logger.warn(`Failed to remove cancelled MCP server '${e}'.`))};n?.signal?.addEventListener(`abort`,r,{once:!0});try{await this.ensureConnected(e),n?.signal?.throwIfAborted()}finally{n?.signal?.removeEventListener(`abort`,r)}}async removeServer(e){let t=this.serverRemovals.get(e);if(t)return t;let n=this.serverTokenStores.get(e);this.serverConfigs.delete(e);let r=(async()=>{try{await this.disconnectServer(e)}finally{this.serverTokenStores.get(e)===n&&this.serverTokenStores.delete(e),this.localOnlyOrigins.delete(e),await n?.clear(e),this.serverStates.delete(e)}})();this.serverRemovals.set(e,r);try{await r}finally{this.serverRemovals.get(e)===r&&this.serverRemovals.delete(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=xn(t),s=n instanceof Error&&[`Invalid MCP API-key configuration.`,`MCP API-key credential is unavailable.`,`MCP credential destination was rejected.`,`MCP secret reference could not be resolved.`].includes(n.message),c=(a||o)&&!s?/* @__PURE__ */ Error(a?`MCP API-key connection failed.`:`MCP connection with a vault secret failed.`):n;throw this.emitServerState({serverName:e,state:this.disposed||r.signal.aborted&&!String(r.signal.reason).includes(`timeout`)?`closed`:On(c)?`needs-auth`:`failed`,error:c instanceof Error?c.message:String(c)}),c}finally{s=void 0,clearTimeout(o),r.signal.removeEventListener(`abort`,i),this.connectionControllers.get(e)===r&&this.connectionControllers.delete(e)}let u=new Nn(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.setAuthorizationRecovery(l.recoverAuthorization),u.setLifecycleChangeCallback((t,n)=>{this.emitServerState({serverName:e,state:bn(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(n){throw this.logger.warn(`Failed to reconnect to ${e}`,xn(t)?`connection with a vault secret failed`:n),n}}),!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 _n(n,r,e,this.outputSchemaValidation):new C.Client(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 En(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=this.localOnlyOrigins.get(e);if(o&&(t!==`http`||Cn(n).origin!==o))throw Error(`Local-only MCP destination changed. Remove and reattach the server.`);let s=n.auth,c=typeof s==`object`&&s?.type===`api-key`?s:void 0;Lt([n.url]);let l=It(n.headers)||V(n.bearerToken),u=n;if(l){let r=new URL(n.url);if(!Sn(r))throw Error(`MCP credential destination was rejected.`);let a={serverName:e,transport:t,origin:r.origin,signal:i},o=await zt(n.headers,{...a,field:`header`},this.resolveSecret),s=n.bearerToken===void 0?void 0:await Rt(n.bearerToken,{...a,field:`bearerToken`},this.resolveSecret);u={...n,...o?{headers:o}:{},...s===void 0?{}:{bearerToken:s}}}let d=this.resolveAuthHeaders(u),f=o?wn(new URL(o)):void 0;if(c){let r=new URL(n.url),a=c.mode===`bearer`?`Authorization`:c.name;if(c.mode!==`bearer`&&c.mode!==`header`||!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(a)||c.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))||!Sn(r)||n.bearerToken||n.bearerTokenEnv||n.oauth!==void 0||Object.keys(d??{}).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:c,signal:i})}catch{throw Error(`MCP API-key credential is unavailable.`)}i?.throwIfAborted();let s=o?.[a];if(!s||Object.keys(o??{}).length!==1||Array.from(s).some(e=>e.charCodeAt(0)<=31||e.charCodeAt(0)===127)||c.mode===`bearer`&&!/^Bearer [^\s]+$/.test(s))throw Error(`MCP API-key credential is unavailable.`);d={...d,[a]:s},f=wn(r)}l&&!f&&(f=wn(new URL(n.url)));let p=!!c||l,m=this.createSdkClient(e,t===`sse`?`legacy`:`auto`),h=d?{headers:d}:void 0,g=await this.createAuthProvider(e,n);await g?.prepareCallback(),i?.throwIfAborted();let _=g?new Xt(g,n.url,i):void 0,v={requestInit:h,authProvider:_,...f?{fetch:f}:{}},y=t===`http`?new C.StreamableHTTPClientTransport(new URL(n.url),v):new C.SSEClientTransport(new URL(n.url),v),b=()=>{g?.cancelAuthorization(),m.close().catch(t=>this.logger.warn(`Failed to close cancelled client ${e}`,p?`credential connection closed`:t))};i?.addEventListener(`abort`,b,{once:!0});let x=!1;try{return await m.connect(y),i?.throwIfAborted(),x=!0,{client:m,..._?{recoverAuthorization:(e,t)=>_.recover(e,t)}:{}}}catch(o){if(i?.throwIfAborted(),c)throw Error(`MCP API-key connection failed.`);if(!g||!_||!r||!(o instanceof C.InsufficientScopeError)&&(!On(o)||!g.hasPendingAuthorization()))throw o;return this.logger.info(`[oauth] Waiting for authorization of MCP server "${e}"`),a?.(!0),await _.recover(o,i,()=>{a?.(!1),this.emitServerState({serverName:e,state:`connecting`})}),i?.throwIfAborted(),await this.connectUrlSdkClient(e,t,n,!1,i,a)}finally{i?.removeEventListener(`abort`,b),x||(g?.cancelAuthorization(),await m.close().catch(t=>this.logger.warn(`Failed to close client ${e}`,p?`credential connection closed`:t)))}}resolveAuthHeaders(e){let t={...e.headers};if(ze(e)===`bearer`){let n=e.bearerTokenEnv?this.env?.[e.bearerTokenEnv]??Ve(e):Ve(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}async createAuthProvider(e,t){return He({serverName:e,config:t,store:this.serverTokenStores.get(e)??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){Lt([n.command,...n.args??[],n.cwd]);let i=await zt(n.env,{serverName:e,field:`env`,transport:`stdio`,command:n.command,args:[...n.args??[]],signal:r},this.resolveSecret);r?.throwIfAborted();let a=new w.StdioClientTransport({command:n.command,args:n.args,cwd:this.executionCwd?(0,l.resolve)(this.executionCwd,n.cwd??`.`):this.workspaceRoot?(0,l.resolve)(this.workspaceRoot,n.cwd??`.`):n.cwd,env:{...process.env,...this.env,...i,PROJECT_PATH:this.repositoryPath,[g.PROCESS_REGISTRY_OWNER_KIND_ENV_VAR]:vn,[g.PROCESS_REGISTRY_OWNER_ID_ENV_VAR]:this.processOwnerId},stderr:`pipe`}),o=()=>{En({client:t,stdioTransport:a}).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(a),r?.throwIfAborted(),this.relayChildStderr(e,a.stderr);let i=a.pid;if(typeof i!=`number`||i<=0)throw Error(`Failed to capture pid for stdio child process on server "${e}"`);let o=await(0,g.createProcessLease)({repositoryPath:this.repositoryPath,serviceName:e,serviceType:`tool`,pid:i,command:n.command,args:n.args,metadata:{transport:`stdio`},ownerKind:vn,ownerId:this.processOwnerId,resourceKey:e});return t.onclose=()=>{let t=this.clients.get(e);t instanceof Nn&&t.handleStdioClosed(a)},{client:t,processLease:o,stdioTransport:a}}catch(n){try{await En({client:t,stdioTransport:a})}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 Fn=`install`,In=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,Ln=`pipe`;function Rn(e){return typeof e==`object`&&!!e&&`command`in e}var zn=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`||!Rn(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 In.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`,Fn,`-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`,Fn,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=(0,m.spawn)(e,t,{stdio:[`ignore`,Ln,Ln],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 Bn=`.runtime.json`;async function Vn(e){await(0,c.mkdir)(e,{recursive:!0,mode:448});try{await(0,c.chmod)(e,448)}catch{}}function Hn(e){return typeof e==`object`&&!!e}function Un(e){return Hn(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 Wn(e){return e instanceof Error?e.message:String(e)}function Gn(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(0,l.join)((0,f.homedir)(),`.mcp-proxy`,`runtimes`)}getRecordPath(e){return(0,l.join)(this.runtimeDir,`${e}${Bn}`)}async write(e){await Vn(this.runtimeDir);let t=this.getRecordPath(e.serverId);await(0,c.writeFile)(t,JSON.stringify(e,null,2),{encoding:`utf-8`,mode:384})}async read(e){let t=this.getRecordPath(e);try{let e=await(0,c.readFile)(t,`utf-8`),n=JSON.parse(e);return Un(n)?n:null}catch(n){if(Hn(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${Wn(n)}`)}}async list(){try{let e=(await(0,c.readdir)(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(Bn));return(await Promise.all(e.map(async e=>{try{let t=await(0,c.readFile)((0,l.join)(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return Un(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(Hn(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${Wn(e)}`)}}async listOrphans(e){return(await this.list()).filter(t=>!e.has(t.serverId))}async pruneStale(){let e=(await this.list()).filter(e=>!Gn(e.pid));return await Promise.all(e.map(async e=>this.remove(e.serverId))),e}async remove(e){await(0,c.rm)(this.getRecordPath(e),{force:!0})}},Kn=class extends Error{filePath;cause;constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function qn(e){try{return await(0,c.access)(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 Jn=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=(0,l.isAbsolute)(e)?e:(0,l.join)(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=(0,l.isAbsolute)(e)?e:(0,l.join)(this.cwd,e);return{skillsDir:t,exists:await qn(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=(0,c.watch)(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(0,c.readdir)(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=(0,l.join)(e,n),i=await(0,c.stat)(r);i.isDirectory()?await this.collectSkillSnapshots(r,t):n===`SKILL.md`&&t.set(r,i.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 qn(e))return n}catch(t){throw new Kn(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await(0,c.readdir)(e)}catch(t){throw new Kn(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let i=await Promise.all(r.map(async t=>{let n=(0,l.join)(e,t);try{return{entry:t,entryPath:n,stat:await(0,c.stat)(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}}})),a=[];for(let{entry:e,entryPath:t,stat:n}of i)if(n){if(n.isDirectory()){let e=(0,l.join)(t,`SKILL.md`);a.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&a.push({filePath:t,isRootLevel:!0})}let o=await Promise.all(a.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await qn(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 o)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await(0,c.readFile)(e,`utf-8`)}catch(t){throw new Kn(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:r,content:i}=Ot(n);return!r||!r.name||!r.description?null:{name:r.name,description:r.description,location:t,content:i,basePath:(0,l.dirname)(e)}}};const Yn=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`::1`]);function Xn(e){return e}function Zn(e){if(typeof e!=`object`||!e)return!1;let t=Xn(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 Qn(e){if(typeof e!=`object`||!e)return!1;let t=Xn(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 $n(e,t){if(!Yn.has(e.host))throw Error(`Refusing to connect to non-loopback host '${e.host}'. Only ${Array.from(Yn).join(`, `)} are allowed.`);return`http://${e.host}:${e.port}${t}`}function er(e){return e instanceof Error?e.message:String(e)}function tr(e){return new Promise(t=>{setTimeout(t,e)})}var nr=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($n(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!Zn(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($n(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!Qn(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 tr(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: ${er(t)}`)}finally{clearTimeout(i)}}};function q(e){return e instanceof Error?e.message:String(e)}function rr(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);return n.length===r.length&&(0,u.timingSafeEqual)(n,r)}var ir=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)}},ar=class{honoApp=new ie.Hono;adminRateLimiter=new ir;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=(0,y.createMcpHandler)(e,{legacy:`reject`,onerror:e=>this.logger.error(`MCP handler failed: ${e.message}`)}),this.nodeMcpHandler=(0,re.toNodeHandler)(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 rr(n.slice(7),t);let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&rr(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=(0,ne.getRequestListener)(this.honoApp.fetch),t=(0,d.createServer)((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([(0,T.once)(t,`listening`),(0,T.once)(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(0,E.promisify)(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 or=`localhost`,sr=12e4,cr=`MCP_PROXY_RUNTIME_DETACHED`;function lr(){return process.env[cr]===`1`}async function ur(e){return(await new g.ProcessRegistryService(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 dr(e){let t=await ur(e);for(let e of t)if(fr(await pr(e.host,e.port)))return e;return null}function fr(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 pr(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}}async function mr(){let e=(0,h.fileURLToPath)(require("url").pathToFileURL(__filename).href),t=l.default.dirname(e),n=[l.default.resolve(t,`cli.mjs`),l.default.resolve(t,`..`,`dist`,`cli.mjs`),l.default.resolve(t,`..`,`..`,`dist`,`cli.mjs`)],r=[l.default.resolve(t,`..`,`cli.ts`),l.default.resolve(t,`..`,`..`,`src`,`cli.ts`)];for(let e of n)try{return await(0,c.access)(e),{command:process.execPath,args:[e]}}catch{continue}for(let e of r)try{return await(0,c.access)(e),{command:process.execPath,args:[`--import`,`tsx`,e]}}catch{continue}throw Error(`Unable to locate mcp-proxy CLI entrypoint`)}function hr(e){if(!e)return sr;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid timeout value: ${e}`);return t}async function gr(e,t){let n=Date.now()+t;for(;Date.now()<n;){try{await(0,c.access)(e);return}catch{}await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for runtime state file: ${e}`)}async function _r(e,t){let n=new K,r=Date.now()+t;for(;Date.now()<r;){let t=await n.read(e);if(t&&fr(await pr(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`)}async function vr(e,t,n){let{command:r,args:i}=await mr(),a=(0,m.spawn)(r,[...i,...e],{detached:!0,cwd:n,stdio:`ignore`,env:t});return a.unref(),a}async function yr(e){let t=e.id||Dt(),n=hr(e.timeoutMs),r=e.registryPath||e.registryDir,i=await O();await new K().pruneStale();let a=await dr(i);if(a)return{host:a.host,port:a.port,serverId:a.serverId,workspaceRoot:i,reusedExistingRuntime:!0,runtimeLifecycle:a.runtimeLifecycle??`manual`};let o=e.port,s=await ur(i);if(e.id&&s.some(e=>e.serverId===t))throw Error(`Runtime ID '${t}' belongs to an incompatible HTTP runtime; choose a new ID`);if(o!==void 0&&s.some(t=>t.host===(e.host||or)&&t.port===o))throw Error(`Port ${o} belongs to a different HTTP runtime; choose a free port`);let c=o,u={...process.env,[cr]:`1`,...e.runtimeLifecycle?{MCP_PROXY_RUNTIME_LIFECYCLE:e.runtimeLifecycle}:{},...r?{PORT_REGISTRY_PATH:r,PROCESS_REGISTRY_PATH:(0,g.resolveSiblingRegistryPath)(r,`processes.json`)}:{}},d=await vr([`mcp-serve`,`--type`,`http`,`--id`,t,`--host`,e.host||or,...c===void 0?[]:[`--port`,String(c)],...wt(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,i),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=l.default.join(K.getDefaultRuntimeDir(),`${t}.runtime.json`);try{await Promise.race([gr(p,n),f]);let{host:r,port:a}=await Promise.race([_r(t,n),f]);return{host:r,port:a,serverId:t,workspaceRoot:i,reusedExistingRuntime:!1,runtimeLifecycle:e.runtimeLifecycle??`manual`}}catch(e){throw Error(`Failed to prestart HTTP runtime '${t}': ${e instanceof Error?e.message:String(e)}`,{cause:e})}}function br(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 xr=`0.0.1-alpha.44`,Sr=`<toolkit id="{{ serverId }}">
9
+ `).length}}function fn(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 mn(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 hn(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 gn(e){return Array.from(e.slice(0,256)).filter(e=>{let t=e.charCodeAt(0);return t>=32&&t<=126||t>=160}).join(``)}var _n=class extends C.Client{serverName;compatibility;calls;constructor(e,t,n,r){let i=new ee.AsyncLocalStorage,a=new te.AjvJsonSchemaValidator;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:gn(this.serverName),toolName:gn(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 C.ProtocolError)||t.code!==C.ProtocolErrorCode.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 vn=`mcp-proxy-client-manager`,yn=[0,100];function bn(e){return e===`reconnecting`?`connecting`:e}function xn(e){if(e.transport===`stdio`)return It(e.config.env);let t=e.config;return It(t.headers)||V(t.bearerToken)}function Sn(e){return!e.username&&!e.password&&(e.protocol===`https:`||e.protocol===`http:`&&[`localhost`,`127.0.0.1`,`[::1]`].includes(e.hostname))}function Cn(e){if(!(`url`in e))throw Error(`Local-only MCP connections require a URL transport.`);let t=new URL(e.url);if(t.protocol!==`http:`||![`127.0.0.1`,`[::1]`,`localhost`].includes(t.hostname)||!t.port||t.username||t.password||t.hash||e.oauth!==!1||e.auth!==void 0||e.headers!==void 0||e.bearerToken!==void 0||e.bearerTokenEnv!==void 0)throw Error(`Local-only MCP connections require credential-free HTTP on an explicit loopback port, with OAuth disabled.`);return t}function wn(e){return async(t,n)=>{let r=new URL(typeof t==`string`?t:t instanceof URL?t.href:t.url);if(r.origin!==e.origin||r.username||r.password)throw Error(`MCP credential destination was rejected.`);return fetch(t,{...n,redirect:`error`})}}var Tn=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 En(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 Dn(e){return Mn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=An(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 On(e){return e instanceof C.UnauthorizedError||Mn(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 Mn(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=An(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 An(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 Mn(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 Nn=class{outputGuard;serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;stdioTransport;processLease;connected=!1;lifecycleState=`closed`;recoveryError;reconnectFn;reconnectPromise;recoverAuthorization;authorizationRecovery;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}setAuthorizationRecovery(e){this.recoverAuthorization=e}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 yn.entries()){i>0&&await(0,S.setTimeout)(i,void 0,{signal:this.lifetime.signal}),this.lifetime.signal.throwIfAborted();try{let n=await t(this.lifetime.signal);this.closing&&(await En(n),this.lifetime.signal.throwIfAborted()),this.client=n.client,this.recoverAuthorization=n.recoverAuthorization,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 Tn(this.serverName,yn.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":yn.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(),(n instanceof C.UnauthorizedError||n instanceof C.InsufficientScopeError)&&this.recoverAuthorization)return this.authorizationRecovery??=this.recoverAuthorization(n,t?AbortSignal.any([t,this.lifetime.signal]):this.lifetime.signal).then(()=>this.reconnectClient(`authorization recovered`)).finally(()=>{this.authorizationRecovery=void 0}),await this.authorizationRecovery,t?.throwIfAborted(),e();if(!this.reconnectFn||!Dn(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(!(0,C.isCallToolResult)(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}},Pn=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=(0,u.randomUUID)();outputGuard;stateListeners=/* @__PURE__ */ new Set;serverStates=/* @__PURE__ */ new Map;tokenStore;serverTokenStores=/* @__PURE__ */ new Map;localOnlyOrigins=/* @__PURE__ */ new Map;serverRemovals=/* @__PURE__ */ new Map;onAuthorizationUrl;callbackTimeoutMs;callbackServer;resolveUrlCredentials;resolveSecret;constructor(e=console,t=process.cwd(),n=new Qt,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,this.resolveSecret=r.resolveSecret}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,n){if(await this.serverRemovals.get(e),n?.signal?.throwIfAborted(),this.disposed)throw Error(`The MCP client manager is disposed`);if(n?.localOnly||this.localOnlyOrigins.has(e)){if(t.transport!==`http`)throw Error(`Local-only MCP connections require HTTP.`);let n=Cn(t.config),r=this.localOnlyOrigins.get(e);if(r&&r!==n.origin||!r&&(this.clients.has(e)||this.connectionPromises.has(e)))throw Error(`Remove the existing MCP connection before changing its local-only policy.`);this.localOnlyOrigins.set(e,n.origin)}n?.tokenStore&&this.serverTokenStores.set(e,n.tokenStore),this.serverConfigs.set(e,t);let r=()=>{this.removeServer(e).catch(()=>this.logger.warn(`Failed to remove cancelled MCP server '${e}'.`))};n?.signal?.addEventListener(`abort`,r,{once:!0});try{await this.ensureConnected(e),n?.signal?.throwIfAborted()}finally{n?.signal?.removeEventListener(`abort`,r)}}async removeServer(e){let t=this.serverRemovals.get(e);if(t)return t;let n=this.serverTokenStores.get(e);this.serverConfigs.delete(e);let r=(async()=>{try{await this.disconnectServer(e)}finally{this.serverTokenStores.get(e)===n&&this.serverTokenStores.delete(e),this.localOnlyOrigins.delete(e),await n?.clear(e),this.serverStates.delete(e)}})();this.serverRemovals.set(e,r);try{await r}finally{this.serverRemovals.get(e)===r&&this.serverRemovals.delete(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=xn(t),s=n instanceof Error&&[`Invalid MCP API-key configuration.`,`MCP API-key credential is unavailable.`,`MCP credential destination was rejected.`,`MCP secret reference could not be resolved.`].includes(n.message),c=(a||o)&&!s?/* @__PURE__ */ Error(a?`MCP API-key connection failed.`:`MCP connection with a vault secret failed.`):n;throw this.emitServerState({serverName:e,state:this.disposed||r.signal.aborted&&!String(r.signal.reason).includes(`timeout`)?`closed`:On(c)?`needs-auth`:`failed`,error:c instanceof Error?c.message:String(c)}),c}finally{s=void 0,clearTimeout(o),r.signal.removeEventListener(`abort`,i),this.connectionControllers.get(e)===r&&this.connectionControllers.delete(e)}let u=new Nn(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.setAuthorizationRecovery(l.recoverAuthorization),u.setLifecycleChangeCallback((t,n)=>{this.emitServerState({serverName:e,state:bn(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(n){throw this.logger.warn(`Failed to reconnect to ${e}`,xn(t)?`connection with a vault secret failed`:n),n}}),!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 _n(n,r,e,this.outputSchemaValidation):new C.Client(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 En(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=this.localOnlyOrigins.get(e);if(o&&(t!==`http`||Cn(n).origin!==o))throw Error(`Local-only MCP destination changed. Remove and reattach the server.`);let s=n.auth,c=typeof s==`object`&&s?.type===`api-key`?s:void 0;Lt([n.url]);let l=It(n.headers)||V(n.bearerToken),u=n;if(l){let r=new URL(n.url);if(!Sn(r))throw Error(`MCP credential destination was rejected.`);let a={serverName:e,transport:t,origin:r.origin,signal:i},o=await zt(n.headers,{...a,field:`header`},this.resolveSecret),s=n.bearerToken===void 0?void 0:await Rt(n.bearerToken,{...a,field:`bearerToken`},this.resolveSecret);u={...n,...o?{headers:o}:{},...s===void 0?{}:{bearerToken:s}}}let d=this.resolveAuthHeaders(u),f=o?wn(new URL(o)):void 0;if(c){let r=new URL(n.url),a=c.mode===`bearer`?`Authorization`:c.name;if(c.mode!==`bearer`&&c.mode!==`header`||!/^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/.test(a)||c.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))||!Sn(r)||n.bearerToken||n.bearerTokenEnv||n.oauth!==void 0||Object.keys(d??{}).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:c,signal:i})}catch{throw Error(`MCP API-key credential is unavailable.`)}i?.throwIfAborted();let s=o?.[a];if(!s||Object.keys(o??{}).length!==1||Array.from(s).some(e=>e.charCodeAt(0)<=31||e.charCodeAt(0)===127)||c.mode===`bearer`&&!/^Bearer [^\s]+$/.test(s))throw Error(`MCP API-key credential is unavailable.`);d={...d,[a]:s},f=wn(r)}l&&!f&&(f=wn(new URL(n.url)));let p=!!c||l,m=this.createSdkClient(e,t===`sse`?`legacy`:`auto`),h=d?{headers:d}:void 0,g=await this.createAuthProvider(e,n);await g?.prepareCallback(),i?.throwIfAborted();let _=g?new Xt(g,n.url,i):void 0,v={requestInit:h,authProvider:_,...f?{fetch:f}:{}},y=t===`http`?new C.StreamableHTTPClientTransport(new URL(n.url),v):new C.SSEClientTransport(new URL(n.url),v),b=()=>{g?.cancelAuthorization(),m.close().catch(t=>this.logger.warn(`Failed to close cancelled client ${e}`,p?`credential connection closed`:t))};i?.addEventListener(`abort`,b,{once:!0});let x=!1;try{return await m.connect(y),i?.throwIfAborted(),x=!0,{client:m,..._?{recoverAuthorization:(e,t)=>_.recover(e,t)}:{}}}catch(o){if(i?.throwIfAborted(),c)throw Error(`MCP API-key connection failed.`);if(!g||!_||!r||!(o instanceof C.InsufficientScopeError)&&(!On(o)||!g.hasPendingAuthorization()))throw o;return this.logger.info(`[oauth] Waiting for authorization of MCP server "${e}"`),a?.(!0),await _.recover(o,i,()=>{a?.(!1),this.emitServerState({serverName:e,state:`connecting`})}),i?.throwIfAborted(),await this.connectUrlSdkClient(e,t,n,!1,i,a)}finally{i?.removeEventListener(`abort`,b),x||(g?.cancelAuthorization(),await m.close().catch(t=>this.logger.warn(`Failed to close client ${e}`,p?`credential connection closed`:t)))}}resolveAuthHeaders(e){let t={...e.headers};if(ze(e)===`bearer`){let n=e.bearerTokenEnv?this.env?.[e.bearerTokenEnv]??Ve(e):Ve(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}async createAuthProvider(e,t){return He({serverName:e,config:t,store:this.serverTokenStores.get(e)??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){Lt([n.command,...n.args??[],n.cwd]);let i=await zt(n.env,{serverName:e,field:`env`,transport:`stdio`,command:n.command,args:[...n.args??[]],signal:r},this.resolveSecret);r?.throwIfAborted();let a=new w.StdioClientTransport({command:n.command,args:n.args,cwd:this.executionCwd?(0,l.resolve)(this.executionCwd,n.cwd??`.`):this.workspaceRoot?(0,l.resolve)(this.workspaceRoot,n.cwd??`.`):n.cwd,env:{...process.env,...this.env,...i,PROJECT_PATH:this.repositoryPath,[g.PROCESS_REGISTRY_OWNER_KIND_ENV_VAR]:vn,[g.PROCESS_REGISTRY_OWNER_ID_ENV_VAR]:this.processOwnerId},stderr:`pipe`}),o=()=>{En({client:t,stdioTransport:a}).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(a),r?.throwIfAborted(),this.relayChildStderr(e,a.stderr);let i=a.pid;if(typeof i!=`number`||i<=0)throw Error(`Failed to capture pid for stdio child process on server "${e}"`);let o=await(0,g.createProcessLease)({repositoryPath:this.repositoryPath,serviceName:e,serviceType:`tool`,pid:i,command:n.command,args:n.args,metadata:{transport:`stdio`},ownerKind:vn,ownerId:this.processOwnerId,resourceKey:e});return t.onclose=()=>{let t=this.clients.get(e);t instanceof Nn&&t.handleStdioClosed(a)},{client:t,processLease:o,stdioTransport:a}}catch(n){try{await En({client:t,stdioTransport:a})}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 Fn=`install`,In=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,Ln=`pipe`;function Rn(e){return typeof e==`object`&&!!e&&`command`in e}var zn=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`||!Rn(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 In.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`,Fn,`-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`,Fn,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=(0,m.spawn)(e,t,{stdio:[`ignore`,Ln,Ln],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 Bn=`.runtime.json`;async function Vn(e){await(0,c.mkdir)(e,{recursive:!0,mode:448});try{await(0,c.chmod)(e,448)}catch{}}function Hn(e){return typeof e==`object`&&!!e}function Un(e){return Hn(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 Wn(e){return e instanceof Error?e.message:String(e)}function Gn(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(0,l.join)((0,f.homedir)(),`.mcp-proxy`,`runtimes`)}getRecordPath(e){return(0,l.join)(this.runtimeDir,`${e}${Bn}`)}async write(e){await Vn(this.runtimeDir);let t=this.getRecordPath(e.serverId);await(0,c.writeFile)(t,JSON.stringify(e,null,2),{encoding:`utf-8`,mode:384})}async read(e){let t=this.getRecordPath(e);try{let e=await(0,c.readFile)(t,`utf-8`),n=JSON.parse(e);return Un(n)?n:null}catch(n){if(Hn(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${Wn(n)}`)}}async list(){try{let e=(await(0,c.readdir)(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(Bn));return(await Promise.all(e.map(async e=>{try{let t=await(0,c.readFile)((0,l.join)(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return Un(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(Hn(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${Wn(e)}`)}}async listOrphans(e){return(await this.list()).filter(t=>!e.has(t.serverId))}async pruneStale(){let e=(await this.list()).filter(e=>!Gn(e.pid));return await Promise.all(e.map(async e=>this.remove(e.serverId))),e}async remove(e){await(0,c.rm)(this.getRecordPath(e),{force:!0})}},Kn=class extends Error{filePath;cause;constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function qn(e){try{return await(0,c.access)(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 Jn=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=(0,l.isAbsolute)(e)?e:(0,l.join)(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=(0,l.isAbsolute)(e)?e:(0,l.join)(this.cwd,e);return{skillsDir:t,exists:await qn(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=(0,c.watch)(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(0,c.readdir)(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=(0,l.join)(e,n),i=await(0,c.stat)(r);i.isDirectory()?await this.collectSkillSnapshots(r,t):n===`SKILL.md`&&t.set(r,i.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 qn(e))return n}catch(t){throw new Kn(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await(0,c.readdir)(e)}catch(t){throw new Kn(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let i=await Promise.all(r.map(async t=>{let n=(0,l.join)(e,t);try{return{entry:t,entryPath:n,stat:await(0,c.stat)(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}}})),a=[];for(let{entry:e,entryPath:t,stat:n}of i)if(n){if(n.isDirectory()){let e=(0,l.join)(t,`SKILL.md`);a.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&a.push({filePath:t,isRootLevel:!0})}let o=await Promise.all(a.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await qn(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 o)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await(0,c.readFile)(e,`utf-8`)}catch(t){throw new Kn(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:r,content:i}=Ot(n);return!r||!r.name||!r.description?null:{name:r.name,description:r.description,location:t,content:i,basePath:(0,l.dirname)(e)}}};const Yn=/* @__PURE__ */ new Set([`localhost`,`127.0.0.1`,`::1`]);function Xn(e){return e}function Zn(e){if(typeof e!=`object`||!e)return!1;let t=Xn(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 Qn(e){if(typeof e!=`object`||!e)return!1;let t=Xn(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 $n(e,t){if(!Yn.has(e.host))throw Error(`Refusing to connect to non-loopback host '${e.host}'. Only ${Array.from(Yn).join(`, `)} are allowed.`);return`http://${e.host}:${e.port}${t}`}function er(e){return e instanceof Error?e.message:String(e)}function tr(e){return new Promise(t=>{setTimeout(t,e)})}var nr=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($n(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!Zn(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($n(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!Qn(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 tr(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: ${er(t)}`)}finally{clearTimeout(i)}}};function q(e){return e instanceof Error?e.message:String(e)}function rr(e,t){let n=Buffer.from(e,`utf-8`),r=Buffer.from(t,`utf-8`);return n.length===r.length&&(0,u.timingSafeEqual)(n,r)}var ir=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)}},ar=class{honoApp=new ie.Hono;adminRateLimiter=new ir;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=(0,y.createMcpHandler)(e,{legacy:`reject`,onerror:e=>this.logger.error(`MCP handler failed: ${e.message}`)}),this.nodeMcpHandler=(0,re.toNodeHandler)(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 rr(n.slice(7),t);let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&rr(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=(0,ne.getRequestListener)(this.honoApp.fetch),t=(0,d.createServer)((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([(0,T.once)(t,`listening`),(0,T.once)(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(0,E.promisify)(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 or=`localhost`,sr=12e4,cr=`MCP_PROXY_RUNTIME_DETACHED`;function lr(){return process.env[cr]===`1`}async function ur(e){return(await new g.ProcessRegistryService(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 dr(e){let t=await ur(e);for(let e of t)if(fr(await pr(e.host,e.port)))return e;return null}function fr(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 pr(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}}async function mr(){let e=(0,h.fileURLToPath)(require("url").pathToFileURL(__filename).href),t=l.default.dirname(e),n=[l.default.resolve(t,`cli.mjs`),l.default.resolve(t,`..`,`dist`,`cli.mjs`),l.default.resolve(t,`..`,`..`,`dist`,`cli.mjs`)],r=[l.default.resolve(t,`..`,`cli.ts`),l.default.resolve(t,`..`,`..`,`src`,`cli.ts`)];for(let e of n)try{return await(0,c.access)(e),{command:process.execPath,args:[e]}}catch{continue}for(let e of r)try{return await(0,c.access)(e),{command:process.execPath,args:[`--import`,`tsx`,e]}}catch{continue}throw Error(`Unable to locate mcp-proxy CLI entrypoint`)}function hr(e){if(!e)return sr;let t=Number.parseInt(e,10);if(!Number.isInteger(t)||t<=0)throw Error(`Invalid timeout value: ${e}`);return t}async function gr(e,t){let n=Date.now()+t;for(;Date.now()<n;){try{await(0,c.access)(e);return}catch{}await new Promise(e=>setTimeout(e,250))}throw Error(`Timed out waiting for runtime state file: ${e}`)}async function _r(e,t){let n=new K,r=Date.now()+t;for(;Date.now()<r;){let t=await n.read(e);if(t&&fr(await pr(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`)}async function vr(e,t,n){let{command:r,args:i}=await mr(),a=(0,m.spawn)(r,[...i,...e],{detached:!0,cwd:n,stdio:`ignore`,env:t});return a.unref(),a}async function yr(e){let t=e.id||Dt(),n=hr(e.timeoutMs),r=e.registryPath||e.registryDir,i=await O();await new K().pruneStale();let a=await dr(i);if(a)return{host:a.host,port:a.port,serverId:a.serverId,workspaceRoot:i,reusedExistingRuntime:!0,runtimeLifecycle:a.runtimeLifecycle??`manual`};let o=e.port,s=await ur(i);if(e.id&&s.some(e=>e.serverId===t))throw Error(`Runtime ID '${t}' belongs to an incompatible HTTP runtime; choose a new ID`);if(o!==void 0&&s.some(t=>t.host===(e.host||or)&&t.port===o))throw Error(`Port ${o} belongs to a different HTTP runtime; choose a free port`);let c=o,u={...process.env,[cr]:`1`,...e.runtimeLifecycle?{MCP_PROXY_RUNTIME_LIFECYCLE:e.runtimeLifecycle}:{},...r?{PORT_REGISTRY_PATH:r,PROCESS_REGISTRY_PATH:(0,g.resolveSiblingRegistryPath)(r,`processes.json`)}:{}},d=await vr([`mcp-serve`,`--type`,`http`,`--id`,t,`--host`,e.host||or,...c===void 0?[]:[`--port`,String(c)],...wt(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,i),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=l.default.join(K.getDefaultRuntimeDir(),`${t}.runtime.json`);try{await Promise.race([gr(p,n),f]);let{host:r,port:a}=await Promise.race([_r(t,n),f]);return{host:r,port:a,serverId:t,workspaceRoot:i,reusedExistingRuntime:!1,runtimeLifecycle:e.runtimeLifecycle??`manual`}}catch(e){throw Error(`Failed to prestart HTTP runtime '${t}': ${e instanceof Error?e.message:String(e)}`,{cause:e})}}function br(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 xr=`0.0.1-alpha.46`,Sr=`<toolkit id="{{ serverId }}">
10
10
  <instruction>
11
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
12
  - For tools: Arguments schema needed to pass to use_tool
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agimon-ai/po-mcp-proxy",
3
- "version": "0.0.1-alpha.44",
3
+ "version": "0.0.1-alpha.46",
4
4
  "description": "MCP proxy server package",
5
5
  "keywords": [
6
6
  "ai",
@@ -52,7 +52,7 @@
52
52
  "@agimon-ai/foundation-port-registry": "0.30.14",
53
53
  "@agimon-ai/foundation-process-registry": "0.30.14",
54
54
  "@agimon-ai/foundation-validator": "0.27.14",
55
- "@agimon-ai/po-logsink": "0.0.1-alpha.47",
55
+ "@agimon-ai/po-logsink": "0.0.1-alpha.49",
56
56
  "@hono/node-server": "2.1.5",
57
57
  "@modelcontextprotocol/client": "2.3.1",
58
58
  "@modelcontextprotocol/core": "2.3.1",