@agimon-ai/po-mcp-proxy 0.0.1-alpha.4 → 0.0.1-alpha.41

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/README.md CHANGED
@@ -246,6 +246,10 @@ Scheme selection when `auth` is not set: a server with a bearer token or a crede
246
246
 
247
247
  For `authorization_code`, mcp-proxy logs an authorization URL, listens on `http://127.0.0.1:19876/callback`, exchanges the code once you approve, and retries the connection. Tokens are persisted under `~/.mcp-proxy/oauth` with `0600` permissions and are refreshed automatically, so later runs do not prompt. Credentials are bound to the URL they were issued for: repointing a server at a different host discards them rather than replaying them against the new host.
248
248
 
249
+ OAuth refresh runs before the next request when an access token approaches its saved absolute expiry. Idle connections do not run background refresh timers. A 401 also refreshes through the same per-credential lock, so healthy file-backed stores coordinate rotating refresh tokens across processes. Lock failures fail closed; a store that degraded to memory coordinates only inside its process. Older credentials without expiry continue to refresh on 401. Transient refresh failures retain the current credentials, and rejected refresh grants can request authorization again on an established connection. A changed callback address does not replace the client that issued a still-valid refresh token.
250
+
251
+ Embedded hosts can add a session-only URL server with `clientManager.connectToServer(name, config, { tokenStore: new MemoryTokenStore(), signal })`. The override survives reconnects but never reads persistent credentials. `removeServer(name)` disconnects and clears that override. Memory-store authorization uses an in-process callback listener with no rendezvous files. Definitions-cache collection persists only config-source server names, not dynamically added test servers.
252
+
249
253
  ### Output Guard
250
254
 
251
255
  Downstream tool results are capped before they reach the calling agent, so one chatty or hostile server cannot evict the agent's context. Oversized text is truncated to a head preview and the full payload is written to an owner-only temp file named in the truncation notice; a `_meta['agiflowai/outputGuard']` report records the original and returned sizes. Images and other non-text blocks pass through untouched.
@@ -485,7 +489,7 @@ Returns detailed tool schemas and skill instructions.
485
489
 
486
490
  ### `use_tool`
487
491
 
488
- Executes a proxied tool in `meta` and `search` modes. In `group` mode, use the server-scoped form such as `browse-tool__use_tool`.
492
+ Executes a proxied tool in `meta` and `search` modes. In `group` mode, use the server-scoped form such as `example__use_tool`.
489
493
 
490
494
  ```json
491
495
  {
package/dist/cli.cjs CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- const e=require("./src-7ZMUtqrH.cjs");let t=require("node:fs"),n=require("node:path"),r=require("node:crypto"),i=require("node:fs/promises"),a=require("@agimon-ai/foundation-process-registry"),o=require("js-yaml");o=e.dt(o,1);let s=require("@agimon-ai/foundation-port-registry"),c=require("liquidjs"),l=require("commander");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 l.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 a.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=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=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.I(t.config),s=o.length>0?null:e.P(),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.L(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 l.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.F).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-1iVj1fH_.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:
6
6
  `);for(let e of u)console.log(`Skill: ${e.name}`),console.log(`Location: ${e.location}`),console.log(`Instructions:\n${e.instructions}`),console.log(``)}if(p.length>0){console.log(`
7
- Next steps:`);for(let e of p)console.log(` • ${e}`);console.log(``)}d.length>0&&console.error(`\nTools/skills not found: ${d.join(`, `)}`),l.length===0&&u.length===0&&(console.error(`No tools or skills found`),process.exit(1))}})}catch(e){console.error(`Error executing describe-tools: ${S(e)}`),process.exit(1)}});function w(e){return e instanceof Error?e.message:String(e)}const ee=new l.Command(`get-prompt`).description(`Get a prompt by name from a connected MCP server`).argument(`<promptName>`,`Prompt name to fetch`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Server name (required if prompt exists on multiple servers)`).option(`-a, --args <json>`,`Prompt arguments as JSON string`,`{}`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{throw Error(`Invalid JSON in --args`)}await x(t,async({clientManager:r})=>{let i=r.getAllClients();if(t.server){let i=r.getClient(t.server);if(!i)throw Error(`Server "${t.server}" not found`);let a=await i.getPrompt(e,n);if(t.json)console.log(JSON.stringify(a,null,2));else for(let e of a.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}return}let a=[];if(await Promise.all(i.map(async n=>{try{(await n.listPrompts()).some(t=>t.name===e)&&a.push(n.serverName)}catch(e){t.json||console.error(`Failed to list prompts from ${n.serverName}: ${w(e)}`)}})),a.length===0)throw Error(`Prompt "${e}" not found on any connected server`);if(a.length>1)throw Error(`Prompt "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=r.getClient(a[0]);if(!o)throw Error(`Internal error: Server "${a[0]}" not connected`);let s=await o.getPrompt(e,n);if(t.json)console.log(JSON.stringify(s,null,2));else for(let e of s.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}})}catch(e){console.error(`Error executing get-prompt: ${w(e)}`),process.exit(1)}});var te=`{
7
+ Next steps:`);for(let e of p)console.log(` • ${e}`);console.log(``)}d.length>0&&console.error(`\nTools/skills not found: ${d.join(`, `)}`),l.length===0&&u.length===0&&(console.error(`No tools or skills found`),process.exit(1))}})}catch(e){console.error(`Error executing describe-tools: ${S(e)}`),process.exit(1)}});function w(e){return e instanceof Error?e.message:String(e)}const ee=new c.Command(`get-prompt`).description(`Get a prompt by name from a connected MCP server`).argument(`<promptName>`,`Prompt name to fetch`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-s, --server <name>`,`Server name (required if prompt exists on multiple servers)`).option(`-a, --args <json>`,`Prompt arguments as JSON string`,`{}`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{throw Error(`Invalid JSON in --args`)}await x(t,async({clientManager:r})=>{let i=r.getAllClients();if(t.server){let i=r.getClient(t.server);if(!i)throw Error(`Server "${t.server}" not found`);let a=await i.getPrompt(e,n);if(t.json)console.log(JSON.stringify(a,null,2));else for(let e of a.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}return}let a=[];if(await Promise.all(i.map(async n=>{try{(await n.listPrompts()).some(t=>t.name===e)&&a.push(n.serverName)}catch(e){t.json||console.error(`Failed to list prompts from ${n.serverName}: ${w(e)}`)}})),a.length===0)throw Error(`Prompt "${e}" not found on any connected server`);if(a.length>1)throw Error(`Prompt "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=r.getClient(a[0]);if(!o)throw Error(`Internal error: Server "${a[0]}" not connected`);let s=await o.getPrompt(e,n);if(t.json)console.log(JSON.stringify(s,null,2));else for(let e of s.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}})}catch(e){console.error(`Error executing get-prompt: ${w(e)}`),process.exit(1)}});var te=`{
8
8
  "_comment": "MCP Server Configuration - Use \${VAR_NAME} syntax for environment variable interpolation",
9
9
  "_instructions": "config.instruction: Server's default instruction | instruction: User override (takes precedence)",
10
10
  "mcpServers": {
@@ -138,9 +138,9 @@ mcpServers:
138
138
  # # omitToolDescription: true
139
139
  # # instruction: Optional user override
140
140
  {% endif %}
141
- `;function T(e=``){console.log(e)}function E(e,t){console.error(t?`${e} ${t}`:e)}const D={info:e=>T(e),error:(e,t)=>E(e,t)},O={info:e=>T(e),warning:e=>T(`Warning: ${e}`),error:e=>E(e),success:e=>T(e),newline:()=>T(),header:e=>T(e),item:e=>T(`- ${e}`),indent:e=>T(` ${e}`)},re=new l.Command(`init`).description(`Initialize MCP configuration file`).option(`-o, --output <path>`,`Output file path`,`mcp-config.yaml`).option(`--json`,`Generate JSON config instead of YAML`,!1).option(`-f, --force`,`Overwrite existing config file`,!1).option(`--mcp-servers <json>`,`JSON string of MCP servers to add to config (optional)`).action(async e=>{try{let t=(0,n.resolve)(e.output),r=!e.json&&(t.endsWith(`.yaml`)||t.endsWith(`.yml`)),a;if(r){let t=new c.Liquid,n=null;if(e.mcpServers)try{let t=JSON.parse(e.mcpServers);n=Object.entries(t).map(([e,t])=>({name:e,command:t.command,args:t.args}))}catch(e){D.error(`Failed to parse --mcp-servers JSON:`,e instanceof Error?e.message:String(e)),process.exit(1)}a=await t.parseAndRender(ne,{mcpServers:n})}else a=te;try{await(0,i.writeFile)(t,a,{encoding:`utf-8`,flag:e.force?`w`:`wx`})}catch(e){throw e&&typeof e==`object`&&`code`in e&&e.code===`EEXIST`&&(D.error(`Config file already exists: ${t}`),D.info(`Use --force to overwrite`),process.exit(1)),e}D.info(`MCP configuration file created: ${t}`),D.info(`Next steps:`),D.info(`1. Edit the configuration file to add your MCP servers`),D.info(`2. Run: po-mcp-proxy mcp-serve --config ${t}`)}catch(e){D.error(`Error executing init:`,e instanceof Error?e.message:String(e)),process.exit(1)}});function k(e){return e instanceof Error?e.message:String(e)}const ie=new l.Command(`list-prompts`).description(`List all available prompts from connected MCP servers`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await x(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={};if(await Promise.all(n.map(async t=>{try{r[t.serverName]=await t.listPrompts()}catch(n){r[t.serverName]=[],e.json||console.error(`Failed to list prompts from ${t.serverName}: ${k(n)}`)}})),e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No prompts available`);else for(let e of t)if(console.log(` - ${e.name}: ${e.description||`No description`}`),e.arguments&&e.arguments.length>0){let t=e.arguments.map(e=>`${e.name}${e.required?` (required)`:``}`).join(`, `);console.log(` args: ${t}`)}})}catch(e){console.error(`Error executing list-prompts: ${k(e)}`),process.exit(1)}});function A(e){return e instanceof Error?e.message:String(e)}const ae=new l.Command(`list-resources`).description(`List all available resources from connected MCP servers`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await x(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={},i=await Promise.all(n.map(async e=>{try{let t=await e.listResources();return{serverName:e.serverName,resources:t,error:null}}catch(t){return{serverName:e.serverName,resources:[],error:t}}}));for(let{serverName:t,resources:n,error:a}of i)a&&!e.json&&console.error(`Failed to list resources from ${t}: ${A(a)}`),r[t]=n;if(e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No resources available`);else for(let e of t){let t=e.name?`${e.name} (${e.uri})`:e.uri;console.log(` - ${t}${e.description?`: ${e.description}`:``}`)}})}catch(e){console.error(`Error executing list-resources: ${A(e)}`),process.exit(1)}});function oe(e){return e instanceof Error?e.message:String(e)}function se(e){for(let t of e.servers)if(console.log(`\n${t.server}:`),t.capabilities&&t.capabilities.length>0&&console.log(` capabilities: ${t.capabilities.join(`, `)}`),t.summary&&console.log(` summary: ${t.summary}`),t.tools.length===0)console.log(` no tools`);else for(let e of t.tools){let t=e.capabilities&&e.capabilities.length>0?` [${e.capabilities.join(`, `)}]`:``;console.log(` - ${e.name}${t}`),e.description&&console.log(` ${e.description}`)}}const ce=new l.Command(`search-tools`).description(`Search proxied MCP tools by capability or server`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Filter by server name`).option(`--capability <name>`,`Filter by capability tag, summary, tool name, or description`).option(`--definitions-cache <path>`,`Path to definitions cache file`).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{await x(t,async({container:n,config:r,clientManager:i,configFilePaths:a})=>{i.registerServerConfigs(r.mcpServers);let o=t.definitionsCache||e.j.getDefaultCachePath(a),s;try{s=await e.j.readFromFile(o)}catch{s=void 0}let c=n.createDefinitionsCacheService(i,void 0,{cacheData:s}),l=(await n.createSearchListToolsTool(i,c).execute({capability:t.capability,serverName:t.server})).content.find(e=>e.type===`text`),u=l?.type===`text`?JSON.parse(l.text):{servers:[]};if(t.json)console.log(JSON.stringify(u,null,2));else{if(!u.servers||u.servers.length===0)throw Error(`No tools matched the requested filters`);se(u)}})}catch(e){console.error(`Error executing search-tools: ${oe(e)}`),process.exit(1)}}),j=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],M=`/mcp`,N=`localhost`,P=`stdio`,F=`http`,I=`stdio-http`,L=`mcp-proxy-http`,R=`service`;function le(){return e.ut()}const z=`mcp-proxy-stdio-http-bridge`,B=`stdio-http-managed`,V=`manual`,H=`MCP_PROXY_IDLE_SHUTDOWN_MINUTES`;function U(){return le()}function W(e){return e instanceof Error?e.message:String(e)}function ue(e){let t=process.env[H],n=e??(t?Number.parseFloat(t):void 0);return n===void 0||!Number.isFinite(n)||n<=0?0:Math.round(n*6e4)}function G(e){return e===P||e===F||e===I}function de(e){return e===`meta`||e===`flat`||e===`search`||e===`group`}async function K(e){try{return await(0,i.access)(e,t.constants.F_OK),!0}catch{return!1}}async function fe(){try{let e=process.env.PROJECT_PATH;if(e)for(let t of j){let r=(0,n.resolve)(e,t);if(await K(r))return r}let t=process.cwd();for(let e=0;e<=3;e++){for(let e of j){let r=(0,n.join)(t,e);if(await K(r))return r}let e=(0,n.dirname)(t);if(e===t)break;t=e}return null}catch(e){throw Error(`Failed to discover MCP config file: ${W(e)}`)}}function pe(e){try{let n=(0,t.readFileSync)(e,`utf-8`),r=(e.endsWith(`.yaml`)||e.endsWith(`.yml`)?o.load(n):JSON.parse(n))?.proxy;if(!r||typeof r!=`object`)return{};let i=r;return{type:typeof i.type==`string`?i.type:void 0,port:typeof i.port==`number`&&Number.isInteger(i.port)&&i.port>0?i.port:void 0,host:typeof i.host==`string`?i.host:void 0,keepAlive:typeof i.keepAlive==`boolean`?i.keepAlive:void 0}}catch{return{}}}function me(e){let t={};for(let n of e){let e=pe(n);e.type!==void 0&&(t.type=e.type),e.port!==void 0&&(t.port=e.port),e.host!==void 0&&(t.host=e.host),e.keepAlive!==void 0&&(t.keepAlive=e.keepAlive)}return t}async function he(t,n){let r=e.o();if(t.id)return t.id;if(n.length>0)try{let i=await r.createConfigFetcherService({configSources:e.L(n),useCache:t.cache!==!1}).fetchConfiguration(t.cache===!1);if(i.id)return i.id}catch(e){throw Error(`Failed to resolve server ID from config '${n.join(`, `)}': ${W(e)}`)}return e.N()}function ge(e){if(!G(e))throw Error(`Unknown transport type: '${e}'. Valid options: ${P}, ${F}, ${I}`);return e}function _e(e){if(!de(e))throw Error(`Unknown proxy mode: '${String(e)}'. Valid options: meta, flat, search, group`)}function ve(e){return e===B?B:V}function q(e,t,n){let r=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0;return{mode:t,port:e.port??(Number.isFinite(r)?r:void 0)??n?.port,host:e.host??process.env.MCP_HOST??n?.host??N}}function J(){let e=(e,t)=>{t===void 0?console.error(e):console.error(e,t)};return{trace:e,debug:e,info:e,warn:e,error:e}}function ye(e,t,n){return{configFilePath:t.length>0?t:void 0,noCache:e.cache===!1,serverId:n,definitionsCachePath:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode}}function be(e,t,n,r){let i=W(r);return e===P?`Failed to start MCP server with transport '${e}': ${i}`:`Failed to start MCP server with transport '${e}' on ${n===void 0?`${t} (dynamic port)`:`${t}:${n}`}: ${i}`}function xe(e,t,n,r,i,a=V){return{serverId:e,host:t.host??N,port:n,transport:`http`,shutdownToken:r,startedAt:(/* @__PURE__ */ new Date()).toISOString(),pid:process.pid,configPath:i,runtimeLifecycle:a}}function Se(){return new s.PortRegistryService(process.env.PORT_REGISTRY_PATH)}function Y(){return process.env.NODE_ENV??`development`}async function Ce(e,t,n,r,i,a,o=n===void 0?s.DEFAULT_PORT_RANGE:{min:n,max:n}){let c=Se(),l=await c.reservePort({repositoryPath:U(),serviceName:e,serviceType:R,environment:Y(),pid:process.pid,host:t,preferredPort:n,portRange:o,force:!0,metadata:{transport:i,serverId:r,...a?{configPath:a}:{}}});if(!l.success||!l.record){let e=n===void 0?`dynamic port`:`port ${n}`;throw Error(l.error||`Failed to reserve ${e} in port registry`)}let u=!1;return{port:l.record.port,release:async()=>{if(u)return;u=!0;let t=await c.releasePort({repositoryPath:U(),serviceName:e,serviceType:R,pid:process.pid,environment:Y(),force:!0});if(!t.success&&t.error&&!t.error.includes(`No matching registry entry`))throw Error(t.error||`Failed to release port for ${e}`)}}}async function we(e){e&&await e.release()}function Te(e,t,n,r,i){return{serverId:e,shutdownToken:t,onShutdownRequested:n,runtimeLifecycle:r,idleShutdownMs:i}}async function X(e,t){try{await e.remove(t)}catch(e){throw Error(`Failed to remove runtime state for '${t}': ${W(e)}`)}}async function Ee(e,t){try{await e.write(t)}catch(e){throw Error(`Failed to persist runtime state for '${t.serverId}': ${W(e)}`)}}async function De(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop owned HTTP transport '${n}': ${W(e)}`)}}finally{await r?.release({kill:!1}),await X(t,n)}}async function Oe(e,t,n){await n?.release({kill:!1}),await X(e,t)}async function ke(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop HTTP transport during cleanup for '${n}': ${W(e)}`)}}finally{await r?.release({kill:!1}),await X(t,n)}}async function Z(e,t,n={}){try{await e.start()}catch(e){throw Error(`Failed to start transport handler: ${W(e)}`)}let r=!1,i=async n=>{if(!r){r=!0,console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),t&&await t(),process.exit(0)}catch(e){console.error(`Failed to gracefully stop transport during ${n}: ${W(e)}`),process.exit(1)}}};process.on(`SIGINT`,async()=>await i(`SIGINT`)),process.on(`SIGTERM`,async()=>await i(`SIGTERM`)),n.shutdownOnStdinClose&&(process.stdin.on(`end`,async()=>await i(`stdin end`)),process.stdin.on(`close`,async()=>await i(`stdin close`)))}async function Ae(t,n,i,o){e.M();let c=i[0],l=await e.l(t),u=new e.T,d=(0,r.randomUUID)(),f=t.serverId??e.N(),p=ve(process.env.MCP_PROXY_RUNTIME_LIFECYCLE),m=n.port,h=m===void 0?s.DEFAULT_PORT_RANGE:{min:m,max:m},g=await Ce(L,n.host??N,m,f,F,c,h),_=g.port,v={...n,port:_},y=await(0,a.createProcessLease)({repositoryPath:U(),serviceName:`mcp-proxy-http`,serviceType:`service`,environment:Y(),host:v.host??N,port:_,command:process.argv[1],args:process.argv.slice(2),...e.v()?{processGroupId:process.pid,terminationMode:`process-group`}:{terminationMode:`direct`},metadata:{transport:F,serverId:f,runtimeLifecycle:p,...c?{configPath:c}:{}}}),b=async()=>{await we(g??null),b=async()=>void 0},x=xe(f,v,_,d,c,p),S,C=!1,w=async()=>{if(!C){C=!0;try{await De(S,u,x.serverId,y),await b(),await l.dispose(),process.exit(0)}catch(e){throw Error(`Failed to stop HTTP runtime '${x.serverId}' from admin shutdown: ${W(e)}`)}}};try{let t=Te(x.serverId,d,w,p,o);S=new e.S(()=>e.r(l),v,t)}catch(e){throw await b(),await y.release({kill:!1}),await l.dispose(),Error(`Failed to create HTTP runtime server: ${W(e)}`)}try{await Z(S,async()=>{await b(),await l.dispose(),await Oe(u,x.serverId,y)}),await Ee(u,x)}catch(e){throw await b(),await l.dispose(),await ke(S,u,x.serverId,y),Error(`Failed to start HTTP runtime '${x.serverId}': ${W(e)}`)}console.error(`Runtime state: http://${x.host}:${x.port} (${x.serverId})`)}async function je(t){let n;try{n=await e.n(t),await Z(new e.d(n,J()),async()=>{await n?.dispose?.()},{shutdownOnStdinClose:!0})}catch(e){throw await n?.dispose?.(),Error(`Failed to start stdio transport: ${W(e)}`)}}async function Me(t){if(t)try{return(await new e.T().read(t))?.runtimeLifecycle}catch{return}}function Ne(t){if(!t)return e.g;let n=Number.parseInt(t,10);return Number.isInteger(n)&&n>0?n:e.g}function Q(e,t){let i=a.ProcessRegistryService.resolveRegistryPath(process.env.PROCESS_REGISTRY_PATH),o=(0,r.createHash)(`sha1`).update(`${(0,a.normalizeRepositoryPath)(e)}|${t}`).digest(`hex`);return(0,n.join)((0,n.dirname)(i),`mcp-proxy-runtime-${o.slice(0,16)}.lock`)}async function $(e,t,n){if(e.port!==void 0)return{endpoint:new URL(`http://${e.host??N}:${e.port}${M}`),runtimeLifecycle:V};let r=U(),i=Ne(t.timeoutMs)+1e4;return await(0,a.withFileLock)(Q(r,L),async()=>Pe(r,e,t,n),{staleAfterMs:i,retryDelayMs:250,maxRetries:Math.ceil(i/250)})}async function Pe(t,n,r,i){let a=await e._(t);if(a){let e=n.host??a.host,t=a.serverId===`unknown`?void 0:a.serverId;return{endpoint:new URL(`http://${e}:${a.port}${M}`),runtimeServerId:t,runtimeLifecycle:a.runtimeLifecycle??await Me(t)??V}}let o=await e.y({host:n.host??N,config:i,cache:r.cache,definitionsCache:r.definitionsCache,clearDefinitionsCache:r.clearDefinitionsCache,proxyMode:r.proxyMode,runtimeLifecycle:B,idleShutdownMinutes:r.idleShutdownMinutes});return{endpoint:new URL(`http://${o.host}:${o.port}${M}`),runtimeServerId:o.serverId,runtimeLifecycle:o.runtimeLifecycle??V}}async function Fe(e,t,n){let{endpoint:r}=await $(e,t,n);return r}function Ie(e){return`runtime:${e}`}async function Le(e){if(e.runtimeLifecycle===B&&e.runtimeServerId)return await(0,a.createProcessLease)({repositoryPath:U(),serviceName:`mcp-proxy-stdio-http-bridge:${(0,r.randomUUID)()}`,serviceType:`tool`,environment:Y(),pid:process.pid,command:process.argv[1],args:process.argv.slice(2),tags:[z,Ie(e.runtimeServerId)],metadata:{transport:I,runtimeServerId:e.runtimeServerId,runtimeLifecycle:e.runtimeLifecycle,endpoint:e.endpoint.toString()},force:!1})}function Re(e){return e.pid===process.pid}async function ze(e){return await new a.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH).listProcesses({repositoryPath:U(),serviceType:`tool`,tags:[z,Ie(e)],environment:Y(),liveOnly:!0})}async function Be(e){return(await ze(e)).filter(e=>!Re(e)).length>0?!1:(await new Promise(e=>setTimeout(e,500)),(await ze(e)).filter(e=>!Re(e)).length===0)}async function Ve(t){if(t.runtimeLifecycle!==B||!t.runtimeServerId)return;let n=t.runtimeServerId,r=Q(U(),L);try{await(0,a.withFileLock)(r,async()=>{await Be(n)&&await new e.C().stop({serverId:n,force:!0})})}catch(e){console.error(`Failed to stop managed stdio-http runtime; leaving it alive: ${W(e)}`)}}async function He(t,n,r,i){let a=n.autoDisconnect?!0:i?.keepAlive!==void 0&&!i.keepAlive,o,s;try{o=await $(t,n,r),s=await Le(o);let{endpoint:i}=o;await Z(new e.u({endpoint:i,resolveEndpoint:async()=>await Fe(t,n,r)},J()),async()=>{try{await s?.release({kill:!1,releasePort:!1})}catch(e){console.error(`Failed to release stdio-http bridge lease; leaving runtime alive: ${W(e)}`);return}a&&o&&await Ve(o)},{shutdownOnStdinClose:!0})}catch(e){try{await s?.release({kill:!1,releasePort:!1})}catch(t){throw Error(`Failed to start stdio-http transport: ${W(e)}; also failed to release bridge lease: ${W(t)}`)}throw Error(`Failed to start stdio-http transport: ${W(e)}`)}}async function Ue(t,n,r,i,a){try{if(t===P){await je(i);return}if(t===F){await Ae(i,q(n,e.t.HTTP,a),r,ue(n.idleShutdownMinutes));return}await He(q(n,e.t.HTTP,a),n,r,a)}catch(e){throw Error(`Failed to start transport '${t}': ${W(e)}`)}}async function We(t,n){try{let r=await e.y({id:t.id,host:t.host??N,port:t.port,config:n,cache:t.cache,definitionsCache:t.definitionsCache,clearDefinitionsCache:t.clearDefinitionsCache,proxyMode:t.proxyMode,timeoutMs:t.timeoutMs,idleShutdownMinutes:t.idleShutdownMinutes});e.x(r)}catch(e){console.error(`Failed to prestart HTTP runtime '${t.id||`generated-server-id`}': ${W(e)}`),process.exit(1)}}const Ge=new l.Command(`mcp-serve`).description(`Start MCP server with specified transport or prestart the HTTP runtime in the background`).option(`-t, --type <type>`,`Transport type: ${P}, ${F}, or ${I}`).option(`-p, --port <port>`,`Port to listen on (http) or backend port for stdio-http`,e=>Number.parseInt(e,10)).option(`--host <host>`,`Host to bind to (http) or backend host for stdio-http`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`--no-cache`,`Disable configuration caching, always reload from config file`).option(`--definitions-cache <path>`,`Path to prefetched tool/prompt/skill definitions cache file`).option(`--clear-definitions-cache`,`Delete definitions cache before startup`,!1).option(`--proxy-mode <mode>`,`How mcp-proxy exposes downstream tools: meta, flat, search, or group`,`meta`).option(`--id <id>`,`Unique server identifier (overrides config file id, auto-generated if not provided)`).option(`--auto-disconnect`,`Stop the managed HTTP runtime when the last stdio-http bridge exits (default: keep runtime alive for reuse)`,!1).option(`--idle-shutdown-minutes <minutes>`,`Stop the HTTP runtime after N minutes with no MCP session and no request (0 disables; overrides ${H})`,e=>Number.parseFloat(e)).option(`--prestart-http`,`Prestart the HTTP runtime in the background and exit after it becomes healthy`,!1).option(`--timeout-ms <ms>`,`How long to wait for the HTTP runtime to become healthy`,String(e.g)).action(async t=>{try{let n=e.I(t.config),r=n.length>0?null:await fe(),i=r?[r]:n;if(t.prestartHttp){await We(t,i);return}let a=me(i),o=ge((t.type??a.type??P).toLowerCase());_e(t.proxyMode),await Ue(o,t,i,ye(t,i,await he(t,i)),a)}catch(e){let n=(t.type??P).toLowerCase(),r=G(n)?n:P,i=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0,a=t.port??(Number.isFinite(i)?i:void 0);console.error(be(r,t.host??N,a,e)),process.exit(1)}}),Ke=new l.Command(`prefetch`).description(`Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-p, --parallel`,`Run prefetch commands in parallel`,!1).option(`-d, --dry-run`,`Show what would be prefetched without executing`,!1).option(`-f, --filter <type>`,`Filter by package manager type: npx, pnpx, uvx, or uv`).option(`--definitions-out <path>`,`Write discovered definitions to a JSON or YAML cache file`).option(`--skip-packages`,`Skip package prefetch and only build definitions cache`,!1).option(`--clear-definitions-cache`,`Delete the definitions cache file before continuing`,!1).action(async t=>{try{let n=e.o(),r=e.I(t.config),i=r.length>0?null:e.P(),a=i?[i]:r;a.length===0&&(O.error(`No MCP configuration file found.`),O.info(`Use --config <path> to specify a config file, or run "po-mcp-proxy init" to create one.`),process.exit(1)),O.info(`Loading configuration from: ${a.join(`, `)}`);let o=await n.createConfigFetcherService({configSources:e.L(a),useCache:!1}).fetchConfiguration(!0),s=o.id||e.N(),c=e.j.generateConfigHash(o),l=t.definitionsOut||e.j.getDefaultCachePath(a),u=n.createPrefetchService({mcpConfig:o,filter:t.filter,parallel:t.parallel}),d=u.extractPackages(),f=!t.skipPackages,p=!!t.definitionsOut;if(t.clearDefinitionsCache&&(t.dryRun?O.info(`Would clear definitions cache: ${l}`):(await e.j.clearFile(l),O.success(`Cleared definitions cache: ${l}`))),f){if(d.length===0)O.warning(`No packages found to prefetch.`),O.info(`Prefetch supports: npx, pnpx, uvx, and uv run commands`);else{O.info(`Found ${d.length} package(s) to prefetch:`);for(let e of d)O.item(`${e.serverName}: ${e.packageManager} ${e.packageName}`)}}if(!f&&!p){O.warning(`Nothing to do. Use package prefetch or provide --definitions-out.`);return}if(t.dryRun){if(f&&d.length>0){O.newline(),O.header(`Dry run mode - commands that would be executed:`);for(let e of d)O.indent(e.fullCommand.join(` `))}p&&(O.newline(),O.info(`Would write definitions cache to: ${l}`));return}let m=!1;if(f&&d.length>0){O.newline(),O.info(`Prefetching packages...`);let e=await u.prefetch();if(O.newline(),e.failed===0?O.success(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`):O.warning(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`),e.failed>0){m=!0,O.newline(),O.error(`Failed packages:`);for(let t of e.results.filter(e=>!e.success))O.item(`${t.package.serverName} (${t.package.packageName}): ${t.output.trim()}`)}}if(p){O.newline(),O.info(`Collecting definitions cache...`);let t=n.createClientManagerService(),r=o.skills?.paths||[],i=r.length>0?n.createSkillService(process.cwd(),r):void 0,u=n.createDefinitionsCacheService(t,i);await Promise.all(Object.entries(o.mcpServers).map(async([e,n])=>{try{await t.connectToServer(e,n),O.item(`Connected for definitions: ${e}`)}catch(t){O.warning(`Failed to connect for definitions: ${e} (${t instanceof Error?t.message:String(t)})`)}}));let d=await u.collectForCache({configPath:a[0],configHash:c,oneMcpVersion:e.h,serverId:s});await e.j.writeToFile(l,d),O.success(`Definitions cache written: ${l} (${Object.keys(d.servers).length} servers, ${d.skills.length} skills)`),d.failures.length>0&&O.warning(`Definitions cache completed with ${d.failures.length} server failure(s)`),await t.disconnectAll()}m&&process.exit(1)}catch(e){O.error(`Error executing prefetch: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});function qe(e){return e instanceof Error?e.message:String(e)}const Je=new l.Command(`read-resource`).description(`Read a resource by URI from a connected MCP server`).argument(`<uri>`,`Resource URI to read`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Server name (required if resource exists on multiple servers)`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await x(t,async({clientManager:n})=>{let r=n.getAllClients();if(t.server){let r=n.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Reading ${e} from ${t.server}...`);let i=await r.readResource(e);if(t.json)console.log(JSON.stringify(i,null,2));else for(let e of i.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2));return}let i=await Promise.all(r.map(async t=>{try{let n=(await t.listResources()).some(t=>t.uri===e);return{serverName:t.serverName,hasResource:n,error:null}}catch(e){return{serverName:t.serverName,hasResource:!1,error:e}}})),a=[];for(let{serverName:e,hasResource:t,error:n}of i)n?console.error(`Failed to list resources from ${e}: ${qe(n)}`):t&&a.push(e);if(a.length===0)throw Error(`Resource "${e}" not found on any connected server`);if(a.length>1)throw Error(`Resource "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=a[0],s=n.getClient(o);if(!s)throw Error(`Internal error: Server "${o}" not connected`);t.json||console.error(`Reading ${e} from ${o}...`);let c=await s.readResource(e);if(t.json)console.log(JSON.stringify(c,null,2));else for(let e of c.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2))})}catch(e){console.error(`Error executing read-resource: ${qe(e)}`),process.exit(1)}});function Ye(e){return e instanceof Error?e.message:String(e)}function Xe(e){console.log(`Stopped mcp-proxy server '${e.serverId}'.`),console.log(`Endpoint: http://${e.host}:${e.port}`),console.log(`Result: ${e.message}`)}const Ze=new l.Command(`stop`).description(`Stop a running HTTP mcp-proxy server`).option(`--id <id>`,`Target server ID from the runtime registry`).option(`--host <host>`,`Target runtime host`).option(`--port <port>`,`Target runtime port`,e=>Number.parseInt(e,10)).option(`-c, --config <path>`,`Reserved for future config-based targeting support`).option(`--token <token>`,`Override the persisted shutdown token`).option(`--force`,`Skip server ID verification against the /health response`,!1).option(`-j, --json`,`Output as JSON`,!1).option(`--timeout <ms>`,`Maximum time to wait for shutdown completion`,e=>Number.parseInt(e,10),5e3).action(async t=>{try{t.config&&console.error(`Warning: --config is not used yet; runtime resolution uses the persisted registry.`);let n=await e.o().createStopServerService().stop({serverId:t.id,host:t.host,port:t.port,token:t.token,force:t.force,timeoutMs:t.timeout});if(t.json){console.log(JSON.stringify(n,null,2));return}Xe(n)}catch(e){let n=`Error executing stop: ${Ye(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function Qe(e){return e instanceof Error?e.message:String(e)}const $e=new l.Command(`use-tool`).description(`Execute an MCP tool with arguments`).argument(`<toolName>`,`Tool name to execute`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.F).option(`-s, --server <name>`,`Server name (required if tool exists on multiple servers)`).option(`-a, --args <json>`,`Tool arguments as JSON string`,`{}`).option(`-t, --timeout <ms>`,`Request timeout in milliseconds for tool execution (default: 60000)`,Number.parseInt).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{console.error(`Error: Invalid JSON in --args`),process.exit(1)}await x(t,async({container:r,config:i,clientManager:a})=>{let o=a.getAllClients();if(t.server){let r=a.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Executing ${e} on ${t.server}...`);let i=t.timeout?{timeout:t.timeout}:void 0,o=await r.callTool(e,n,i);if(t.json)console.log(JSON.stringify(o,null,2));else{if(console.log(`
141
+ `;function T(e=``){console.log(e)}function E(e,t){console.error(t?`${e} ${t}`:e)}const D={info:e=>T(e),error:(e,t)=>E(e,t)},O={info:e=>T(e),warning:e=>T(`Warning: ${e}`),error:e=>E(e),success:e=>T(e),newline:()=>T(),header:e=>T(e),item:e=>T(`- ${e}`),indent:e=>T(` ${e}`)},re=new c.Command(`init`).description(`Initialize MCP configuration file`).option(`-o, --output <path>`,`Output file path`,`mcp-config.yaml`).option(`--json`,`Generate JSON config instead of YAML`,!1).option(`-f, --force`,`Overwrite existing config file`,!1).option(`--mcp-servers <json>`,`JSON string of MCP servers to add to config (optional)`).action(async e=>{try{let r=(0,n.resolve)(e.output),i=!e.json&&(r.endsWith(`.yaml`)||r.endsWith(`.yml`)),a;if(i){let t=new s.Liquid,n=null;if(e.mcpServers)try{let t=JSON.parse(e.mcpServers);n=Object.entries(t).map(([e,t])=>({name:e,command:t.command,args:t.args}))}catch(e){D.error(`Failed to parse --mcp-servers JSON:`,e instanceof Error?e.message:String(e)),process.exit(1)}a=await t.parseAndRender(ne,{mcpServers:n})}else a=te;try{await(0,t.writeFile)(r,a,{encoding:`utf-8`,flag:e.force?`w`:`wx`})}catch(e){throw e&&typeof e==`object`&&`code`in e&&e.code===`EEXIST`&&(D.error(`Config file already exists: ${r}`),D.info(`Use --force to overwrite`),process.exit(1)),e}D.info(`MCP configuration file created: ${r}`),D.info(`Next steps:`),D.info(`1. Edit the configuration file to add your MCP servers`),D.info(`2. Run: po-mcp-proxy mcp-serve --config ${r}`)}catch(e){D.error(`Error executing init:`,e instanceof Error?e.message:String(e)),process.exit(1)}});function k(e){return e instanceof Error?e.message:String(e)}const ie=new c.Command(`list-prompts`).description(`List all available prompts from connected MCP servers`).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=>{try{await x(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={};if(await Promise.all(n.map(async t=>{try{r[t.serverName]=await t.listPrompts()}catch(n){r[t.serverName]=[],e.json||console.error(`Failed to list prompts from ${t.serverName}: ${k(n)}`)}})),e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No prompts available`);else for(let e of t)if(console.log(` - ${e.name}: ${e.description||`No description`}`),e.arguments&&e.arguments.length>0){let t=e.arguments.map(e=>`${e.name}${e.required?` (required)`:``}`).join(`, `);console.log(` args: ${t}`)}})}catch(e){console.error(`Error executing list-prompts: ${k(e)}`),process.exit(1)}});function A(e){return e instanceof Error?e.message:String(e)}const ae=new c.Command(`list-resources`).description(`List all available resources from connected MCP servers`).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=>{try{await x(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={},i=await Promise.all(n.map(async e=>{try{let t=await e.listResources();return{serverName:e.serverName,resources:t,error:null}}catch(t){return{serverName:e.serverName,resources:[],error:t}}}));for(let{serverName:t,resources:n,error:a}of i)a&&!e.json&&console.error(`Failed to list resources from ${t}: ${A(a)}`),r[t]=n;if(e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No resources available`);else for(let e of t){let t=e.name?`${e.name} (${e.uri})`:e.uri;console.log(` - ${t}${e.description?`: ${e.description}`:``}`)}})}catch(e){console.error(`Error executing list-resources: ${A(e)}`),process.exit(1)}});function oe(e){return e instanceof Error?e.message:String(e)}function se(e){for(let t of e.servers)if(console.log(`\n${t.server}:`),t.capabilities&&t.capabilities.length>0&&console.log(` capabilities: ${t.capabilities.join(`, `)}`),t.summary&&console.log(` summary: ${t.summary}`),t.tools.length===0)console.log(` no tools`);else for(let e of t.tools){let t=e.capabilities&&e.capabilities.length>0?` [${e.capabilities.join(`, `)}]`:``;console.log(` - ${e.name}${t}`),e.description&&console.log(` ${e.description}`)}}const ce=new c.Command(`search-tools`).description(`Search proxied MCP tools by capability or server`).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(`--capability <name>`,`Filter by capability tag, summary, tool name, or description`).option(`--definitions-cache <path>`,`Path to definitions cache file`).option(`-j, --json`,`Output as JSON`,!1).action(async t=>{try{await x(t,async({container:n,config:r,clientManager:i,configFilePaths:a})=>{i.registerServerConfigs(r.mcpServers);let o=t.definitionsCache||e.j.getDefaultCachePath(a),s;try{s=await e.j.readFromFile(o)}catch{s=void 0}let c=n.createDefinitionsCacheService(i,void 0,{cacheData:s}),l=(await n.createSearchListToolsTool(i,c).execute({capability:t.capability,serverName:t.server})).content.find(e=>e.type===`text`),u=l?.type===`text`?JSON.parse(l.text):{servers:[]};if(t.json)console.log(JSON.stringify(u,null,2));else{if(!u.servers||u.servers.length===0)throw Error(`No tools matched the requested filters`);se(u)}})}catch(e){console.error(`Error executing search-tools: ${oe(e)}`),process.exit(1)}}),j=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],M=`/mcp`,N=`localhost`,P=`stdio`,F=`http`,I=`stdio-http`,L=`mcp-proxy-http`,R=`service`;async function le(){return e.pt()}const z=`mcp-proxy-stdio-http-bridge`,B=`stdio-http-managed`,V=`manual`,H=`MCP_PROXY_IDLE_SHUTDOWN_MINUTES`;async function U(){return le()}function W(e){return e instanceof Error?e.message:String(e)}function ue(e){let t=process.env[H],n=e??(t?Number.parseFloat(t):void 0);return n===void 0||!Number.isFinite(n)||n<=0?0:Math.round(n*6e4)}function G(e){return e===P||e===F||e===I}function de(e){return e===`meta`||e===`flat`||e===`search`||e===`group`}async function K(e){try{return await(0,t.access)(e,l.constants.F_OK),!0}catch{return!1}}async function fe(){try{let e=process.env.PROJECT_PATH;if(e)for(let t of j){let r=(0,n.resolve)(e,t);if(await K(r))return r}let t=process.cwd();for(let e=0;e<=3;e++){for(let e of j){let r=(0,n.join)(t,e);if(await K(r))return r}let e=(0,n.dirname)(t);if(e===t)break;t=e}return null}catch(e){throw Error(`Failed to discover MCP config file: ${W(e)}`)}}async function pe(e){try{let n=await(0,t.readFile)(e,`utf-8`),r=(e.endsWith(`.yaml`)||e.endsWith(`.yml`)?a.load(n):JSON.parse(n))?.proxy;if(!r||typeof r!=`object`)return{};let i=r;return{type:typeof i.type==`string`?i.type:void 0,port:typeof i.port==`number`&&Number.isInteger(i.port)&&i.port>0?i.port:void 0,host:typeof i.host==`string`?i.host:void 0,keepAlive:typeof i.keepAlive==`boolean`?i.keepAlive:void 0}}catch{return{}}}async function me(e){let t={};for(let n of e){let e=await pe(n);e.type!==void 0&&(t.type=e.type),e.port!==void 0&&(t.port=e.port),e.host!==void 0&&(t.host=e.host),e.keepAlive!==void 0&&(t.keepAlive=e.keepAlive)}return t}async function he(t,n){let r=e.o();if(t.id)return t.id;if(n.length>0)try{let i=await r.createConfigFetcherService({configSources:e.z(n),useCache:t.cache!==!1}).fetchConfiguration(t.cache===!1);if(i.id)return i.id}catch(e){throw Error(`Failed to resolve server ID from config '${n.join(`, `)}': ${W(e)}`)}return e.F()}function ge(e){if(!G(e))throw Error(`Unknown transport type: '${e}'. Valid options: ${P}, ${F}, ${I}`);return e}function _e(e){if(!de(e))throw Error(`Unknown proxy mode: '${String(e)}'. Valid options: meta, flat, search, group`)}function ve(e){return e===B?B:V}function q(e,t,n){let r=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0;return{mode:t,port:e.port??(Number.isFinite(r)?r:void 0)??n?.port,host:e.host??process.env.MCP_HOST??n?.host??N}}function J(){let e=(e,t)=>{t===void 0?console.error(e):console.error(e,t)};return{trace:e,debug:e,info:e,warn:e,error:e}}function ye(e,t,n){return{configFilePath:t.length>0?t:void 0,noCache:e.cache===!1,serverId:n,definitionsCachePath:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode}}function be(e,t,n,r){let i=W(r);return e===P?`Failed to start MCP server with transport '${e}': ${i}`:`Failed to start MCP server with transport '${e}' on ${n===void 0?`${t} (dynamic port)`:`${t}:${n}`}: ${i}`}function xe(e,t,n,r,i,a=V){return{serverId:e,host:t.host??N,port:n,transport:`http`,shutdownToken:r,startedAt:(/* @__PURE__ */ new Date()).toISOString(),pid:process.pid,configPath:i,runtimeLifecycle:a}}function Se(){return new o.PortRegistryService(process.env.PORT_REGISTRY_PATH)}function Y(){return process.env.NODE_ENV??`development`}async function Ce(e,t,n,r,i,a,s=n===void 0?o.DEFAULT_PORT_RANGE:{min:n,max:n}){let c=Se(),l=await c.reservePort({repositoryPath:await U(),serviceName:e,serviceType:R,environment:Y(),pid:process.pid,host:t,preferredPort:n,portRange:s,force:!0,metadata:{transport:i,serverId:r,...a?{configPath:a}:{}}});if(!l.success||!l.record){let e=n===void 0?`dynamic port`:`port ${n}`;throw Error(l.error||`Failed to reserve ${e} in port registry`)}let u=!1;return{port:l.record.port,release:async()=>{if(u)return;u=!0;let t=await c.releasePort({repositoryPath:await U(),serviceName:e,serviceType:R,pid:process.pid,environment:Y(),force:!0});if(!t.success&&t.error&&!t.error.includes(`No matching registry entry`))throw Error(t.error||`Failed to release port for ${e}`)}}}async function we(e){e&&await e.release()}function Te(e,t,n,r,i){return{serverId:e,shutdownToken:t,onShutdownRequested:n,runtimeLifecycle:r,idleShutdownMs:i}}async function X(e,t){try{await e.remove(t)}catch(e){throw Error(`Failed to remove runtime state for '${t}': ${W(e)}`)}}async function Ee(e,t){try{await e.write(t)}catch(e){throw Error(`Failed to persist runtime state for '${t.serverId}': ${W(e)}`)}}async function De(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop owned HTTP transport '${n}': ${W(e)}`)}}finally{await r?.release({kill:!1}),await X(t,n)}}async function Oe(e,t,n){await n?.release({kill:!1}),await X(e,t)}async function ke(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop HTTP transport during cleanup for '${n}': ${W(e)}`)}}finally{await r?.release({kill:!1}),await X(t,n)}}async function Z(e,t,n={}){try{await e.start()}catch(e){throw Error(`Failed to start transport handler: ${W(e)}`)}let r=!1,i=async n=>{if(!r){r=!0,console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),t&&await t(),process.exit(0)}catch(e){console.error(`Failed to gracefully stop transport during ${n}: ${W(e)}`),process.exit(1)}}};process.on(`SIGINT`,async()=>await i(`SIGINT`)),process.on(`SIGTERM`,async()=>await i(`SIGTERM`)),n.shutdownOnStdinClose&&(process.stdin.on(`end`,async()=>await i(`stdin end`)),process.stdin.on(`close`,async()=>await i(`stdin close`)))}async function Ae(t,n,a,s){e.P();let c=a[0],l=await e.l(t),u=new e.T,d=(0,r.randomUUID)(),f=t.serverId??e.F(),p=ve(process.env.MCP_PROXY_RUNTIME_LIFECYCLE),m=n.port,h=m===void 0?o.DEFAULT_PORT_RANGE:{min:m,max:m},g=await Ce(L,n.host??N,m,f,F,c,h),_=g.port,v={...n,port:_},y=await(0,i.createProcessLease)({repositoryPath:await U(),serviceName:`mcp-proxy-http`,serviceType:`service`,environment:Y(),host:v.host??N,port:_,command:process.argv[1],args:process.argv.slice(2),...e.v()?{processGroupId:process.pid,terminationMode:`process-group`}:{terminationMode:`direct`},metadata:{transport:F,serverId:f,runtimeLifecycle:p,...c?{configPath:c}:{}}}),b=async()=>{await we(g??null),b=async()=>void 0},x=xe(f,v,_,d,c,p),S,C=!1,w=async()=>{if(!C){C=!0;try{await De(S,u,x.serverId,y),await b(),await l.dispose(),process.exit(0)}catch(e){throw Error(`Failed to stop HTTP runtime '${x.serverId}' from admin shutdown: ${W(e)}`)}}};try{let t=Te(x.serverId,d,w,p,s);S=new e.S(()=>e.r(l),v,t)}catch(e){throw await b(),await y.release({kill:!1}),await l.dispose(),Error(`Failed to create HTTP runtime server: ${W(e)}`)}try{await Z(S,async()=>{await b(),await l.dispose(),await Oe(u,x.serverId,y)}),await Ee(u,x)}catch(e){throw await b(),await l.dispose(),await ke(S,u,x.serverId,y),Error(`Failed to start HTTP runtime '${x.serverId}': ${W(e)}`)}console.error(`Runtime state: http://${x.host}:${x.port} (${x.serverId})`)}async function je(t){let n;try{n=await e.n(t),await Z(new e.d(n,J()),async()=>{await n?.dispose?.()},{shutdownOnStdinClose:!0})}catch(e){throw await n?.dispose?.(),Error(`Failed to start stdio transport: ${W(e)}`)}}async function Me(t){if(t)try{return(await new e.T().read(t))?.runtimeLifecycle}catch{return}}function Ne(t){if(!t)return e.g;let n=Number.parseInt(t,10);return Number.isInteger(n)&&n>0?n:e.g}function Q(e,t){let a=i.ProcessRegistryService.resolveRegistryPath(process.env.PROCESS_REGISTRY_PATH),o=(0,r.createHash)(`sha1`).update(`${(0,i.normalizeRepositoryPath)(e)}|${t}`).digest(`hex`);return(0,n.join)((0,n.dirname)(a),`mcp-proxy-runtime-${o.slice(0,16)}.lock`)}async function $(e,t,n){if(e.port!==void 0)return{endpoint:new URL(`http://${e.host??N}:${e.port}${M}`),runtimeLifecycle:V};let r=await U(),a=Ne(t.timeoutMs)+1e4;return await(0,i.withFileLock)(Q(r,L),async()=>Pe(r,e,t,n),{staleAfterMs:a,retryDelayMs:250,maxRetries:Math.ceil(a/250)})}async function Pe(t,n,r,i){let a=await e._(t);if(a){let e=n.host??a.host,t=a.serverId===`unknown`?void 0:a.serverId;return{endpoint:new URL(`http://${e}:${a.port}${M}`),runtimeServerId:t,runtimeLifecycle:a.runtimeLifecycle??await Me(t)??V}}let o=await e.y({host:n.host??N,config:i,cache:r.cache,definitionsCache:r.definitionsCache,clearDefinitionsCache:r.clearDefinitionsCache,proxyMode:r.proxyMode,runtimeLifecycle:B,idleShutdownMinutes:r.idleShutdownMinutes});return{endpoint:new URL(`http://${o.host}:${o.port}${M}`),runtimeServerId:o.serverId,runtimeLifecycle:o.runtimeLifecycle??V}}async function Fe(e,t,n){let{endpoint:r}=await $(e,t,n);return r}function Ie(e){return`runtime:${e}`}async function Le(e){if(e.runtimeLifecycle===B&&e.runtimeServerId)return await(0,i.createProcessLease)({repositoryPath:await U(),serviceName:`mcp-proxy-stdio-http-bridge:${(0,r.randomUUID)()}`,serviceType:`tool`,environment:Y(),pid:process.pid,command:process.argv[1],args:process.argv.slice(2),tags:[z,Ie(e.runtimeServerId)],metadata:{transport:I,runtimeServerId:e.runtimeServerId,runtimeLifecycle:e.runtimeLifecycle,endpoint:e.endpoint.toString()},force:!1})}function Re(e){return e.pid===process.pid}async function ze(e){return await new i.ProcessRegistryService(process.env.PROCESS_REGISTRY_PATH).listProcesses({repositoryPath:await U(),serviceType:`tool`,tags:[z,Ie(e)],environment:Y(),liveOnly:!0})}async function Be(e){return(await ze(e)).filter(e=>!Re(e)).length>0?!1:(await new Promise(e=>setTimeout(e,500)),(await ze(e)).filter(e=>!Re(e)).length===0)}async function Ve(t){if(t.runtimeLifecycle!==B||!t.runtimeServerId)return;let n=t.runtimeServerId,r=Q(await U(),L);try{await(0,i.withFileLock)(r,async()=>{await Be(n)&&await new e.C().stop({serverId:n,force:!0})})}catch(e){console.error(`Failed to stop managed stdio-http runtime; leaving it alive: ${W(e)}`)}}async function He(t,n,r,i){let a=n.autoDisconnect?!0:i?.keepAlive!==void 0&&!i.keepAlive,o,s;try{o=await $(t,n,r),s=await Le(o);let{endpoint:i}=o;await Z(new e.u({endpoint:i,resolveEndpoint:async()=>await Fe(t,n,r)},J()),async()=>{try{await s?.release({kill:!1,releasePort:!1})}catch(e){console.error(`Failed to release stdio-http bridge lease; leaving runtime alive: ${W(e)}`);return}a&&o&&await Ve(o)},{shutdownOnStdinClose:!0})}catch(e){try{await s?.release({kill:!1,releasePort:!1})}catch(t){throw Error(`Failed to start stdio-http transport: ${W(e)}; also failed to release bridge lease: ${W(t)}`)}throw Error(`Failed to start stdio-http transport: ${W(e)}`)}}async function Ue(t,n,r,i,a){try{if(t===P){await je(i);return}if(t===F){await Ae(i,q(n,e.t.HTTP,a),r,ue(n.idleShutdownMinutes));return}await He(q(n,e.t.HTTP,a),n,r,a)}catch(e){throw Error(`Failed to start transport '${t}': ${W(e)}`)}}async function We(t,n){try{let r=await e.y({id:t.id,host:t.host??N,port:t.port,config:n,cache:t.cache,definitionsCache:t.definitionsCache,clearDefinitionsCache:t.clearDefinitionsCache,proxyMode:t.proxyMode,timeoutMs:t.timeoutMs,idleShutdownMinutes:t.idleShutdownMinutes});e.x(r)}catch(e){console.error(`Failed to prestart HTTP runtime '${t.id||`generated-server-id`}': ${W(e)}`),process.exit(1)}}const Ge=new c.Command(`mcp-serve`).description(`Start MCP server with specified transport or prestart the HTTP runtime in the background`).option(`-t, --type <type>`,`Transport type: ${P}, ${F}, or ${I}`).option(`-p, --port <port>`,`Port to listen on (http) or backend port for stdio-http`,e=>Number.parseInt(e,10)).option(`--host <host>`,`Host to bind to (http) or backend host for stdio-http`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`--no-cache`,`Disable configuration caching, always reload from config file`).option(`--definitions-cache <path>`,`Path to prefetched tool/prompt/skill definitions cache file`).option(`--clear-definitions-cache`,`Delete definitions cache before startup`,!1).option(`--proxy-mode <mode>`,`How mcp-proxy exposes downstream tools: meta, flat, search, or group`,`meta`).option(`--id <id>`,`Unique server identifier (overrides config file id, auto-generated if not provided)`).option(`--auto-disconnect`,`Stop the managed HTTP runtime when the last stdio-http bridge exits (default: keep runtime alive for reuse)`,!1).option(`--idle-shutdown-minutes <minutes>`,`Stop the HTTP runtime after N minutes with no MCP session and no request (0 disables; overrides ${H})`,e=>Number.parseFloat(e)).option(`--prestart-http`,`Prestart the HTTP runtime in the background and exit after it becomes healthy`,!1).option(`--timeout-ms <ms>`,`How long to wait for the HTTP runtime to become healthy`,String(e.g)).action(async t=>{try{let n=e.R(t.config),r=n.length>0?null:await fe(),i=r?[r]:n;if(t.prestartHttp){await We(t,i);return}let a=await me(i),o=ge((t.type??a.type??P).toLowerCase());_e(t.proxyMode),await Ue(o,t,i,ye(t,i,await he(t,i)),a)}catch(e){let n=(t.type??P).toLowerCase(),r=G(n)?n:P,i=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0,a=t.port??(Number.isFinite(i)?i:void 0);console.error(be(r,t.host??N,a,e)),process.exit(1)}}),Ke=new c.Command(`prefetch`).description(`Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-p, --parallel`,`Run prefetch commands in parallel`,!1).option(`-d, --dry-run`,`Show what would be prefetched without executing`,!1).option(`-f, --filter <type>`,`Filter by package manager type: npx, pnpx, uvx, or uv`).option(`--definitions-out <path>`,`Write discovered definitions to a JSON or YAML cache file`).option(`--skip-packages`,`Skip package prefetch and only build definitions cache`,!1).option(`--clear-definitions-cache`,`Delete the definitions cache file before continuing`,!1).action(async t=>{try{let n=e.o(),r=e.R(t.config),i=r.length>0?null:await e.I(),a=i?[i]:r;a.length===0&&(O.error(`No MCP configuration file found.`),O.info(`Use --config <path> to specify a config file, or run "po-mcp-proxy init" to create one.`),process.exit(1)),O.info(`Loading configuration from: ${a.join(`, `)}`);let o=await n.createConfigFetcherService({configSources:e.z(a),useCache:!1}).fetchConfiguration(!0),s=o.id||e.F(),c=e.j.generateConfigHash(o),l=t.definitionsOut||e.j.getDefaultCachePath(a),u=n.createPrefetchService({mcpConfig:o,filter:t.filter,parallel:t.parallel}),d=u.extractPackages(),f=!t.skipPackages,p=!!t.definitionsOut;if(t.clearDefinitionsCache&&(t.dryRun?O.info(`Would clear definitions cache: ${l}`):(await e.j.clearFile(l),O.success(`Cleared definitions cache: ${l}`))),f){if(d.length===0)O.warning(`No packages found to prefetch.`),O.info(`Prefetch supports: npx, pnpx, uvx, and uv run commands`);else{O.info(`Found ${d.length} package(s) to prefetch:`);for(let e of d)O.item(`${e.serverName}: ${e.packageManager} ${e.packageName}`)}}if(!f&&!p){O.warning(`Nothing to do. Use package prefetch or provide --definitions-out.`);return}if(t.dryRun){if(f&&d.length>0){O.newline(),O.header(`Dry run mode - commands that would be executed:`);for(let e of d)O.indent(e.fullCommand.join(` `))}p&&(O.newline(),O.info(`Would write definitions cache to: ${l}`));return}let m=!1;if(f&&d.length>0){O.newline(),O.info(`Prefetching packages...`);let e=await u.prefetch();if(O.newline(),e.failed===0?O.success(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`):O.warning(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`),e.failed>0){m=!0,O.newline(),O.error(`Failed packages:`);for(let t of e.results.filter(e=>!e.success))O.item(`${t.package.serverName} (${t.package.packageName}): ${t.output.trim()}`)}}if(p){O.newline(),O.info(`Collecting definitions cache...`);let t=await n.createClientManagerService(),r=o.skills?.paths||[],i=r.length>0?n.createSkillService(process.cwd(),r):void 0,u=n.createDefinitionsCacheService(t,i);await Promise.all(Object.entries(o.mcpServers).map(async([e,n])=>{try{await t.connectToServer(e,n),O.item(`Connected for definitions: ${e}`)}catch(t){O.warning(`Failed to connect for definitions: ${e} (${t instanceof Error?t.message:String(t)})`)}}));let d=await u.collectForCache({configPath:a[0],configHash:c,oneMcpVersion:e.h,serverId:s});await e.j.writeToFile(l,d),O.success(`Definitions cache written: ${l} (${Object.keys(d.servers).length} servers, ${d.skills.length} skills)`),d.failures.length>0&&O.warning(`Definitions cache completed with ${d.failures.length} server failure(s)`),await t.disconnectAll()}m&&process.exit(1)}catch(e){O.error(`Error executing prefetch: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});function qe(e){return e instanceof Error?e.message:String(e)}const Je=new c.Command(`read-resource`).description(`Read a resource by URI from a connected MCP server`).argument(`<uri>`,`Resource URI to read`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-s, --server <name>`,`Server name (required if resource exists on multiple servers)`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await x(t,async({clientManager:n})=>{let r=n.getAllClients();if(t.server){let r=n.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Reading ${e} from ${t.server}...`);let i=await r.readResource(e);if(t.json)console.log(JSON.stringify(i,null,2));else for(let e of i.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2));return}let i=await Promise.all(r.map(async t=>{try{let n=(await t.listResources()).some(t=>t.uri===e);return{serverName:t.serverName,hasResource:n,error:null}}catch(e){return{serverName:t.serverName,hasResource:!1,error:e}}})),a=[];for(let{serverName:e,hasResource:t,error:n}of i)n?console.error(`Failed to list resources from ${e}: ${qe(n)}`):t&&a.push(e);if(a.length===0)throw Error(`Resource "${e}" not found on any connected server`);if(a.length>1)throw Error(`Resource "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=a[0],s=n.getClient(o);if(!s)throw Error(`Internal error: Server "${o}" not connected`);t.json||console.error(`Reading ${e} from ${o}...`);let c=await s.readResource(e);if(t.json)console.log(JSON.stringify(c,null,2));else for(let e of c.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2))})}catch(e){console.error(`Error executing read-resource: ${qe(e)}`),process.exit(1)}});function Ye(e){return e instanceof Error?e.message:String(e)}function Xe(e){console.log(`Stopped mcp-proxy server '${e.serverId}'.`),console.log(`Endpoint: http://${e.host}:${e.port}`),console.log(`Result: ${e.message}`)}const Ze=new c.Command(`stop`).description(`Stop a running HTTP mcp-proxy server`).option(`--id <id>`,`Target server ID from the runtime registry`).option(`--host <host>`,`Target runtime host`).option(`--port <port>`,`Target runtime port`,e=>Number.parseInt(e,10)).option(`-c, --config <path>`,`Reserved for future config-based targeting support`).option(`--token <token>`,`Override the persisted shutdown token`).option(`--force`,`Skip server ID verification against the /health response`,!1).option(`-j, --json`,`Output as JSON`,!1).option(`--timeout <ms>`,`Maximum time to wait for shutdown completion`,e=>Number.parseInt(e,10),5e3).action(async t=>{try{t.config&&console.error(`Warning: --config is not used yet; runtime resolution uses the persisted registry.`);let n=await e.o().createStopServerService().stop({serverId:t.id,host:t.host,port:t.port,token:t.token,force:t.force,timeoutMs:t.timeout});if(t.json){console.log(JSON.stringify(n,null,2));return}Xe(n)}catch(e){let n=`Error executing stop: ${Ye(e)}`;t.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function Qe(e){return e instanceof Error?e.message:String(e)}const $e=new c.Command(`use-tool`).description(`Execute an MCP tool with arguments`).argument(`<toolName>`,`Tool name to execute`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,e.L).option(`-s, --server <name>`,`Server name (required if tool exists on multiple servers)`).option(`-a, --args <json>`,`Tool arguments as JSON string`,`{}`).option(`-t, --timeout <ms>`,`Request timeout in milliseconds for tool execution (default: 60000)`,Number.parseInt).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{console.error(`Error: Invalid JSON in --args`),process.exit(1)}await x(t,async({container:r,config:i,clientManager:a})=>{let o=a.getAllClients();if(t.server){let r=a.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Executing ${e} on ${t.server}...`);let i=t.timeout?{timeout:t.timeout}:void 0,o=await r.callTool(e,n,i);if(t.json)console.log(JSON.stringify(o,null,2));else{if(console.log(`
142
142
  Result:`),o.content)for(let e of o.content)e.type===`text`?console.log(e.text):console.log(JSON.stringify(e,null,2));o.isError&&(console.error(`
143
143
  ⚠️ Tool execution returned an error`),process.exit(1))}return}let s=await Promise.all(o.map(async t=>{try{let n=(await t.listTools()).some(t=>t.name===e);return{serverName:t.serverName,hasTool:n,error:null}}catch(e){return{serverName:t.serverName,hasTool:!1,error:e}}})),c=[];for(let{serverName:e,hasTool:n,error:r}of s)r?t.json||console.error(`Failed to list tools from ${e}:`,r):n&&c.push(e);if(c.length===0){let n=i.skills?.paths||[];if(n.length>0)try{let i=process.env.PROJECT_PATH||process.cwd(),a=r.createSkillService(i,n),o=e.startsWith(`skill__`)?e.slice(7):e,s=await a.getSkill(o);if(s){let e={content:[{type:`text`,text:s.content}]};t.json?console.log(JSON.stringify(e,null,2)):(console.log(`
144
144
  Skill content:`),console.log(s.content));return}}catch(n){t.json||console.error(`Failed to lookup skill "${e}":`,n)}throw Error(`Tool or skill "${e}" not found on any connected server or configured skill paths`)}if(c.length>1)throw Error(`Tool "${e}" found on multiple servers: ${c.join(`, `)}`);let l=c[0],u=a.getClient(l);if(!u)throw Error(`Internal error: Server "${l}" not connected`);t.json||console.error(`Executing ${e} on ${l}...`);let d=t.timeout?{timeout:t.timeout}:void 0,f=await u.callTool(e,n,d);if(t.json)console.log(JSON.stringify(f,null,2));else{if(console.log(`
145
145
  Result:`),f.content)for(let e of f.content)e.type===`text`?console.log(e.text):console.log(JSON.stringify(e,null,2));f.isError&&(console.error(`
146
- ⚠️ Tool execution returned an error`),process.exit(1))}})}catch(e){console.error(`Error executing use-tool: ${Qe(e)}`),process.exit(1)}});async function et(){try{let t=new l.Command;t.name(`po-mcp-proxy`).description(`MCP proxy server package`).version(e.h),t.addCommand(re),t.addCommand(Ge),t.addCommand(ce),t.addCommand(C),t.addCommand($e),t.addCommand(ae),t.addCommand(Je),t.addCommand(ie),t.addCommand(ee),t.addCommand(Ke),t.addCommand(Ze),t.addCommand(g),await t.parseAsync(process.argv)}catch(e){console.error(`CLI execution failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}et().catch(e=>{console.error(`Fatal error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
146
+ ⚠️ Tool execution returned an error`),process.exit(1))}})}catch(e){console.error(`Error executing use-tool: ${Qe(e)}`),process.exit(1)}});async function et(){try{let t=new c.Command;t.name(`po-mcp-proxy`).description(`MCP proxy server package`).version(e.h),t.addCommand(re),t.addCommand(Ge),t.addCommand(ce),t.addCommand(C),t.addCommand($e),t.addCommand(ae),t.addCommand(Je),t.addCommand(ie),t.addCommand(ee),t.addCommand(Ke),t.addCommand(Ze),t.addCommand(g),await t.parseAsync(process.argv)}catch(e){console.error(`CLI execution failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}et().catch(e=>{console.error(`Fatal error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});
package/dist/cli.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
- import{C as e,F as t,I as n,L as r,M as i,N as a,P as o,S as s,T as c,_ as l,b as u,d,g as f,h as p,j as m,l as h,n as g,o as _,r as v,t as y,u as b,ut as x,v as ee,x as S,y as C}from"./src-CnSFuSoW.mjs";import{constants as w,readFileSync as T}from"node:fs";import{dirname as E,join as te,resolve as D}from"node:path";import{createHash as ne,randomUUID as O}from"node:crypto";import{access as re,writeFile as ie}from"node:fs/promises";import{ProcessRegistryService as k,createProcessLease as ae,normalizeRepositoryPath as oe,withFileLock as se}from"@agimon-ai/foundation-process-registry";import*as ce from"js-yaml";import{DEFAULT_PORT_RANGE as le,PortRegistryService as ue}from"@agimon-ai/foundation-port-registry";import{Liquid as de}from"liquidjs";import{Command as A}from"commander";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 u(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 c,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 C({host:a,port:o,config:n,cache:r.useCache!==!1,clearDefinitionsCache:!1,proxyMode:`flat`}));let c=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=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 i=(e,t)=>{t===void 0?console.error(e):console.error(e,t)},a=e.json?{trace:i,debug:i,info:i,warn:i,error:i}:console,s=_(a),c=n(e.config),l=c.length>0?null:o(),u=l?[l]:c;if(u.length===0)throw Error(`No config file found. Use --config or create mcp-config.yaml`);let d=await s.createConfigFetcherService({configSources:r(u),useCache:e.useCache}).fetchConfiguration();return d.proxy?.port?await be(s,d,u,e,t):await xe(s,d,u,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)`,t).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-DqTvGVh7.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:
6
6
  `);for(let e of u)console.log(`Skill: ${e.name}`),console.log(`Location: ${e.location}`),console.log(`Instructions:\n${e.instructions}`),console.log(``)}if(p.length>0){console.log(`
7
- Next steps:`);for(let e of p)console.log(` • ${e}`);console.log(``)}d.length>0&&console.error(`\nTools/skills not found: ${d.join(`, `)}`),l.length===0&&u.length===0&&(console.error(`No tools or skills found`),process.exit(1))}})}catch(e){console.error(`Error executing describe-tools: ${Se(e)}`),process.exit(1)}});function N(e){return e instanceof Error?e.message:String(e)}const we=new A(`get-prompt`).description(`Get a prompt by name from a connected MCP server`).argument(`<promptName>`,`Prompt name to fetch`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Server name (required if prompt exists on multiple servers)`).option(`-a, --args <json>`,`Prompt arguments as JSON string`,`{}`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{throw Error(`Invalid JSON in --args`)}await M(t,async({clientManager:r})=>{let i=r.getAllClients();if(t.server){let i=r.getClient(t.server);if(!i)throw Error(`Server "${t.server}" not found`);let a=await i.getPrompt(e,n);if(t.json)console.log(JSON.stringify(a,null,2));else for(let e of a.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}return}let a=[];if(await Promise.all(i.map(async n=>{try{(await n.listPrompts()).some(t=>t.name===e)&&a.push(n.serverName)}catch(e){t.json||console.error(`Failed to list prompts from ${n.serverName}: ${N(e)}`)}})),a.length===0)throw Error(`Prompt "${e}" not found on any connected server`);if(a.length>1)throw Error(`Prompt "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=r.getClient(a[0]);if(!o)throw Error(`Internal error: Server "${a[0]}" not connected`);let s=await o.getPrompt(e,n);if(t.json)console.log(JSON.stringify(s,null,2));else for(let e of s.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}})}catch(e){console.error(`Error executing get-prompt: ${N(e)}`),process.exit(1)}});var Te=`{
7
+ Next steps:`);for(let e of p)console.log(` • ${e}`);console.log(``)}d.length>0&&console.error(`\nTools/skills not found: ${d.join(`, `)}`),l.length===0&&u.length===0&&(console.error(`No tools or skills found`),process.exit(1))}})}catch(e){console.error(`Error executing describe-tools: ${Se(e)}`),process.exit(1)}});function N(e){return e instanceof Error?e.message:String(e)}const we=new A(`get-prompt`).description(`Get a prompt by name from a connected MCP server`).argument(`<promptName>`,`Prompt name to fetch`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-s, --server <name>`,`Server name (required if prompt exists on multiple servers)`).option(`-a, --args <json>`,`Prompt arguments as JSON string`,`{}`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{throw Error(`Invalid JSON in --args`)}await M(t,async({clientManager:r})=>{let i=r.getAllClients();if(t.server){let i=r.getClient(t.server);if(!i)throw Error(`Server "${t.server}" not found`);let a=await i.getPrompt(e,n);if(t.json)console.log(JSON.stringify(a,null,2));else for(let e of a.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}return}let a=[];if(await Promise.all(i.map(async n=>{try{(await n.listPrompts()).some(t=>t.name===e)&&a.push(n.serverName)}catch(e){t.json||console.error(`Failed to list prompts from ${n.serverName}: ${N(e)}`)}})),a.length===0)throw Error(`Prompt "${e}" not found on any connected server`);if(a.length>1)throw Error(`Prompt "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=r.getClient(a[0]);if(!o)throw Error(`Internal error: Server "${a[0]}" not connected`);let s=await o.getPrompt(e,n);if(t.json)console.log(JSON.stringify(s,null,2));else for(let e of s.messages){let t=e.content;typeof t==`object`&&t&&`text`in t?console.log(t.text):console.log(JSON.stringify(e,null,2))}})}catch(e){console.error(`Error executing get-prompt: ${N(e)}`),process.exit(1)}});var Te=`{
8
8
  "_comment": "MCP Server Configuration - Use \${VAR_NAME} syntax for environment variable interpolation",
9
9
  "_instructions": "config.instruction: Server's default instruction | instruction: User override (takes precedence)",
10
10
  "mcpServers": {
@@ -138,9 +138,9 @@ mcpServers:
138
138
  # # omitToolDescription: true
139
139
  # # instruction: Optional user override
140
140
  {% endif %}
141
- `;function P(e=``){console.log(e)}function F(e,t){console.error(t?`${e} ${t}`:e)}const I={info:e=>P(e),error:(e,t)=>F(e,t)},L={info:e=>P(e),warning:e=>P(`Warning: ${e}`),error:e=>F(e),success:e=>P(e),newline:()=>P(),header:e=>P(e),item:e=>P(`- ${e}`),indent:e=>P(` ${e}`)},De=new A(`init`).description(`Initialize MCP configuration file`).option(`-o, --output <path>`,`Output file path`,`mcp-config.yaml`).option(`--json`,`Generate JSON config instead of YAML`,!1).option(`-f, --force`,`Overwrite existing config file`,!1).option(`--mcp-servers <json>`,`JSON string of MCP servers to add to config (optional)`).action(async e=>{try{let t=D(e.output),n=!e.json&&(t.endsWith(`.yaml`)||t.endsWith(`.yml`)),r;if(n){let t=new de,n=null;if(e.mcpServers)try{let t=JSON.parse(e.mcpServers);n=Object.entries(t).map(([e,t])=>({name:e,command:t.command,args:t.args}))}catch(e){I.error(`Failed to parse --mcp-servers JSON:`,e instanceof Error?e.message:String(e)),process.exit(1)}r=await t.parseAndRender(Ee,{mcpServers:n})}else r=Te;try{await ie(t,r,{encoding:`utf-8`,flag:e.force?`w`:`wx`})}catch(e){throw e&&typeof e==`object`&&`code`in e&&e.code===`EEXIST`&&(I.error(`Config file already exists: ${t}`),I.info(`Use --force to overwrite`),process.exit(1)),e}I.info(`MCP configuration file created: ${t}`),I.info(`Next steps:`),I.info(`1. Edit the configuration file to add your MCP servers`),I.info(`2. Run: po-mcp-proxy mcp-serve --config ${t}`)}catch(e){I.error(`Error executing init:`,e instanceof Error?e.message:String(e)),process.exit(1)}});function R(e){return e instanceof Error?e.message:String(e)}const Oe=new A(`list-prompts`).description(`List all available prompts from connected MCP servers`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await M(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={};if(await Promise.all(n.map(async t=>{try{r[t.serverName]=await t.listPrompts()}catch(n){r[t.serverName]=[],e.json||console.error(`Failed to list prompts from ${t.serverName}: ${R(n)}`)}})),e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No prompts available`);else for(let e of t)if(console.log(` - ${e.name}: ${e.description||`No description`}`),e.arguments&&e.arguments.length>0){let t=e.arguments.map(e=>`${e.name}${e.required?` (required)`:``}`).join(`, `);console.log(` args: ${t}`)}})}catch(e){console.error(`Error executing list-prompts: ${R(e)}`),process.exit(1)}});function ke(e){return e instanceof Error?e.message:String(e)}const Ae=new A(`list-resources`).description(`List all available resources from connected MCP servers`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Filter by server name`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await M(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={},i=await Promise.all(n.map(async e=>{try{let t=await e.listResources();return{serverName:e.serverName,resources:t,error:null}}catch(t){return{serverName:e.serverName,resources:[],error:t}}}));for(let{serverName:t,resources:n,error:a}of i)a&&!e.json&&console.error(`Failed to list resources from ${t}: ${ke(a)}`),r[t]=n;if(e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No resources available`);else for(let e of t){let t=e.name?`${e.name} (${e.uri})`:e.uri;console.log(` - ${t}${e.description?`: ${e.description}`:``}`)}})}catch(e){console.error(`Error executing list-resources: ${ke(e)}`),process.exit(1)}});function je(e){return e instanceof Error?e.message:String(e)}function Me(e){for(let t of e.servers)if(console.log(`\n${t.server}:`),t.capabilities&&t.capabilities.length>0&&console.log(` capabilities: ${t.capabilities.join(`, `)}`),t.summary&&console.log(` summary: ${t.summary}`),t.tools.length===0)console.log(` no tools`);else for(let e of t.tools){let t=e.capabilities&&e.capabilities.length>0?` [${e.capabilities.join(`, `)}]`:``;console.log(` - ${e.name}${t}`),e.description&&console.log(` ${e.description}`)}}const Ne=new A(`search-tools`).description(`Search proxied MCP tools by capability or server`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Filter by server name`).option(`--capability <name>`,`Filter by capability tag, summary, tool name, or description`).option(`--definitions-cache <path>`,`Path to definitions cache file`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await M(e,async({container:t,config:n,clientManager:r,configFilePaths:i})=>{r.registerServerConfigs(n.mcpServers);let a=e.definitionsCache||m.getDefaultCachePath(i),o;try{o=await m.readFromFile(a)}catch{o=void 0}let s=t.createDefinitionsCacheService(r,void 0,{cacheData:o}),c=(await t.createSearchListToolsTool(r,s).execute({capability:e.capability,serverName:e.server})).content.find(e=>e.type===`text`),l=c?.type===`text`?JSON.parse(c.text):{servers:[]};if(e.json)console.log(JSON.stringify(l,null,2));else{if(!l.servers||l.servers.length===0)throw Error(`No tools matched the requested filters`);Me(l)}})}catch(e){console.error(`Error executing search-tools: ${je(e)}`),process.exit(1)}}),Pe=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],z=`/mcp`,B=`localhost`,V=`stdio`,H=`http`,U=`stdio-http`,W=`mcp-proxy-http`,Fe=`service`;function Ie(){return x()}const G=`mcp-proxy-stdio-http-bridge`,K=`stdio-http-managed`,q=`manual`,Le=`MCP_PROXY_IDLE_SHUTDOWN_MINUTES`;function J(){return Ie()}function Y(e){return e instanceof Error?e.message:String(e)}function Re(e){let t=process.env[Le],n=e??(t?Number.parseFloat(t):void 0);return n===void 0||!Number.isFinite(n)||n<=0?0:Math.round(n*6e4)}function ze(e){return e===V||e===H||e===U}function Be(e){return e===`meta`||e===`flat`||e===`search`||e===`group`}async function Ve(e){try{return await re(e,w.F_OK),!0}catch{return!1}}async function He(){try{let e=process.env.PROJECT_PATH;if(e)for(let t of Pe){let n=D(e,t);if(await Ve(n))return n}let t=process.cwd();for(let e=0;e<=3;e++){for(let e of Pe){let n=te(t,e);if(await Ve(n))return n}let e=E(t);if(e===t)break;t=e}return null}catch(e){throw Error(`Failed to discover MCP config file: ${Y(e)}`)}}function Ue(e){try{let t=T(e,`utf-8`),n=(e.endsWith(`.yaml`)||e.endsWith(`.yml`)?ce.load(t):JSON.parse(t))?.proxy;if(!n||typeof n!=`object`)return{};let r=n;return{type:typeof r.type==`string`?r.type:void 0,port:typeof r.port==`number`&&Number.isInteger(r.port)&&r.port>0?r.port:void 0,host:typeof r.host==`string`?r.host:void 0,keepAlive:typeof r.keepAlive==`boolean`?r.keepAlive:void 0}}catch{return{}}}function We(e){let t={};for(let n of e){let e=Ue(n);e.type!==void 0&&(t.type=e.type),e.port!==void 0&&(t.port=e.port),e.host!==void 0&&(t.host=e.host),e.keepAlive!==void 0&&(t.keepAlive=e.keepAlive)}return t}async function Ge(e,t){let n=_();if(e.id)return e.id;if(t.length>0)try{let i=await n.createConfigFetcherService({configSources:r(t),useCache:e.cache!==!1}).fetchConfiguration(e.cache===!1);if(i.id)return i.id}catch(e){throw Error(`Failed to resolve server ID from config '${t.join(`, `)}': ${Y(e)}`)}return a()}function Ke(e){if(!ze(e))throw Error(`Unknown transport type: '${e}'. Valid options: ${V}, ${H}, ${U}`);return e}function qe(e){if(!Be(e))throw Error(`Unknown proxy mode: '${String(e)}'. Valid options: meta, flat, search, group`)}function Je(e){return e===K?K:q}function Ye(e,t,n){let r=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0;return{mode:t,port:e.port??(Number.isFinite(r)?r:void 0)??n?.port,host:e.host??process.env.MCP_HOST??n?.host??B}}function Xe(){let e=(e,t)=>{t===void 0?console.error(e):console.error(e,t)};return{trace:e,debug:e,info:e,warn:e,error:e}}function Ze(e,t,n){return{configFilePath:t.length>0?t:void 0,noCache:e.cache===!1,serverId:n,definitionsCachePath:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode}}function Qe(e,t,n,r){let i=Y(r);return e===V?`Failed to start MCP server with transport '${e}': ${i}`:`Failed to start MCP server with transport '${e}' on ${n===void 0?`${t} (dynamic port)`:`${t}:${n}`}: ${i}`}function $e(e,t,n,r,i,a=q){return{serverId:e,host:t.host??B,port:n,transport:`http`,shutdownToken:r,startedAt:(/* @__PURE__ */ new Date()).toISOString(),pid:process.pid,configPath:i,runtimeLifecycle:a}}function et(){return new ue(process.env.PORT_REGISTRY_PATH)}function X(){return process.env.NODE_ENV??`development`}async function tt(e,t,n,r,i,a,o=n===void 0?le:{min:n,max:n}){let s=et(),c=await s.reservePort({repositoryPath:J(),serviceName:e,serviceType:Fe,environment:X(),pid:process.pid,host:t,preferredPort:n,portRange:o,force:!0,metadata:{transport:i,serverId:r,...a?{configPath:a}:{}}});if(!c.success||!c.record){let e=n===void 0?`dynamic port`:`port ${n}`;throw Error(c.error||`Failed to reserve ${e} in port registry`)}let l=!1;return{port:c.record.port,release:async()=>{if(l)return;l=!0;let t=await s.releasePort({repositoryPath:J(),serviceName:e,serviceType:Fe,pid:process.pid,environment:X(),force:!0});if(!t.success&&t.error&&!t.error.includes(`No matching registry entry`))throw Error(t.error||`Failed to release port for ${e}`)}}}async function nt(e){e&&await e.release()}function rt(e,t,n,r,i){return{serverId:e,shutdownToken:t,onShutdownRequested:n,runtimeLifecycle:r,idleShutdownMs:i}}async function Z(e,t){try{await e.remove(t)}catch(e){throw Error(`Failed to remove runtime state for '${t}': ${Y(e)}`)}}async function it(e,t){try{await e.write(t)}catch(e){throw Error(`Failed to persist runtime state for '${t.serverId}': ${Y(e)}`)}}async function at(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop owned HTTP transport '${n}': ${Y(e)}`)}}finally{await r?.release({kill:!1}),await Z(t,n)}}async function ot(e,t,n){await n?.release({kill:!1}),await Z(e,t)}async function st(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop HTTP transport during cleanup for '${n}': ${Y(e)}`)}}finally{await r?.release({kill:!1}),await Z(t,n)}}async function Q(e,t,n={}){try{await e.start()}catch(e){throw Error(`Failed to start transport handler: ${Y(e)}`)}let r=!1,i=async n=>{if(!r){r=!0,console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),t&&await t(),process.exit(0)}catch(e){console.error(`Failed to gracefully stop transport during ${n}: ${Y(e)}`),process.exit(1)}}};process.on(`SIGINT`,async()=>await i(`SIGINT`)),process.on(`SIGTERM`,async()=>await i(`SIGTERM`)),n.shutdownOnStdinClose&&(process.stdin.on(`end`,async()=>await i(`stdin end`)),process.stdin.on(`close`,async()=>await i(`stdin close`)))}async function ct(e,t,n,r){i();let o=n[0],l=await h(e),u=new c,d=O(),f=e.serverId??a(),p=Je(process.env.MCP_PROXY_RUNTIME_LIFECYCLE),m=t.port,g=m===void 0?le:{min:m,max:m},_=await tt(W,t.host??B,m,f,H,o,g),y=_.port,b={...t,port:y},x=await ae({repositoryPath:J(),serviceName:`mcp-proxy-http`,serviceType:`service`,environment:X(),host:b.host??B,port:y,command:process.argv[1],args:process.argv.slice(2),...ee()?{processGroupId:process.pid,terminationMode:`process-group`}:{terminationMode:`direct`},metadata:{transport:H,serverId:f,runtimeLifecycle:p,...o?{configPath:o}:{}}}),S=async()=>{await nt(_??null),S=async()=>void 0},C=$e(f,b,y,d,o,p),w,T=!1,E=async()=>{if(!T){T=!0;try{await at(w,u,C.serverId,x),await S(),await l.dispose(),process.exit(0)}catch(e){throw Error(`Failed to stop HTTP runtime '${C.serverId}' from admin shutdown: ${Y(e)}`)}}};try{let e=rt(C.serverId,d,E,p,r);w=new s(()=>v(l),b,e)}catch(e){throw await S(),await x.release({kill:!1}),await l.dispose(),Error(`Failed to create HTTP runtime server: ${Y(e)}`)}try{await Q(w,async()=>{await S(),await l.dispose(),await ot(u,C.serverId,x)}),await it(u,C)}catch(e){throw await S(),await l.dispose(),await st(w,u,C.serverId,x),Error(`Failed to start HTTP runtime '${C.serverId}': ${Y(e)}`)}console.error(`Runtime state: http://${C.host}:${C.port} (${C.serverId})`)}async function lt(e){let t;try{t=await g(e),await Q(new d(t,Xe()),async()=>{await t?.dispose?.()},{shutdownOnStdinClose:!0})}catch(e){throw await t?.dispose?.(),Error(`Failed to start stdio transport: ${Y(e)}`)}}async function ut(e){if(e)try{return(await new c().read(e))?.runtimeLifecycle}catch{return}}function dt(e){if(!e)return f;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0?t:f}function ft(e,t){let n=k.resolveRegistryPath(process.env.PROCESS_REGISTRY_PATH),r=ne(`sha1`).update(`${oe(e)}|${t}`).digest(`hex`);return te(E(n),`mcp-proxy-runtime-${r.slice(0,16)}.lock`)}async function pt(e,t,n){if(e.port!==void 0)return{endpoint:new URL(`http://${e.host??B}:${e.port}${z}`),runtimeLifecycle:q};let r=J(),i=dt(t.timeoutMs)+1e4;return await se(ft(r,W),async()=>mt(r,e,t,n),{staleAfterMs:i,retryDelayMs:250,maxRetries:Math.ceil(i/250)})}async function mt(e,t,n,r){let i=await l(e);if(i){let e=t.host??i.host,n=i.serverId===`unknown`?void 0:i.serverId;return{endpoint:new URL(`http://${e}:${i.port}${z}`),runtimeServerId:n,runtimeLifecycle:i.runtimeLifecycle??await ut(n)??q}}let a=await C({host:t.host??B,config:r,cache:n.cache,definitionsCache:n.definitionsCache,clearDefinitionsCache:n.clearDefinitionsCache,proxyMode:n.proxyMode,runtimeLifecycle:K,idleShutdownMinutes:n.idleShutdownMinutes});return{endpoint:new URL(`http://${a.host}:${a.port}${z}`),runtimeServerId:a.serverId,runtimeLifecycle:a.runtimeLifecycle??q}}async function ht(e,t,n){let{endpoint:r}=await pt(e,t,n);return r}function gt(e){return`runtime:${e}`}async function _t(e){if(e.runtimeLifecycle===K&&e.runtimeServerId)return await ae({repositoryPath:J(),serviceName:`mcp-proxy-stdio-http-bridge:${O()}`,serviceType:`tool`,environment:X(),pid:process.pid,command:process.argv[1],args:process.argv.slice(2),tags:[G,gt(e.runtimeServerId)],metadata:{transport:U,runtimeServerId:e.runtimeServerId,runtimeLifecycle:e.runtimeLifecycle,endpoint:e.endpoint.toString()},force:!1})}function vt(e){return e.pid===process.pid}async function yt(e){return await new k(process.env.PROCESS_REGISTRY_PATH).listProcesses({repositoryPath:J(),serviceType:`tool`,tags:[G,gt(e)],environment:X(),liveOnly:!0})}async function bt(e){return(await yt(e)).filter(e=>!vt(e)).length>0?!1:(await new Promise(e=>setTimeout(e,500)),(await yt(e)).filter(e=>!vt(e)).length===0)}async function xt(t){if(t.runtimeLifecycle!==K||!t.runtimeServerId)return;let n=t.runtimeServerId,r=ft(J(),W);try{await se(r,async()=>{await bt(n)&&await new e().stop({serverId:n,force:!0})})}catch(e){console.error(`Failed to stop managed stdio-http runtime; leaving it alive: ${Y(e)}`)}}async function St(e,t,n,r){let i=t.autoDisconnect?!0:r?.keepAlive!==void 0&&!r.keepAlive,a,o;try{a=await pt(e,t,n),o=await _t(a);let{endpoint:r}=a;await Q(new b({endpoint:r,resolveEndpoint:async()=>await ht(e,t,n)},Xe()),async()=>{try{await o?.release({kill:!1,releasePort:!1})}catch(e){console.error(`Failed to release stdio-http bridge lease; leaving runtime alive: ${Y(e)}`);return}i&&a&&await xt(a)},{shutdownOnStdinClose:!0})}catch(e){try{await o?.release({kill:!1,releasePort:!1})}catch(t){throw Error(`Failed to start stdio-http transport: ${Y(e)}; also failed to release bridge lease: ${Y(t)}`)}throw Error(`Failed to start stdio-http transport: ${Y(e)}`)}}async function Ct(e,t,n,r,i){try{if(e===V){await lt(r);return}if(e===H){await ct(r,Ye(t,y.HTTP,i),n,Re(t.idleShutdownMinutes));return}await St(Ye(t,y.HTTP,i),t,n,i)}catch(t){throw Error(`Failed to start transport '${e}': ${Y(t)}`)}}async function wt(e,t){try{let n=await C({id:e.id,host:e.host??B,port:e.port,config:t,cache:e.cache,definitionsCache:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode,timeoutMs:e.timeoutMs,idleShutdownMinutes:e.idleShutdownMinutes});S(n)}catch(t){console.error(`Failed to prestart HTTP runtime '${e.id||`generated-server-id`}': ${Y(t)}`),process.exit(1)}}const Tt=new A(`mcp-serve`).description(`Start MCP server with specified transport or prestart the HTTP runtime in the background`).option(`-t, --type <type>`,`Transport type: ${V}, ${H}, or ${U}`).option(`-p, --port <port>`,`Port to listen on (http) or backend port for stdio-http`,e=>Number.parseInt(e,10)).option(`--host <host>`,`Host to bind to (http) or backend host for stdio-http`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`--no-cache`,`Disable configuration caching, always reload from config file`).option(`--definitions-cache <path>`,`Path to prefetched tool/prompt/skill definitions cache file`).option(`--clear-definitions-cache`,`Delete definitions cache before startup`,!1).option(`--proxy-mode <mode>`,`How mcp-proxy exposes downstream tools: meta, flat, search, or group`,`meta`).option(`--id <id>`,`Unique server identifier (overrides config file id, auto-generated if not provided)`).option(`--auto-disconnect`,`Stop the managed HTTP runtime when the last stdio-http bridge exits (default: keep runtime alive for reuse)`,!1).option(`--idle-shutdown-minutes <minutes>`,`Stop the HTTP runtime after N minutes with no MCP session and no request (0 disables; overrides ${Le})`,e=>Number.parseFloat(e)).option(`--prestart-http`,`Prestart the HTTP runtime in the background and exit after it becomes healthy`,!1).option(`--timeout-ms <ms>`,`How long to wait for the HTTP runtime to become healthy`,String(f)).action(async e=>{try{let t=n(e.config),r=t.length>0?null:await He(),i=r?[r]:t;if(e.prestartHttp){await wt(e,i);return}let a=We(i),o=Ke((e.type??a.type??V).toLowerCase());qe(e.proxyMode),await Ct(o,e,i,Ze(e,i,await Ge(e,i)),a)}catch(t){let n=(e.type??V).toLowerCase(),r=ze(n)?n:V,i=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0,a=e.port??(Number.isFinite(i)?i:void 0);console.error(Qe(r,e.host??B,a,t)),process.exit(1)}}),Et=new A(`prefetch`).description(`Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-p, --parallel`,`Run prefetch commands in parallel`,!1).option(`-d, --dry-run`,`Show what would be prefetched without executing`,!1).option(`-f, --filter <type>`,`Filter by package manager type: npx, pnpx, uvx, or uv`).option(`--definitions-out <path>`,`Write discovered definitions to a JSON or YAML cache file`).option(`--skip-packages`,`Skip package prefetch and only build definitions cache`,!1).option(`--clear-definitions-cache`,`Delete the definitions cache file before continuing`,!1).action(async e=>{try{let t=_(),i=n(e.config),s=i.length>0?null:o(),c=s?[s]:i;c.length===0&&(L.error(`No MCP configuration file found.`),L.info(`Use --config <path> to specify a config file, or run "po-mcp-proxy init" to create one.`),process.exit(1)),L.info(`Loading configuration from: ${c.join(`, `)}`);let l=await t.createConfigFetcherService({configSources:r(c),useCache:!1}).fetchConfiguration(!0),u=l.id||a(),d=m.generateConfigHash(l),f=e.definitionsOut||m.getDefaultCachePath(c),h=t.createPrefetchService({mcpConfig:l,filter:e.filter,parallel:e.parallel}),g=h.extractPackages(),v=!e.skipPackages,y=!!e.definitionsOut;if(e.clearDefinitionsCache&&(e.dryRun?L.info(`Would clear definitions cache: ${f}`):(await m.clearFile(f),L.success(`Cleared definitions cache: ${f}`))),v){if(g.length===0)L.warning(`No packages found to prefetch.`),L.info(`Prefetch supports: npx, pnpx, uvx, and uv run commands`);else{L.info(`Found ${g.length} package(s) to prefetch:`);for(let e of g)L.item(`${e.serverName}: ${e.packageManager} ${e.packageName}`)}}if(!v&&!y){L.warning(`Nothing to do. Use package prefetch or provide --definitions-out.`);return}if(e.dryRun){if(v&&g.length>0){L.newline(),L.header(`Dry run mode - commands that would be executed:`);for(let e of g)L.indent(e.fullCommand.join(` `))}y&&(L.newline(),L.info(`Would write definitions cache to: ${f}`));return}let b=!1;if(v&&g.length>0){L.newline(),L.info(`Prefetching packages...`);let e=await h.prefetch();if(L.newline(),e.failed===0?L.success(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`):L.warning(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`),e.failed>0){b=!0,L.newline(),L.error(`Failed packages:`);for(let t of e.results.filter(e=>!e.success))L.item(`${t.package.serverName} (${t.package.packageName}): ${t.output.trim()}`)}}if(y){L.newline(),L.info(`Collecting definitions cache...`);let e=t.createClientManagerService(),n=l.skills?.paths||[],r=n.length>0?t.createSkillService(process.cwd(),n):void 0,i=t.createDefinitionsCacheService(e,r);await Promise.all(Object.entries(l.mcpServers).map(async([t,n])=>{try{await e.connectToServer(t,n),L.item(`Connected for definitions: ${t}`)}catch(e){L.warning(`Failed to connect for definitions: ${t} (${e instanceof Error?e.message:String(e)})`)}}));let a=await i.collectForCache({configPath:c[0],configHash:d,oneMcpVersion:p,serverId:u});await m.writeToFile(f,a),L.success(`Definitions cache written: ${f} (${Object.keys(a.servers).length} servers, ${a.skills.length} skills)`),a.failures.length>0&&L.warning(`Definitions cache completed with ${a.failures.length} server failure(s)`),await e.disconnectAll()}b&&process.exit(1)}catch(e){L.error(`Error executing prefetch: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});function $(e){return e instanceof Error?e.message:String(e)}const Dt=new A(`read-resource`).description(`Read a resource by URI from a connected MCP server`).argument(`<uri>`,`Resource URI to read`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Server name (required if resource exists on multiple servers)`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await M(t,async({clientManager:n})=>{let r=n.getAllClients();if(t.server){let r=n.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Reading ${e} from ${t.server}...`);let i=await r.readResource(e);if(t.json)console.log(JSON.stringify(i,null,2));else for(let e of i.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2));return}let i=await Promise.all(r.map(async t=>{try{let n=(await t.listResources()).some(t=>t.uri===e);return{serverName:t.serverName,hasResource:n,error:null}}catch(e){return{serverName:t.serverName,hasResource:!1,error:e}}})),a=[];for(let{serverName:e,hasResource:t,error:n}of i)n?console.error(`Failed to list resources from ${e}: ${$(n)}`):t&&a.push(e);if(a.length===0)throw Error(`Resource "${e}" not found on any connected server`);if(a.length>1)throw Error(`Resource "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=a[0],s=n.getClient(o);if(!s)throw Error(`Internal error: Server "${o}" not connected`);t.json||console.error(`Reading ${e} from ${o}...`);let c=await s.readResource(e);if(t.json)console.log(JSON.stringify(c,null,2));else for(let e of c.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2))})}catch(e){console.error(`Error executing read-resource: ${$(e)}`),process.exit(1)}});function Ot(e){return e instanceof Error?e.message:String(e)}function kt(e){console.log(`Stopped mcp-proxy server '${e.serverId}'.`),console.log(`Endpoint: http://${e.host}:${e.port}`),console.log(`Result: ${e.message}`)}const At=new A(`stop`).description(`Stop a running HTTP mcp-proxy server`).option(`--id <id>`,`Target server ID from the runtime registry`).option(`--host <host>`,`Target runtime host`).option(`--port <port>`,`Target runtime port`,e=>Number.parseInt(e,10)).option(`-c, --config <path>`,`Reserved for future config-based targeting support`).option(`--token <token>`,`Override the persisted shutdown token`).option(`--force`,`Skip server ID verification against the /health response`,!1).option(`-j, --json`,`Output as JSON`,!1).option(`--timeout <ms>`,`Maximum time to wait for shutdown completion`,e=>Number.parseInt(e,10),5e3).action(async e=>{try{e.config&&console.error(`Warning: --config is not used yet; runtime resolution uses the persisted registry.`);let t=await _().createStopServerService().stop({serverId:e.id,host:e.host,port:e.port,token:e.token,force:e.force,timeoutMs:e.timeout});if(e.json){console.log(JSON.stringify(t,null,2));return}kt(t)}catch(t){let n=`Error executing stop: ${Ot(t)}`;e.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function jt(e){return e instanceof Error?e.message:String(e)}const Mt=new A(`use-tool`).description(`Execute an MCP tool with arguments`).argument(`<toolName>`,`Tool name to execute`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,t).option(`-s, --server <name>`,`Server name (required if tool exists on multiple servers)`).option(`-a, --args <json>`,`Tool arguments as JSON string`,`{}`).option(`-t, --timeout <ms>`,`Request timeout in milliseconds for tool execution (default: 60000)`,Number.parseInt).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{console.error(`Error: Invalid JSON in --args`),process.exit(1)}await M(t,async({container:r,config:i,clientManager:a})=>{let o=a.getAllClients();if(t.server){let r=a.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Executing ${e} on ${t.server}...`);let i=t.timeout?{timeout:t.timeout}:void 0,o=await r.callTool(e,n,i);if(t.json)console.log(JSON.stringify(o,null,2));else{if(console.log(`
141
+ `;function P(e=``){console.log(e)}function F(e,t){console.error(t?`${e} ${t}`:e)}const I={info:e=>P(e),error:(e,t)=>F(e,t)},L={info:e=>P(e),warning:e=>P(`Warning: ${e}`),error:e=>F(e),success:e=>P(e),newline:()=>P(),header:e=>P(e),item:e=>P(`- ${e}`),indent:e=>P(` ${e}`)},De=new A(`init`).description(`Initialize MCP configuration file`).option(`-o, --output <path>`,`Output file path`,`mcp-config.yaml`).option(`--json`,`Generate JSON config instead of YAML`,!1).option(`-f, --force`,`Overwrite existing config file`,!1).option(`--mcp-servers <json>`,`JSON string of MCP servers to add to config (optional)`).action(async e=>{try{let t=O(e.output),n=!e.json&&(t.endsWith(`.yaml`)||t.endsWith(`.yml`)),r;if(n){let t=new ue,n=null;if(e.mcpServers)try{let t=JSON.parse(e.mcpServers);n=Object.entries(t).map(([e,t])=>({name:e,command:t.command,args:t.args}))}catch(e){I.error(`Failed to parse --mcp-servers JSON:`,e instanceof Error?e.message:String(e)),process.exit(1)}r=await t.parseAndRender(Ee,{mcpServers:n})}else r=Te;try{await te(t,r,{encoding:`utf-8`,flag:e.force?`w`:`wx`})}catch(e){throw e&&typeof e==`object`&&`code`in e&&e.code===`EEXIST`&&(I.error(`Config file already exists: ${t}`),I.info(`Use --force to overwrite`),process.exit(1)),e}I.info(`MCP configuration file created: ${t}`),I.info(`Next steps:`),I.info(`1. Edit the configuration file to add your MCP servers`),I.info(`2. Run: po-mcp-proxy mcp-serve --config ${t}`)}catch(e){I.error(`Error executing init:`,e instanceof Error?e.message:String(e)),process.exit(1)}});function R(e){return e instanceof Error?e.message:String(e)}const Oe=new A(`list-prompts`).description(`List all available prompts from connected MCP servers`).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=>{try{await M(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={};if(await Promise.all(n.map(async t=>{try{r[t.serverName]=await t.listPrompts()}catch(n){r[t.serverName]=[],e.json||console.error(`Failed to list prompts from ${t.serverName}: ${R(n)}`)}})),e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No prompts available`);else for(let e of t)if(console.log(` - ${e.name}: ${e.description||`No description`}`),e.arguments&&e.arguments.length>0){let t=e.arguments.map(e=>`${e.name}${e.required?` (required)`:``}`).join(`, `);console.log(` args: ${t}`)}})}catch(e){console.error(`Error executing list-prompts: ${R(e)}`),process.exit(1)}});function ke(e){return e instanceof Error?e.message:String(e)}const Ae=new A(`list-resources`).description(`List all available resources from connected MCP servers`).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=>{try{await M(e,async({clientManager:t})=>{let n=e.server?[t.getClient(e.server)].filter(e=>e!==void 0):t.getAllClients();if(e.server&&n.length===0)throw Error(`Server "${e.server}" not found`);let r={},i=await Promise.all(n.map(async e=>{try{let t=await e.listResources();return{serverName:e.serverName,resources:t,error:null}}catch(t){return{serverName:e.serverName,resources:[],error:t}}}));for(let{serverName:t,resources:n,error:a}of i)a&&!e.json&&console.error(`Failed to list resources from ${t}: ${ke(a)}`),r[t]=n;if(e.json)console.log(JSON.stringify(r,null,2));else for(let[e,t]of Object.entries(r))if(console.log(`\n${e}:`),t.length===0)console.log(` No resources available`);else for(let e of t){let t=e.name?`${e.name} (${e.uri})`:e.uri;console.log(` - ${t}${e.description?`: ${e.description}`:``}`)}})}catch(e){console.error(`Error executing list-resources: ${ke(e)}`),process.exit(1)}});function je(e){return e instanceof Error?e.message:String(e)}function Me(e){for(let t of e.servers)if(console.log(`\n${t.server}:`),t.capabilities&&t.capabilities.length>0&&console.log(` capabilities: ${t.capabilities.join(`, `)}`),t.summary&&console.log(` summary: ${t.summary}`),t.tools.length===0)console.log(` no tools`);else for(let e of t.tools){let t=e.capabilities&&e.capabilities.length>0?` [${e.capabilities.join(`, `)}]`:``;console.log(` - ${e.name}${t}`),e.description&&console.log(` ${e.description}`)}}const Ne=new A(`search-tools`).description(`Search proxied MCP tools by capability or server`).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(`--capability <name>`,`Filter by capability tag, summary, tool name, or description`).option(`--definitions-cache <path>`,`Path to definitions cache file`).option(`-j, --json`,`Output as JSON`,!1).action(async e=>{try{await M(e,async({container:t,config:n,clientManager:r,configFilePaths:i})=>{r.registerServerConfigs(n.mcpServers);let a=e.definitionsCache||p.getDefaultCachePath(i),o;try{o=await p.readFromFile(a)}catch{o=void 0}let s=t.createDefinitionsCacheService(r,void 0,{cacheData:o}),c=(await t.createSearchListToolsTool(r,s).execute({capability:e.capability,serverName:e.server})).content.find(e=>e.type===`text`),l=c?.type===`text`?JSON.parse(c.text):{servers:[]};if(e.json)console.log(JSON.stringify(l,null,2));else{if(!l.servers||l.servers.length===0)throw Error(`No tools matched the requested filters`);Me(l)}})}catch(e){console.error(`Error executing search-tools: ${je(e)}`),process.exit(1)}}),Pe=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],z=`/mcp`,B=`localhost`,V=`stdio`,H=`http`,U=`stdio-http`,W=`mcp-proxy-http`,Fe=`service`;async function Ie(){return _()}const G=`mcp-proxy-stdio-http-bridge`,K=`stdio-http-managed`,q=`manual`,Le=`MCP_PROXY_IDLE_SHUTDOWN_MINUTES`;async function J(){return Ie()}function Y(e){return e instanceof Error?e.message:String(e)}function Re(e){let t=process.env[Le],n=e??(t?Number.parseFloat(t):void 0);return n===void 0||!Number.isFinite(n)||n<=0?0:Math.round(n*6e4)}function ze(e){return e===V||e===H||e===U}function Be(e){return e===`meta`||e===`flat`||e===`search`||e===`group`}async function Ve(e){try{return await w(e,de.F_OK),!0}catch{return!1}}async function He(){try{let e=process.env.PROJECT_PATH;if(e)for(let t of Pe){let n=O(e,t);if(await Ve(n))return n}let t=process.cwd();for(let e=0;e<=3;e++){for(let e of Pe){let n=D(t,e);if(await Ve(n))return n}let e=E(t);if(e===t)break;t=e}return null}catch(e){throw Error(`Failed to discover MCP config file: ${Y(e)}`)}}async function Ue(e){try{let t=await T(e,`utf-8`),n=(e.endsWith(`.yaml`)||e.endsWith(`.yml`)?se.load(t):JSON.parse(t))?.proxy;if(!n||typeof n!=`object`)return{};let r=n;return{type:typeof r.type==`string`?r.type:void 0,port:typeof r.port==`number`&&Number.isInteger(r.port)&&r.port>0?r.port:void 0,host:typeof r.host==`string`?r.host:void 0,keepAlive:typeof r.keepAlive==`boolean`?r.keepAlive:void 0}}catch{return{}}}async function We(e){let t={};for(let n of e){let e=await Ue(n);e.type!==void 0&&(t.type=e.type),e.port!==void 0&&(t.port=e.port),e.host!==void 0&&(t.host=e.host),e.keepAlive!==void 0&&(t.keepAlive=e.keepAlive)}return t}async function Ge(e,n){let r=g();if(e.id)return e.id;if(n.length>0)try{let t=await r.createConfigFetcherService({configSources:C(n),useCache:e.cache!==!1}).fetchConfiguration(e.cache===!1);if(t.id)return t.id}catch(e){throw Error(`Failed to resolve server ID from config '${n.join(`, `)}': ${Y(e)}`)}return t()}function Ke(e){if(!ze(e))throw Error(`Unknown transport type: '${e}'. Valid options: ${V}, ${H}, ${U}`);return e}function qe(e){if(!Be(e))throw Error(`Unknown proxy mode: '${String(e)}'. Valid options: meta, flat, search, group`)}function Je(e){return e===K?K:q}function Ye(e,t,n){let r=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0;return{mode:t,port:e.port??(Number.isFinite(r)?r:void 0)??n?.port,host:e.host??process.env.MCP_HOST??n?.host??B}}function Xe(){let e=(e,t)=>{t===void 0?console.error(e):console.error(e,t)};return{trace:e,debug:e,info:e,warn:e,error:e}}function Ze(e,t,n){return{configFilePath:t.length>0?t:void 0,noCache:e.cache===!1,serverId:n,definitionsCachePath:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode}}function Qe(e,t,n,r){let i=Y(r);return e===V?`Failed to start MCP server with transport '${e}': ${i}`:`Failed to start MCP server with transport '${e}' on ${n===void 0?`${t} (dynamic port)`:`${t}:${n}`}: ${i}`}function $e(e,t,n,r,i,a=q){return{serverId:e,host:t.host??B,port:n,transport:`http`,shutdownToken:r,startedAt:(/* @__PURE__ */ new Date()).toISOString(),pid:process.pid,configPath:i,runtimeLifecycle:a}}function et(){return new le(process.env.PORT_REGISTRY_PATH)}function X(){return process.env.NODE_ENV??`development`}async function tt(e,t,n,r,i,a,o=n===void 0?ce:{min:n,max:n}){let s=et(),c=await s.reservePort({repositoryPath:await J(),serviceName:e,serviceType:Fe,environment:X(),pid:process.pid,host:t,preferredPort:n,portRange:o,force:!0,metadata:{transport:i,serverId:r,...a?{configPath:a}:{}}});if(!c.success||!c.record){let e=n===void 0?`dynamic port`:`port ${n}`;throw Error(c.error||`Failed to reserve ${e} in port registry`)}let l=!1;return{port:c.record.port,release:async()=>{if(l)return;l=!0;let t=await s.releasePort({repositoryPath:await J(),serviceName:e,serviceType:Fe,pid:process.pid,environment:X(),force:!0});if(!t.success&&t.error&&!t.error.includes(`No matching registry entry`))throw Error(t.error||`Failed to release port for ${e}`)}}}async function nt(e){e&&await e.release()}function rt(e,t,n,r,i){return{serverId:e,shutdownToken:t,onShutdownRequested:n,runtimeLifecycle:r,idleShutdownMs:i}}async function Z(e,t){try{await e.remove(t)}catch(e){throw Error(`Failed to remove runtime state for '${t}': ${Y(e)}`)}}async function it(e,t){try{await e.write(t)}catch(e){throw Error(`Failed to persist runtime state for '${t.serverId}': ${Y(e)}`)}}async function at(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop owned HTTP transport '${n}': ${Y(e)}`)}}finally{await r?.release({kill:!1}),await Z(t,n)}}async function ot(e,t,n){await n?.release({kill:!1}),await Z(e,t)}async function st(e,t,n,r){try{try{await e.stop()}catch(e){throw Error(`Failed to stop HTTP transport during cleanup for '${n}': ${Y(e)}`)}}finally{await r?.release({kill:!1}),await Z(t,n)}}async function Q(e,t,n={}){try{await e.start()}catch(e){throw Error(`Failed to start transport handler: ${Y(e)}`)}let r=!1,i=async n=>{if(!r){r=!0,console.error(`\nReceived ${n}, shutting down gracefully...`);try{await e.stop(),t&&await t(),process.exit(0)}catch(e){console.error(`Failed to gracefully stop transport during ${n}: ${Y(e)}`),process.exit(1)}}};process.on(`SIGINT`,async()=>await i(`SIGINT`)),process.on(`SIGTERM`,async()=>await i(`SIGTERM`)),n.shutdownOnStdinClose&&(process.stdin.on(`end`,async()=>await i(`stdin end`)),process.stdin.on(`close`,async()=>await i(`stdin close`)))}async function ct(e,n,r,a){i();let c=r[0],l=await m(e),u=new s,d=re(),f=e.serverId??t(),p=Je(process.env.MCP_PROXY_RUNTIME_LIFECYCLE),h=n.port,g=h===void 0?ce:{min:h,max:h},_=await tt(W,n.host??B,h,f,H,c,g),y=_.port,b={...n,port:y},x=await ie({repositoryPath:await J(),serviceName:`mcp-proxy-http`,serviceType:`service`,environment:X(),host:b.host??B,port:y,command:process.argv[1],args:process.argv.slice(2),...ee()?{processGroupId:process.pid,terminationMode:`process-group`}:{terminationMode:`direct`},metadata:{transport:H,serverId:f,runtimeLifecycle:p,...c?{configPath:c}:{}}}),S=async()=>{await nt(_??null),S=async()=>void 0},C=$e(f,b,y,d,c,p),w,T=!1,te=async()=>{if(!T){T=!0;try{await at(w,u,C.serverId,x),await S(),await l.dispose(),process.exit(0)}catch(e){throw Error(`Failed to stop HTTP runtime '${C.serverId}' from admin shutdown: ${Y(e)}`)}}};try{let e=rt(C.serverId,d,te,p,a);w=new o(()=>v(l),b,e)}catch(e){throw await S(),await x.release({kill:!1}),await l.dispose(),Error(`Failed to create HTTP runtime server: ${Y(e)}`)}try{await Q(w,async()=>{await S(),await l.dispose(),await ot(u,C.serverId,x)}),await it(u,C)}catch(e){throw await S(),await l.dispose(),await st(w,u,C.serverId,x),Error(`Failed to start HTTP runtime '${C.serverId}': ${Y(e)}`)}console.error(`Runtime state: http://${C.host}:${C.port} (${C.serverId})`)}async function lt(e){let t;try{t=await h(e),await Q(new u(t,Xe()),async()=>{await t?.dispose?.()},{shutdownOnStdinClose:!0})}catch(e){throw await t?.dispose?.(),Error(`Failed to start stdio transport: ${Y(e)}`)}}async function ut(e){if(e)try{return(await new s().read(e))?.runtimeLifecycle}catch{return}}function dt(e){if(!e)return d;let t=Number.parseInt(e,10);return Number.isInteger(t)&&t>0?t:d}function ft(e,t){let n=k.resolveRegistryPath(process.env.PROCESS_REGISTRY_PATH),r=ne(`sha1`).update(`${ae(e)}|${t}`).digest(`hex`);return D(E(n),`mcp-proxy-runtime-${r.slice(0,16)}.lock`)}async function pt(e,t,n){if(e.port!==void 0)return{endpoint:new URL(`http://${e.host??B}:${e.port}${z}`),runtimeLifecycle:q};let r=await J(),i=dt(t.timeoutMs)+1e4;return await oe(ft(r,W),async()=>mt(r,e,t,n),{staleAfterMs:i,retryDelayMs:250,maxRetries:Math.ceil(i/250)})}async function mt(e,t,n,r){let i=await c(e);if(i){let e=t.host??i.host,n=i.serverId===`unknown`?void 0:i.serverId;return{endpoint:new URL(`http://${e}:${i.port}${z}`),runtimeServerId:n,runtimeLifecycle:i.runtimeLifecycle??await ut(n)??q}}let a=await S({host:t.host??B,config:r,cache:n.cache,definitionsCache:n.definitionsCache,clearDefinitionsCache:n.clearDefinitionsCache,proxyMode:n.proxyMode,runtimeLifecycle:K,idleShutdownMinutes:n.idleShutdownMinutes});return{endpoint:new URL(`http://${a.host}:${a.port}${z}`),runtimeServerId:a.serverId,runtimeLifecycle:a.runtimeLifecycle??q}}async function ht(e,t,n){let{endpoint:r}=await pt(e,t,n);return r}function gt(e){return`runtime:${e}`}async function _t(e){if(e.runtimeLifecycle===K&&e.runtimeServerId)return await ie({repositoryPath:await J(),serviceName:`mcp-proxy-stdio-http-bridge:${re()}`,serviceType:`tool`,environment:X(),pid:process.pid,command:process.argv[1],args:process.argv.slice(2),tags:[G,gt(e.runtimeServerId)],metadata:{transport:U,runtimeServerId:e.runtimeServerId,runtimeLifecycle:e.runtimeLifecycle,endpoint:e.endpoint.toString()},force:!1})}function vt(e){return e.pid===process.pid}async function yt(e){return await new k(process.env.PROCESS_REGISTRY_PATH).listProcesses({repositoryPath:await J(),serviceType:`tool`,tags:[G,gt(e)],environment:X(),liveOnly:!0})}async function bt(e){return(await yt(e)).filter(e=>!vt(e)).length>0?!1:(await new Promise(e=>setTimeout(e,500)),(await yt(e)).filter(e=>!vt(e)).length===0)}async function xt(t){if(t.runtimeLifecycle!==K||!t.runtimeServerId)return;let n=t.runtimeServerId,r=ft(await J(),W);try{await oe(r,async()=>{await bt(n)&&await new e().stop({serverId:n,force:!0})})}catch(e){console.error(`Failed to stop managed stdio-http runtime; leaving it alive: ${Y(e)}`)}}async function St(e,t,n,r){let i=t.autoDisconnect?!0:r?.keepAlive!==void 0&&!r.keepAlive,a,o;try{a=await pt(e,t,n),o=await _t(a);let{endpoint:r}=a;await Q(new b({endpoint:r,resolveEndpoint:async()=>await ht(e,t,n)},Xe()),async()=>{try{await o?.release({kill:!1,releasePort:!1})}catch(e){console.error(`Failed to release stdio-http bridge lease; leaving runtime alive: ${Y(e)}`);return}i&&a&&await xt(a)},{shutdownOnStdinClose:!0})}catch(e){try{await o?.release({kill:!1,releasePort:!1})}catch(t){throw Error(`Failed to start stdio-http transport: ${Y(e)}; also failed to release bridge lease: ${Y(t)}`)}throw Error(`Failed to start stdio-http transport: ${Y(e)}`)}}async function Ct(e,t,n,r,i){try{if(e===V){await lt(r);return}if(e===H){await ct(r,Ye(t,y.HTTP,i),n,Re(t.idleShutdownMinutes));return}await St(Ye(t,y.HTTP,i),t,n,i)}catch(t){throw Error(`Failed to start transport '${e}': ${Y(t)}`)}}async function wt(e,t){try{let n=await S({id:e.id,host:e.host??B,port:e.port,config:t,cache:e.cache,definitionsCache:e.definitionsCache,clearDefinitionsCache:e.clearDefinitionsCache,proxyMode:e.proxyMode,timeoutMs:e.timeoutMs,idleShutdownMinutes:e.idleShutdownMinutes});x(n)}catch(t){console.error(`Failed to prestart HTTP runtime '${e.id||`generated-server-id`}': ${Y(t)}`),process.exit(1)}}const Tt=new A(`mcp-serve`).description(`Start MCP server with specified transport or prestart the HTTP runtime in the background`).option(`-t, --type <type>`,`Transport type: ${V}, ${H}, or ${U}`).option(`-p, --port <port>`,`Port to listen on (http) or backend port for stdio-http`,e=>Number.parseInt(e,10)).option(`--host <host>`,`Host to bind to (http) or backend host for stdio-http`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`--no-cache`,`Disable configuration caching, always reload from config file`).option(`--definitions-cache <path>`,`Path to prefetched tool/prompt/skill definitions cache file`).option(`--clear-definitions-cache`,`Delete definitions cache before startup`,!1).option(`--proxy-mode <mode>`,`How mcp-proxy exposes downstream tools: meta, flat, search, or group`,`meta`).option(`--id <id>`,`Unique server identifier (overrides config file id, auto-generated if not provided)`).option(`--auto-disconnect`,`Stop the managed HTTP runtime when the last stdio-http bridge exits (default: keep runtime alive for reuse)`,!1).option(`--idle-shutdown-minutes <minutes>`,`Stop the HTTP runtime after N minutes with no MCP session and no request (0 disables; overrides ${Le})`,e=>Number.parseFloat(e)).option(`--prestart-http`,`Prestart the HTTP runtime in the background and exit after it becomes healthy`,!1).option(`--timeout-ms <ms>`,`How long to wait for the HTTP runtime to become healthy`,String(d)).action(async e=>{try{let t=a(e.config),n=t.length>0?null:await He(),r=n?[n]:t;if(e.prestartHttp){await wt(e,r);return}let i=await We(r),o=Ke((e.type??i.type??V).toLowerCase());qe(e.proxyMode),await Ct(o,e,r,Ze(e,r,await Ge(e,r)),i)}catch(t){let n=(e.type??V).toLowerCase(),r=ze(n)?n:V,i=process.env.MCP_PORT?Number(process.env.MCP_PORT):void 0,a=e.port??(Number.isFinite(i)?i:void 0);console.error(Qe(r,e.host??B,a,t)),process.exit(1)}}),Et=new A(`prefetch`).description(`Pre-download packages used by MCP servers (npx, pnpx, uvx, uv)`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-p, --parallel`,`Run prefetch commands in parallel`,!1).option(`-d, --dry-run`,`Show what would be prefetched without executing`,!1).option(`-f, --filter <type>`,`Filter by package manager type: npx, pnpx, uvx, or uv`).option(`--definitions-out <path>`,`Write discovered definitions to a JSON or YAML cache file`).option(`--skip-packages`,`Skip package prefetch and only build definitions cache`,!1).option(`--clear-definitions-cache`,`Delete the definitions cache file before continuing`,!1).action(async e=>{try{let r=g(),i=a(e.config),o=i.length>0?null:await n(),s=o?[o]:i;s.length===0&&(L.error(`No MCP configuration file found.`),L.info(`Use --config <path> to specify a config file, or run "po-mcp-proxy init" to create one.`),process.exit(1)),L.info(`Loading configuration from: ${s.join(`, `)}`);let c=await r.createConfigFetcherService({configSources:C(s),useCache:!1}).fetchConfiguration(!0),l=c.id||t(),u=p.generateConfigHash(c),d=e.definitionsOut||p.getDefaultCachePath(s),m=r.createPrefetchService({mcpConfig:c,filter:e.filter,parallel:e.parallel}),h=m.extractPackages(),_=!e.skipPackages,v=!!e.definitionsOut;if(e.clearDefinitionsCache&&(e.dryRun?L.info(`Would clear definitions cache: ${d}`):(await p.clearFile(d),L.success(`Cleared definitions cache: ${d}`))),_){if(h.length===0)L.warning(`No packages found to prefetch.`),L.info(`Prefetch supports: npx, pnpx, uvx, and uv run commands`);else{L.info(`Found ${h.length} package(s) to prefetch:`);for(let e of h)L.item(`${e.serverName}: ${e.packageManager} ${e.packageName}`)}}if(!_&&!v){L.warning(`Nothing to do. Use package prefetch or provide --definitions-out.`);return}if(e.dryRun){if(_&&h.length>0){L.newline(),L.header(`Dry run mode - commands that would be executed:`);for(let e of h)L.indent(e.fullCommand.join(` `))}v&&(L.newline(),L.info(`Would write definitions cache to: ${d}`));return}let y=!1;if(_&&h.length>0){L.newline(),L.info(`Prefetching packages...`);let e=await m.prefetch();if(L.newline(),e.failed===0?L.success(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`):L.warning(`Package prefetch complete: ${e.successful} succeeded, ${e.failed} failed`),e.failed>0){y=!0,L.newline(),L.error(`Failed packages:`);for(let t of e.results.filter(e=>!e.success))L.item(`${t.package.serverName} (${t.package.packageName}): ${t.output.trim()}`)}}if(v){L.newline(),L.info(`Collecting definitions cache...`);let e=await r.createClientManagerService(),t=c.skills?.paths||[],n=t.length>0?r.createSkillService(process.cwd(),t):void 0,i=r.createDefinitionsCacheService(e,n);await Promise.all(Object.entries(c.mcpServers).map(async([t,n])=>{try{await e.connectToServer(t,n),L.item(`Connected for definitions: ${t}`)}catch(e){L.warning(`Failed to connect for definitions: ${t} (${e instanceof Error?e.message:String(e)})`)}}));let a=await i.collectForCache({configPath:s[0],configHash:u,oneMcpVersion:f,serverId:l});await p.writeToFile(d,a),L.success(`Definitions cache written: ${d} (${Object.keys(a.servers).length} servers, ${a.skills.length} skills)`),a.failures.length>0&&L.warning(`Definitions cache completed with ${a.failures.length} server failure(s)`),await e.disconnectAll()}y&&process.exit(1)}catch(e){L.error(`Error executing prefetch: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}});function $(e){return e instanceof Error?e.message:String(e)}const Dt=new A(`read-resource`).description(`Read a resource by URI from a connected MCP server`).argument(`<uri>`,`Resource URI to read`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-s, --server <name>`,`Server name (required if resource exists on multiple servers)`).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{await M(t,async({clientManager:n})=>{let r=n.getAllClients();if(t.server){let r=n.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Reading ${e} from ${t.server}...`);let i=await r.readResource(e);if(t.json)console.log(JSON.stringify(i,null,2));else for(let e of i.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2));return}let i=await Promise.all(r.map(async t=>{try{let n=(await t.listResources()).some(t=>t.uri===e);return{serverName:t.serverName,hasResource:n,error:null}}catch(e){return{serverName:t.serverName,hasResource:!1,error:e}}})),a=[];for(let{serverName:e,hasResource:t,error:n}of i)n?console.error(`Failed to list resources from ${e}: ${$(n)}`):t&&a.push(e);if(a.length===0)throw Error(`Resource "${e}" not found on any connected server`);if(a.length>1)throw Error(`Resource "${e}" found on multiple servers: ${a.join(`, `)}. Use --server to disambiguate`);let o=a[0],s=n.getClient(o);if(!s)throw Error(`Internal error: Server "${o}" not connected`);t.json||console.error(`Reading ${e} from ${o}...`);let c=await s.readResource(e);if(t.json)console.log(JSON.stringify(c,null,2));else for(let e of c.contents)`text`in e?console.log(e.text):console.log(JSON.stringify(e,null,2))})}catch(e){console.error(`Error executing read-resource: ${$(e)}`),process.exit(1)}});function Ot(e){return e instanceof Error?e.message:String(e)}function kt(e){console.log(`Stopped mcp-proxy server '${e.serverId}'.`),console.log(`Endpoint: http://${e.host}:${e.port}`),console.log(`Result: ${e.message}`)}const At=new A(`stop`).description(`Stop a running HTTP mcp-proxy server`).option(`--id <id>`,`Target server ID from the runtime registry`).option(`--host <host>`,`Target runtime host`).option(`--port <port>`,`Target runtime port`,e=>Number.parseInt(e,10)).option(`-c, --config <path>`,`Reserved for future config-based targeting support`).option(`--token <token>`,`Override the persisted shutdown token`).option(`--force`,`Skip server ID verification against the /health response`,!1).option(`-j, --json`,`Output as JSON`,!1).option(`--timeout <ms>`,`Maximum time to wait for shutdown completion`,e=>Number.parseInt(e,10),5e3).action(async e=>{try{e.config&&console.error(`Warning: --config is not used yet; runtime resolution uses the persisted registry.`);let t=await g().createStopServerService().stop({serverId:e.id,host:e.host,port:e.port,token:e.token,force:e.force,timeoutMs:e.timeout});if(e.json){console.log(JSON.stringify(t,null,2));return}kt(t)}catch(t){let n=`Error executing stop: ${Ot(t)}`;e.json?console.log(JSON.stringify({ok:!1,error:n},null,2)):console.error(n),process.exit(1)}});function jt(e){return e instanceof Error?e.message:String(e)}const Mt=new A(`use-tool`).description(`Execute an MCP tool with arguments`).argument(`<toolName>`,`Tool name to execute`).option(`-c, --config <path>`,`Path to MCP server configuration file (repeatable; later files override earlier ones)`,r).option(`-s, --server <name>`,`Server name (required if tool exists on multiple servers)`).option(`-a, --args <json>`,`Tool arguments as JSON string`,`{}`).option(`-t, --timeout <ms>`,`Request timeout in milliseconds for tool execution (default: 60000)`,Number.parseInt).option(`-j, --json`,`Output as JSON`,!1).action(async(e,t)=>{try{let n={};try{n=JSON.parse(t.args)}catch{console.error(`Error: Invalid JSON in --args`),process.exit(1)}await M(t,async({container:r,config:i,clientManager:a})=>{let o=a.getAllClients();if(t.server){let r=a.getClient(t.server);if(!r)throw Error(`Server "${t.server}" not found`);t.json||console.error(`Executing ${e} on ${t.server}...`);let i=t.timeout?{timeout:t.timeout}:void 0,o=await r.callTool(e,n,i);if(t.json)console.log(JSON.stringify(o,null,2));else{if(console.log(`
142
142
  Result:`),o.content)for(let e of o.content)e.type===`text`?console.log(e.text):console.log(JSON.stringify(e,null,2));o.isError&&(console.error(`
143
143
  ⚠️ Tool execution returned an error`),process.exit(1))}return}let s=await Promise.all(o.map(async t=>{try{let n=(await t.listTools()).some(t=>t.name===e);return{serverName:t.serverName,hasTool:n,error:null}}catch(e){return{serverName:t.serverName,hasTool:!1,error:e}}})),c=[];for(let{serverName:e,hasTool:n,error:r}of s)r?t.json||console.error(`Failed to list tools from ${e}:`,r):n&&c.push(e);if(c.length===0){let n=i.skills?.paths||[];if(n.length>0)try{let i=process.env.PROJECT_PATH||process.cwd(),a=r.createSkillService(i,n),o=e.startsWith(`skill__`)?e.slice(7):e,s=await a.getSkill(o);if(s){let e={content:[{type:`text`,text:s.content}]};t.json?console.log(JSON.stringify(e,null,2)):(console.log(`
144
144
  Skill content:`),console.log(s.content));return}}catch(n){t.json||console.error(`Failed to lookup skill "${e}":`,n)}throw Error(`Tool or skill "${e}" not found on any connected server or configured skill paths`)}if(c.length>1)throw Error(`Tool "${e}" found on multiple servers: ${c.join(`, `)}`);let l=c[0],u=a.getClient(l);if(!u)throw Error(`Internal error: Server "${l}" not connected`);t.json||console.error(`Executing ${e} on ${l}...`);let d=t.timeout?{timeout:t.timeout}:void 0,f=await u.callTool(e,n,d);if(t.json)console.log(JSON.stringify(f,null,2));else{if(console.log(`
145
145
  Result:`),f.content)for(let e of f.content)e.type===`text`?console.log(e.text):console.log(JSON.stringify(e,null,2));f.isError&&(console.error(`
146
- ⚠️ Tool execution returned an error`),process.exit(1))}})}catch(e){console.error(`Error executing use-tool: ${jt(e)}`),process.exit(1)}});async function Nt(){try{let e=new A;e.name(`po-mcp-proxy`).description(`MCP proxy server package`).version(p),e.addCommand(De),e.addCommand(Tt),e.addCommand(Ne),e.addCommand(Ce),e.addCommand(Mt),e.addCommand(Ae),e.addCommand(Dt),e.addCommand(Oe),e.addCommand(we),e.addCommand(Et),e.addCommand(At),e.addCommand(ve),await e.parseAsync(process.argv)}catch(e){console.error(`CLI execution failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}Nt().catch(e=>{console.error(`Fatal error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});export{};
146
+ ⚠️ Tool execution returned an error`),process.exit(1))}})}catch(e){console.error(`Error executing use-tool: ${jt(e)}`),process.exit(1)}});async function Nt(){try{let e=new A;e.name(`po-mcp-proxy`).description(`MCP proxy server package`).version(f),e.addCommand(De),e.addCommand(Tt),e.addCommand(Ne),e.addCommand(Ce),e.addCommand(Mt),e.addCommand(Ae),e.addCommand(Dt),e.addCommand(Oe),e.addCommand(we),e.addCommand(Et),e.addCommand(At),e.addCommand(ve),await e.parseAsync(process.argv)}catch(e){console.error(`CLI execution failed: ${e instanceof Error?e.message:String(e)}`),process.exit(1)}}Nt().catch(e=>{console.error(`Fatal error: ${e instanceof Error?e.message:String(e)}`),process.exit(1)});export{};
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src-7ZMUtqrH.cjs");exports.CALLBACK_BIND_WAIT_MS=e.Y,exports.CALLBACK_POLL_INTERVAL_MS=e.X,exports.CALLBACK_PORT_SPAN=e.Z,exports.CALLBACK_TIMEOUT_MS=e.Q,exports.CallbackRendezvous=e.st,exports.ConfigFetcherService=e.R,exports.DEFAULT_CALLBACK_PATH=e.$,exports.DEFAULT_CALLBACK_PORT=e.et,exports.DEFAULT_HTTP_RUNTIME_TIMEOUT_MS=e.g,exports.DefinitionsCacheService=e.j,exports.DescribeToolsTool=e.m,exports.FileTokenStore=e.W,exports.HttpTransportHandler=e.S,exports.McpClientManagerService=e.E,exports.McpOAuthProvider=e.J,exports.MemoryTokenStore=e.G,exports.OAuthCallbackServer=e.tt,exports.OutputGuardService=e.O,exports.RESERVATION_STALE_MS=e.ct,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.acquireSharedCallbackServer=e.nt,exports.cleanupStaleRegistries=e.M,exports.closeSharedCallbackServer=e.rt,exports.collectConfigPath=e.F,exports.createHttpTransportHandler=e.i,exports.createOAuthProvider=e.B,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.P,exports.findHealthyExistingRuntime=e._,exports.generateServerId=e.N,exports.getDefaultRendezvousRoot=e.lt,exports.getDefaultTokenStoreDir=e.K,exports.getSharedCallbackServer=e.it,exports.initializeSharedServices=e.l,exports.isAuthError=e.D,exports.parseMcpConfig=e.z,exports.prestartHttpRuntime=e.y,exports.probeRuntimeHealth=e.b,exports.readAuthEntryForUrl=e.q,exports.releaseSharedCallbackServer=e.at,exports.resolveAuthScheme=e.V,exports.resolveBearerToken=e.H,exports.resolveCallbackPort=e.U,exports.resolveOutputGuardOptions=e.k,exports.resolveWorkspaceRoot=e.ut,exports.toConfigPaths=e.I,exports.toConfigSources=e.L,exports.workspaceCallbackPort=e.ot;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./src-1iVj1fH_.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;