@agimon-ai/mcp-proxy 0.10.5 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,27 +1 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_src = require("./src-Bf27zWoI.cjs");
3
- exports.ConfigFetcherService = require_src.ConfigFetcherService;
4
- exports.DefinitionsCacheService = require_src.DefinitionsCacheService;
5
- exports.DescribeToolsTool = require_src.DescribeToolsTool;
6
- exports.HttpTransportHandler = require_src.HttpTransportHandler;
7
- exports.McpClientManagerService = require_src.McpClientManagerService;
8
- exports.RuntimeStateService = require_src.RuntimeStateService;
9
- exports.SearchListToolsTool = require_src.SearchListToolsTool;
10
- exports.SkillService = require_src.SkillService;
11
- exports.SseTransportHandler = require_src.SseTransportHandler;
12
- exports.StdioHttpTransportHandler = require_src.StdioHttpTransportHandler;
13
- exports.StdioTransportHandler = require_src.StdioTransportHandler;
14
- exports.StopServerService = require_src.StopServerService;
15
- exports.TRANSPORT_MODE = require_src.TRANSPORT_MODE;
16
- exports.UseToolTool = require_src.UseToolTool;
17
- exports.createHttpTransportHandler = require_src.createHttpTransportHandler;
18
- exports.createProxyContainer = require_src.createProxyContainer;
19
- exports.createProxyLogger = require_src.createProxyLogger;
20
- exports.createServer = require_src.createServer;
21
- exports.createSessionServer = require_src.createSessionServer;
22
- exports.createSseTransportHandler = require_src.createSseTransportHandler;
23
- exports.createStdioHttpTransportHandler = require_src.createStdioHttpTransportHandler;
24
- exports.createStdioTransportHandler = require_src.createStdioTransportHandler;
25
- exports.findConfigFile = require_src.findConfigFile;
26
- exports.generateServerId = require_src.generateServerId;
27
- exports.initializeSharedServices = require_src.initializeSharedServices;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require(`./src-CLGPFgYD.cjs`);exports.ConfigFetcherService=e.E,exports.DefinitionsCacheService=e.C,exports.DescribeToolsTool=e._,exports.HttpTransportHandler=e.m,exports.McpClientManagerService=e.x,exports.RuntimeStateService=e.b,exports.SearchListToolsTool=e.g,exports.SkillService=e.y,exports.SseTransportHandler=e.p,exports.StdioHttpTransportHandler=e.d,exports.StdioTransportHandler=e.f,exports.StopServerService=e.v,exports.TRANSPORT_MODE=e.t,exports.UseToolTool=e.h,exports.createHttpTransportHandler=e.i,exports.createProxyContainer=e.a,exports.createProxyLogger=e.S,exports.createServer=e.n,exports.createSessionServer=e.r,exports.createSseTransportHandler=e.s,exports.createStdioHttpTransportHandler=e.c,exports.createStdioTransportHandler=e.l,exports.findConfigFile=e.T,exports.generateServerId=e.w,exports.initializeSharedServices=e.u;
package/dist/index.mjs CHANGED
@@ -1,2 +1 @@
1
- import { C as DefinitionsCacheService, E as ConfigFetcherService, S as createProxyLogger, T as findConfigFile, _ as DescribeToolsTool, a as createProxyContainer, b as RuntimeStateService, c as createStdioHttpTransportHandler, d as StdioHttpTransportHandler, f as StdioTransportHandler, g as SearchListToolsTool, h as UseToolTool, i as createHttpTransportHandler, l as createStdioTransportHandler, m as HttpTransportHandler, n as createServer, p as SseTransportHandler, r as createSessionServer, s as createSseTransportHandler, t as TRANSPORT_MODE, u as initializeSharedServices, v as StopServerService, w as generateServerId, x as McpClientManagerService, y as SkillService } from "./src-Dv4pMmyW.mjs";
2
- export { ConfigFetcherService, DefinitionsCacheService, DescribeToolsTool, HttpTransportHandler, McpClientManagerService, RuntimeStateService, SearchListToolsTool, SkillService, SseTransportHandler, StdioHttpTransportHandler, StdioTransportHandler, StopServerService, TRANSPORT_MODE, UseToolTool, createHttpTransportHandler, createProxyContainer, createProxyLogger, createServer, createSessionServer, createSseTransportHandler, createStdioHttpTransportHandler, createStdioTransportHandler, findConfigFile, generateServerId, initializeSharedServices };
1
+ import{C as e,E as t,S as n,T as r,_ as i,a,b as o,c as s,d as c,f as l,g as u,h as d,i as f,l as p,m,n as h,p as g,r as _,s as v,t as y,u as b,v as x,w as S,x as C,y as w}from"./src-CK3NGPwW.mjs";export{t as ConfigFetcherService,e as DefinitionsCacheService,i as DescribeToolsTool,m as HttpTransportHandler,C as McpClientManagerService,o as RuntimeStateService,u as SearchListToolsTool,w as SkillService,g as SseTransportHandler,c as StdioHttpTransportHandler,l as StdioTransportHandler,x as StopServerService,y as TRANSPORT_MODE,d as UseToolTool,f as createHttpTransportHandler,a as createProxyContainer,n as createProxyLogger,h as createServer,_ as createSessionServer,v as createSseTransportHandler,s as createStdioHttpTransportHandler,p as createStdioTransportHandler,r as findConfigFile,S as generateServerId,b as initializeSharedServices};
@@ -0,0 +1,59 @@
1
+ import{existsSync as e}from"node:fs";import{access as t,mkdir as n,readFile as r,readdir as i,rm as a,stat as o,unlink as s,watch as c,writeFile as l}from"node:fs/promises";import u from"js-yaml";import{z as d}from"zod";import{createHash as f,randomBytes as p,randomUUID as m}from"node:crypto";import{homedir as h,tmpdir as g}from"node:os";import{dirname as _,isAbsolute as v,join as y,resolve as b}from"node:path";import{createNodeTelemetry as ee}from"@agimon-ai/log-sink-mcp";import{Client as x}from"@modelcontextprotocol/sdk/client/index.js";import{SSEClientTransport as te}from"@modelcontextprotocol/sdk/client/sse.js";import{StdioClientTransport as ne}from"@modelcontextprotocol/sdk/client/stdio.js";import{StreamableHTTPClientTransport as re}from"@modelcontextprotocol/sdk/client/streamableHttp.js";import{createProcessLease as ie}from"@agimon-ai/foundation-process-registry";import{spawn as ae}from"node:child_process";import{Liquid as oe}from"liquidjs";import{coerceArgs as se,formatZodError as ce,jsonSchemaToZod as le}from"@agimon-ai/foundation-validator";import{once as ue}from"node:events";import{createServer as de}from"node:http";import{promisify as fe}from"node:util";import{getRequestListener as pe}from"@hono/node-server";import{StreamableHTTPServerTransport as me}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{CallToolRequestSchema as he,ElicitRequestSchema as ge,GetPromptRequestSchema as _e,ListPromptsRequestSchema as ve,ListResourcesRequestSchema as ye,ListToolsRequestSchema as be,ReadResourceRequestSchema as xe,isInitializeRequest as Se}from"@modelcontextprotocol/sdk/types.js";import{Hono as Ce}from"hono";import{SSEServerTransport as we}from"@modelcontextprotocol/sdk/server/sse.js";import{StdioServerTransport as Te}from"@modelcontextprotocol/sdk/server/stdio.js";import{Server as Ee}from"@modelcontextprotocol/sdk/server/index.js";var S=`0.10.5`;function C(e){return e.replace(/\$\{([^}]+)\}/g,(e,t)=>{let n=process.env[t];return n===void 0?(console.warn(`Environment variable ${t} is not defined, keeping placeholder`),`\${${t}}`):n})}function w(e){if(typeof e==`string`)return C(e);if(Array.isArray(e))return e.map(e=>w(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=w(r);return t}return e}const De=[/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\./,/^224\./,/^240\./,/^localhost$/i,/^.*\.localhost$/i,/^\[::\]/,/^\[::1\]/,/^\[0:0:0:0:0:0:0:1\]/,/^\[0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:1\]/i,/^\[fe80:/i,/^\[fc00:/i,/^\[fd00:/i,/^\[::ffff:127\./i,/^\[::ffff:7f[0-9a-f]{2}:/i,/^\[::ffff:10\./i,/^\[::ffff:a[0-9a-f]{2}:/i,/^\[::ffff:172\.(1[6-9]|2\d|3[01])\./i,/^\[::ffff:ac1[0-9a-f]:/i,/^\[::ffff:192\.168\./i,/^\[::ffff:c0a8:/i,/^\[::ffff:169\.254\./i,/^\[::ffff:a9fe:/i,/^\[::ffff:0\./i,/^\[::127\./i,/^\[::7f[0-9a-f]{2}:/i,/^\[::10\./i,/^\[::a[0-9a-f]{2}:/i,/^\[::192\.168\./i,/^\[::c0a8:/i];function Oe(e,t){let n=t?.allowPrivateIPs??!1,r=t?.enforceHttps??!0,i;try{i=new URL(e)}catch{throw Error(`Invalid URL format: ${e}`)}let a=i.protocol.replace(`:`,``);if(r&&a!==`https`)throw Error(`HTTPS is required for security. URL uses '${a}://'. Set security.enforceHttps: false to allow HTTP.`);if(a!==`http`&&a!==`https`)throw Error(`Invalid URL protocol '${a}://'. Only http:// and https:// are allowed.`);if(!n){let e=i.hostname.toLowerCase();if(De.some(t=>t.test(e)))throw Error(`Private IP addresses and localhost are blocked for security (${e}). Set security.allowPrivateIPs: true to allow internal networks.`)}}function ke(e){let t=C(e.url);if(Oe(t,e.security),e.validation){if(e.validation.url&&!new RegExp(e.validation.url).test(t))throw Error(`Remote config URL "${t}" does not match validation pattern: ${e.validation.url}`);if(e.validation.headers&&Object.keys(e.validation.headers).length>0){if(!e.headers){let t=Object.keys(e.validation.headers);throw Error(`Remote config is missing required headers: ${t.join(`, `)}`)}for(let[t,n]of Object.entries(e.validation.headers)){if(!(t in e.headers))throw Error(`Remote config is missing required header: ${t}`);let r=C(e.headers[t]);if(!new RegExp(n).test(r))throw Error(`Remote config header "${t}" value "${r}" does not match validation pattern: ${n}`)}}}}const Ae=d.object({name:d.string(),description:d.string(),folder:d.string().optional()}),je=d.object({skill:Ae.optional()}),T=d.object({instruction:d.string().optional(),toolBlacklist:d.array(d.string()).optional(),omitToolDescription:d.boolean().optional(),prompts:d.record(d.string(),je).optional()}).optional(),Me=d.object({command:d.string(),args:d.array(d.string()).optional(),env:d.record(d.string(),d.string()).optional(),disabled:d.boolean().optional(),instruction:d.string().optional(),timeout:d.number().positive().optional(),requestTimeout:d.number().positive().optional(),config:T}),Ne=d.object({url:d.string().url(),headers:d.record(d.string(),d.string()).optional(),type:d.enum([`http`,`sse`]).optional(),disabled:d.boolean().optional(),instruction:d.string().optional(),timeout:d.number().positive().optional(),requestTimeout:d.number().positive().optional(),config:T}),Pe=d.union([Me,Ne]),Fe=d.object({url:d.string().optional(),headers:d.record(d.string(),d.string()).optional()}).optional(),Ie=d.object({allowPrivateIPs:d.boolean().optional(),enforceHttps:d.boolean().optional()}).optional(),Le=d.object({url:d.string(),headers:d.record(d.string(),d.string()).optional(),validation:Fe,security:Ie,mergeStrategy:d.enum([`local-priority`,`remote-priority`,`merge-deep`]).optional()}),E=d.object({paths:d.array(d.string())}),D=d.object({type:d.enum([`stdio`,`http`,`sse`,`stdio-http`]).optional(),port:d.number().int().positive().optional(),host:d.string().optional(),keepAlive:d.boolean().optional()}).optional(),Re=d.object({id:d.string().optional(),proxy:D,mcpServers:d.record(d.string(),Pe),remoteConfigs:d.array(Le).optional(),skills:E.optional()}),ze=d.object({command:d.string(),args:d.array(d.string()).optional(),env:d.record(d.string(),d.string()).optional()}),Be=d.object({url:d.string().url(),headers:d.record(d.string(),d.string()).optional()}),Ve=d.object({url:d.string().url(),headers:d.record(d.string(),d.string()).optional()}),He=d.object({name:d.string(),description:d.string(),folder:d.string().optional()}),O=d.object({skill:He.optional()}),Ue=d.discriminatedUnion(`transport`,[d.object({name:d.string(),instruction:d.string().optional(),toolBlacklist:d.array(d.string()).optional(),omitToolDescription:d.boolean().optional(),prompts:d.record(d.string(),O).optional(),timeout:d.number().positive().optional(),requestTimeout:d.number().positive().optional(),transport:d.literal(`stdio`),config:ze}),d.object({name:d.string(),instruction:d.string().optional(),toolBlacklist:d.array(d.string()).optional(),omitToolDescription:d.boolean().optional(),prompts:d.record(d.string(),O).optional(),timeout:d.number().positive().optional(),requestTimeout:d.number().positive().optional(),transport:d.literal(`http`),config:Be}),d.object({name:d.string(),instruction:d.string().optional(),toolBlacklist:d.array(d.string()).optional(),omitToolDescription:d.boolean().optional(),prompts:d.record(d.string(),O).optional(),timeout:d.number().positive().optional(),requestTimeout:d.number().positive().optional(),transport:d.literal(`sse`),config:Ve})]),We=d.object({id:d.string().optional(),proxy:D,mcpServers:d.record(d.string(),Ue),skills:E.optional()});function Ge(e){let t={};for(let[n,r]of Object.entries(e.mcpServers))if(!(`disabled`in r&&r.disabled===!0)){if(`command`in r){let e=r,i=C(e.command),a=e.args?.map(e=>C(e)),o=e.env?w(e.env):void 0;t[n]={name:n,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:`stdio`,config:{command:i,args:a,env:o}}}else if(`url`in r){let e=r,i=e.type===`sse`?`sse`:`http`,a=C(e.url),o=e.headers?w(e.headers):void 0;t[n]={name:n,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:i,config:{url:a,headers:o}}}}return{id:e.id,proxy:e.proxy,mcpServers:t,skills:e.skills}}function k(e){let t=Ge(Re.parse(e));return We.parse(t)}var Ke=class{cacheDir;cacheTTL;readEnabled;writeEnabled;logger;constructor(e,t=console){this.cacheDir=y(g(),`mcp-proxy-cache`,`remote-configs`),this.cacheTTL=e?.ttl||3600*1e3,this.readEnabled=e?.readEnabled===void 0?!0:e.readEnabled,this.writeEnabled=e?.writeEnabled===void 0?!0:e.writeEnabled,this.logger=t}generateCacheKey(e){return f(`sha256`).update(e).digest(`hex`)}getCacheFilePath(e){return y(this.cacheDir,`${e}.json`)}async ensureCacheDir(){try{await n(this.cacheDir,{recursive:!0})}catch(e){if(e?.code!==`EEXIST`)throw e}}async get(t){if(!this.readEnabled)return null;try{await this.ensureCacheDir();let n=this.generateCacheKey(t),i=this.getCacheFilePath(n);if(!e(i))return null;let a=await r(i,`utf-8`),o=JSON.parse(a),c=Date.now();if(c>o.expiresAt)return await s(i).catch(()=>{}),null;let l=Math.round((o.expiresAt-c)/1e3);return this.logger.debug(`Remote config cache hit for ${t} (expires in ${l}s)`),o.data}catch(e){return this.logger.warn(`Failed to read remote config cache for ${t}`,e),null}}async set(e,t){if(this.writeEnabled)try{await this.ensureCacheDir();let n=this.generateCacheKey(e),r=this.getCacheFilePath(n),i=Date.now(),a={data:t,timestamp:i,expiresAt:i+this.cacheTTL,url:e};await l(r,JSON.stringify(a,null,2),`utf-8`),this.logger.debug(`Cached remote config for ${e} (TTL: ${Math.round(this.cacheTTL/1e3)}s)`)}catch(t){this.logger.warn(`Failed to write remote config cache for ${e}`,t)}}async clear(t){try{let n=this.generateCacheKey(t),r=this.getCacheFilePath(n);e(r)&&(await s(r),this.logger.info(`Cleared remote config cache for ${t}`))}catch(e){this.logger.warn(`Failed to clear remote config cache for ${t}`,e)}}async clearAll(){try{if(!e(this.cacheDir))return;let t=await i(this.cacheDir),n=t.filter(e=>e.endsWith(`.json`)).map(e=>s(y(this.cacheDir,e)).catch(t=>{this.logger.debug(`Failed to delete remote config cache file ${e}`,t)}));await Promise.all(n),this.logger.info(`Cleared all remote config cache entries (${t.length} files)`)}catch(e){this.logger.warn(`Failed to clear all remote config cache`,e)}}async cleanExpired(){try{if(!e(this.cacheDir))return;let t=Date.now(),n=(await i(this.cacheDir)).filter(e=>e.endsWith(`.json`)),a=(await Promise.all(n.map(async e=>{let n=y(this.cacheDir,e);try{let e=await r(n,`utf-8`);return t>JSON.parse(e).expiresAt?(await s(n),!0):!1}catch(e){return await s(n).catch(()=>{this.logger.debug(`Failed to delete corrupt cache file ${n}`,e)}),this.logger.warn(`Removed unreadable remote config cache file ${n}`,e),!0}}))).filter(Boolean).length;a>0&&this.logger.info(`Cleaned up ${a} expired remote config cache entries`)}catch(e){this.logger.warn(`Failed to clean expired remote config cache`,e)}}async getStats(){try{if(!e(this.cacheDir))return{totalEntries:0,totalSize:0};let t=(await i(this.cacheDir)).filter(e=>e.endsWith(`.json`)),n=(await Promise.all(t.map(async e=>{let t=y(this.cacheDir,e);try{let e=await r(t,`utf-8`);return Buffer.byteLength(e,`utf-8`)}catch{return 0}}))).reduce((e,t)=>e+t,0);return{totalEntries:t.length,totalSize:n}}catch(e){return this.logger.warn(`Failed to get remote config cache stats`,e),{totalEntries:0,totalSize:0}}}isReadEnabled(){return this.readEnabled}isWriteEnabled(){return this.writeEnabled}setReadEnabled(e){this.readEnabled=e}setWriteEnabled(e){this.writeEnabled=e}},qe=class{configFilePath;cacheTtlMs;cachedConfig=null;lastFetchTime=0;remoteConfigCache;logger;constructor(e,t=console){this.configFilePath=e.configFilePath,this.cacheTtlMs=e.cacheTtlMs||6e4,this.logger=t;let n=e.useCache===void 0?!0:e.useCache;if(this.remoteConfigCache=new Ke({ttl:e.remoteCacheTtlMs||3600*1e3,readEnabled:n,writeEnabled:!0},t),!this.configFilePath)throw Error(`configFilePath must be provided`)}async fetchConfiguration(e=!1){let t=Date.now();if(!e&&this.cachedConfig&&t-this.lastFetchTime<this.cacheTtlMs)return this.cachedConfig;let n=await this.loadRawConfigFromFile(),r=n.remoteConfigs||[],i=await this.parseConfig(n),a=r.map(async e=>{try{return ke(e),{config:await this.loadFromUrl(e),mergeStrategy:e.mergeStrategy||`local-priority`,url:e.url}}catch(t){return this.logger.warn(`Failed to fetch remote config from ${e.url}`,t),null}}),o=await Promise.all(a);for(let e of o)e!==null&&(i=this.mergeConfigurations(i,e.config,e.mergeStrategy));if(!i.mcpServers||typeof i.mcpServers!=`object`)throw Error(`Invalid MCP configuration: missing or invalid mcpServers`);return this.cachedConfig=i,this.lastFetchTime=t,i}async loadRawConfigFromFile(){if(!this.configFilePath)throw Error(`No config file path provided`);if(!e(this.configFilePath))throw Error(`Config file not found: ${this.configFilePath}`);try{let e=await r(this.configFilePath,`utf-8`),t;return t=this.configFilePath.endsWith(`.yaml`)||this.configFilePath.endsWith(`.yml`)?u.load(e):JSON.parse(e),t}catch(e){throw e instanceof Error?Error(`Failed to load config file: ${e.message}`):Error(`Failed to load config file: Unknown error`)}}async parseConfig(e){try{let{remoteConfigs:t,...n}=e;return k(n)}catch(e){throw e instanceof Error?Error(`Failed to parse config: ${e.message}`):Error(`Failed to parse config: Unknown error`)}}async loadFromUrl(e){try{let t=this.interpolateEnvVars(e.url),n=await this.remoteConfigCache.get(t);if(n)return n;let r=e.headers?Object.fromEntries(Object.entries(e.headers).map(([e,t])=>[e,this.interpolateEnvVars(t)])):{},i=await fetch(t,{headers:r,signal:AbortSignal.timeout(3e4)});if(!i.ok)throw Error(`Failed to fetch remote config: ${i.status} ${i.statusText}`);let a=k(await i.json());return await this.remoteConfigCache.set(t,a),a}catch(t){throw t instanceof Error?Error(`Failed to fetch remote config from ${e.url}: ${t.message}`,{cause:t}):Error(`Failed to fetch remote config from ${e.url}: Unknown error`)}}interpolateEnvVars(e){return e.replace(/\$\{([^}]+)\}/g,(e,t)=>{let n=process.env[t];return n===void 0?(this.logger.warn(`Environment variable ${t} is not defined, keeping placeholder`),`\${${t}}`):n})}mergeConfigurations(e,t,n){switch(n){case`local-priority`:return{id:e.id??t.id,mcpServers:{...t.mcpServers,...e.mcpServers},skills:e.skills??t.skills};case`remote-priority`:return{id:t.id??e.id,mcpServers:{...e.mcpServers,...t.mcpServers},skills:t.skills??e.skills};case`merge-deep`:{let n={...t.mcpServers};for(let[t,r]of Object.entries(e.mcpServers))if(n[t]){let e=n[t],i={...e.config,...r.config},a=`env`in e.config?e.config.env:void 0,o=`env`in r.config?r.config.env:void 0;(a||o)&&(i.env={...a||{},...o||{}});let s=`headers`in e.config?e.config.headers:void 0,c=`headers`in r.config?r.config.headers:void 0;(s||c)&&(i.headers={...s||{},...c||{}}),n[t]={...e,...r,config:i}}else n[t]=r;return{id:e.id??t.id,mcpServers:n,skills:e.skills??t.skills}}default:throw Error(`Unknown merge strategy: ${n}`)}}clearCache(){this.cachedConfig=null,this.lastFetchTime=0}isCacheValid(){let e=Date.now();return this.cachedConfig!==null&&e-this.lastFetchTime<this.cacheTtlMs}};const Je=`[skill-detection]`;function Ye(){let t=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],n=process.env.PROJECT_PATH;if(n)for(let r of t){let t=b(n,r);if(e(t))return t}let r=process.cwd();for(let n=0;n<=3;n++){for(let n of t){let t=y(r,n);if(e(t))return t}let n=_(r);if(n===r)break;r=n}return null}function Xe(e=6){let t=``,n=e;for(;n>0;){let e=p(n);for(let r=0;r<e.length&&n>0;r++){let i=e[r];i>247||(t+=`23456789abcdefghjkmnpqrstuvwxyz`[i%31],n--)}}return t}function Ze(e){let t=e.trimStart();if(!t.startsWith(`---`))return{frontMatter:null,content:e};let n=t.indexOf(`
2
+ ---`,3);if(n===-1)return{frontMatter:null,content:e};let r=t.slice(4,n).trim();if(!r)return{frontMatter:null,content:e};let i={},a=r.split(`
3
+ `),o=null,s=[],c=null,l=0,u=()=>{o&&s.length>0&&(c===`literal`?i[o]=s.join(`
4
+ `).trimEnd():c===`folded`?i[o]=s.join(` `).trim():i[o]=s.join(``).trim()),o=null,s=[],c=null,l=0};for(let e=0;e<a.length;e++){let t=a[e],n=t.trim(),r=t.indexOf(`:`);if(r!==-1&&!t.startsWith(` `)&&!t.startsWith(` `)){u();let n=t.slice(0,r).trim(),s=t.slice(r+1).trim();if(s===`|`||s===`|-`){if(o=n,c=`literal`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else if(s===`>`||s===`>-`){if(o=n,c=`folded`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else (s.startsWith(`"`)&&s.endsWith(`"`)||s.startsWith(`'`)&&s.endsWith(`'`))&&(s=s.slice(1,-1)),n&&s&&(i[n]=s)}else if(c&&o){let e=t.match(/^(\s*)/)?.[1].length||0;if(n===``)s.push(``);else if(e>=l){let e=t.slice(l);s.push(e)}else u()}}return u(),{frontMatter:i,content:t.slice(n+4).trimStart()}}function Qe(e){return e!==null&&typeof e.name==`string`&&e.name.length>0&&typeof e.description==`string`&&e.description.length>0}function $e(e){let{frontMatter:t,content:n}=Ze(e);return t&&Qe(t)?{skill:{name:t.name,description:t.description},content:n}:null}function A(e){let t=e.indexOf(`__`);return t>0?{serverName:e.substring(0,t),actualToolName:e.substring(t+2)}:{actualToolName:e}}function et(e){return e.endsWith(`.yaml`)||e.endsWith(`.yml`)}function j(e){return e instanceof Error?e.message:String(e)}function tt(e){let t=b(e),n=t.length>=2&&t[1]===`:`&&(t[0]>=`A`&&t[0]<=`Z`||t[0]>=`a`&&t[0]<=`z`)?`${t[0].toLowerCase()}${t.slice(1)}`:t,r=``,i=!1;for(let e of n){if(e>=`a`&&e<=`z`||e>=`A`&&e<=`Z`||e>=`0`&&e<=`9`||e===`.`||e===`_`||e===`-`){r+=e,i=!1;continue}i||=(r+=`_`,!0)}let a=0,o=r.length;for(;a<o&&r[a]===`_`;)a+=1;for(;o>a&&r[o-1]===`_`;)--o;return r.slice(a,o)}function M(e){return{...e,failures:[...e.failures??[]],skills:(e.skills??[]).map(e=>({...e})),servers:Object.fromEntries(Object.entries(e.servers).map(([e,t])=>[e,{...t,tools:(t.tools??[]).map(e=>({...e})),resources:(t.resources??[]).map(e=>({...e})),prompts:(t.prompts??[]).map(e=>({...e,arguments:e.arguments?.map(e=>({...e}))})),promptSkills:(t.promptSkills??[]).map(e=>({...e,skill:{...e.skill}}))}]))}}var N=class{clientManager;skillService;cacheData;liveDefinitionsPromise=null;mergedDefinitionsPromise=null;logger;constructor(e,t,n,r=console){this.clientManager=e,this.skillService=t,this.cacheData=n?.cacheData,this.logger=r}static async readFromFile(e){let t=await r(e,`utf-8`),n=et(e)?u.load(t):JSON.parse(t);if(!n||typeof n!=`object`)throw Error(`Definitions cache must be an object`);let i=n;if(i.version!==1||!i.servers)throw Error(`Definitions cache is missing required fields`);return{...i,failures:Array.isArray(i.failures)?i.failures:[],skills:Array.isArray(i.skills)?i.skills:[],servers:Object.fromEntries(Object.entries(i.servers).map(([e,t])=>[e,{...t,tools:Array.isArray(t.tools)?t.tools:[],resources:Array.isArray(t.resources)?t.resources:[],prompts:Array.isArray(t.prompts)?t.prompts:[],promptSkills:Array.isArray(t.promptSkills)?t.promptSkills:[]}]))}}static async writeToFile(e,t){let r=et(e)?u.dump(t,{noRefs:!0}):JSON.stringify(t,null,2);await n(_(e),{recursive:!0}),await l(e,r,`utf-8`)}static getDefaultCachePath(e){let t=tt(e);return y(h(),`.aicode-toolkit`,`${t}.definitions-cache.json`)}static generateConfigHash(e){return f(`sha256`).update(JSON.stringify(e)).digest(`hex`)}static isCacheValid(e,t){return!(t.configHash&&e.configHash&&e.configHash!==t.configHash||t.oneMcpVersion&&e.oneMcpVersion&&e.oneMcpVersion!==t.oneMcpVersion)}static async clearFile(e){await a(e,{force:!0})}clearLiveCache(){this.liveDefinitionsPromise=null,this.mergedDefinitionsPromise=null}setCacheData(e){this.cacheData=e,this.mergedDefinitionsPromise=null}async collectForCache(e){let t=await this.collectLiveDefinitions(e);return this.setCacheData(t),this.liveDefinitionsPromise=Promise.resolve(M(t)),M(t)}async getDefinitions(){return this.mergedDefinitionsPromise||=(async()=>{let e=this.clientManager.getAllClients();if(!this.cacheData)return this.getLiveDefinitions();let t=e.map(e=>e.serverName).filter(e=>!this.cacheData?.servers[e]);if(t.length===0)return M(this.cacheData);let n=await this.getLiveDefinitions(),r=M(this.cacheData);for(let e of t){let t=n.servers[e];t&&(r.servers[e]=t)}let i=new Map;for(let e of[...r.failures,...n.failures])i.set(e.serverName,e.error);return r.failures=Array.from(i.entries()).map(([e,t])=>({serverName:e,error:t})),r.skills.length===0&&n.skills.length>0&&(r.skills=n.skills.map(e=>({...e}))),r})(),this.mergedDefinitionsPromise}async getServerDefinitions(){let e=await this.getDefinitions(),t=this.clientManager.getKnownServerNames();return t.length===0?Object.values(e.servers):t.map(t=>e.servers[t]).filter(e=>e!==void 0)}async getServersForTool(e){return(await this.getServerDefinitions()).filter(t=>t.tools.some(t=>t.name===e)).map(e=>e.serverName)}async getToolSchema(e,t){return(await this.getDefinitions()).servers[e]?.tools.find(e=>e.name===t)?.inputSchema}async getServersForResource(e){return(await this.getServerDefinitions()).filter(t=>t.resources.some(t=>t.uri===e)).map(e=>e.serverName)}async getPromptSkillByName(e){let t=await this.getDefinitions();for(let[n,r]of Object.entries(t.servers))for(let t of r.promptSkills)if(t.skill.name===e)return{serverName:n,promptName:t.promptName,skill:t.skill,autoDetected:t.autoDetected}}async getCachedFileSkills(){return(await this.getDefinitions()).skills.map(e=>({...e}))}async getLiveDefinitions(){return this.liveDefinitionsPromise||=this.collectLiveDefinitions(),this.liveDefinitionsPromise}async collectLiveDefinitions(e){let t=this.clientManager.getAllClients(),n=[],r={},i=await Promise.all(t.map(async e=>{try{let t=await e.listTools(),n=await this.listResourcesSafe(e),r=await this.listPromptsSafe(e),i=new Set(e.toolBlacklist||[]),a=t.filter(e=>!i.has(e.name)),o=await this.collectPromptSkillsForClient(e,r);return{serverName:e.serverName,serverInstruction:e.serverInstruction,omitToolDescription:e.omitToolDescription,toolBlacklist:e.toolBlacklist,tools:a.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,_meta:e._meta})),resources:n,prompts:r,promptSkills:o}}catch(t){return n.push({serverName:e.serverName,error:j(t)}),null}}));for(let e of i)e&&(r[e.serverName]=e);return{version:1,oneMcpVersion:e?.oneMcpVersion,generatedAt:new Date().toISOString(),configPath:e?.configPath,configHash:e?.configHash,serverId:e?.serverId,servers:r,skills:await this.collectFileSkills(),failures:n}}async collectFileSkills(){return this.skillService?(await this.skillService.getSkills()).map(e=>this.toCachedFileSkill(e)):[]}toCachedFileSkill(e){return{name:e.name,description:e.description,location:e.location,basePath:e.basePath}}async listPromptsSafe(e){try{return(await e.listPrompts()).map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(e=>({...e}))}))}catch(t){return this.logger.warn(`${Je} Failed to list prompts from ${e.serverName}: ${j(t)}`),[]}}async listResourcesSafe(e){try{return(await e.listResources()).map(e=>({uri:e.uri,name:e.name,description:e.description,mimeType:e.mimeType}))}catch(t){return this.logger.warn(`[capability-discovery] Failed to list resources from ${e.serverName}: ${j(t)}`),[]}}async collectPromptSkillsForClient(e,t){let n=new Set(e.prompts?Object.keys(e.prompts):[]),r=[];if(e.prompts)for(let[t,n]of Object.entries(e.prompts))n.skill&&r.push({promptName:t,skill:{...n.skill}});let i=t.filter(e=>!n.has(e.name)).slice(0,50),a=await Promise.all(i.map(async t=>{try{let n=$e((await e.getPrompt(t.name)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
5
+ `)||``);return n?{promptName:t.name,skill:n.skill,autoDetected:!0}:null}catch(n){return this.logger.warn(`${Je} Failed to fetch prompt '${t.name}' from ${e.serverName}: ${j(n)}`),null}}));for(let e of a)e&&r.push(e);return r}};function nt(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function P(e){if(e!==void 0)return e instanceof Error?{exception:e}:nt(e)&&(`attributes`in e||`exception`in e||`context`in e)?e:nt(e)?{attributes:e}:{attributes:{value:e}}}function rt(e){let t=e.logger;return{backend:e.backend,enabled:e.enabled,endpoint:e.endpoint,filePath:e.filePath,trace(e,n){t.trace(e,P(n))},debug(e,n){t.debug(e,P(n))},info(e,n){t.info(e,P(n))},warn(e,n){t.warn(e,P(n))},error(e,n){t.error(e,P(n))},getTraceContext(){return t.getTraceContext()},flush:()=>e.flush(),shutdown:()=>e.shutdown()}}async function it(e={}){return rt(await ee({env:e.env,workspaceRoot:e.workspaceRoot,serviceName:e.serviceName??`@agimon-ai/mcp-proxy`,serviceVersion:e.serviceVersion,logDir:e.logDir,logFileName:e.logFileName,maxFileSizeBytes:e.maxFileSizeBytes,maxFileCount:e.maxFileCount}))}function F(e){return ot(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=at(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function at(e){return typeof e==`string`?e.toLowerCase():void 0}function ot(e){let t=new Set,n=[],r=e;for(;r&&!t.has(r);){if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause;continue}if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:String(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause;continue}n.push({message:String(r)});break}return n}var st=class{serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;childProcess;processLease;connected=!1;reconnectFn;reconnectPromise;constructor(e,t,n,r,i){this.serverName=e,this.serverInstruction=i.instruction,this.toolBlacklist=i.toolBlacklist,this.omitToolDescription=i.omitToolDescription,this.prompts=i.prompts,this.transport=t,this.logger=r,this.client=n}setChildProcess(e){this.childProcess=e}setProcessLease(e){this.processLease=e}setConnected(e){this.connected=e}setReconnectFn(e){this.reconnectFn=e}async reconnectClient(){if(!this.reconnectFn)throw Error(`No reconnect function configured for ${this.serverName}`);let e=this.reconnectFn;this.reconnectPromise||=(async()=>{try{await this.client.close()}catch(e){this.logger.warn(`Failed to close stale client for ${this.serverName}`,e)}let t=await e();this.client=t.client,t.childProcess&&(this.childProcess=t.childProcess)})();try{await this.reconnectPromise}finally{this.reconnectPromise&&=void 0}}async withSessionRetry(e){let t=0;for(;;)try{return await e()}catch(e){if(!this.reconnectFn||!F(e)||t>=2)throw e;for(t+=1,this.logger.warn(`Session error for ${this.serverName}, reconnecting: ${e instanceof Error?e.message:String(e)}`);;)try{await this.reconnectClient();break}catch(e){if(!F(e)||t>=2)throw e;this.logger.warn(`Reconnect attempt ${String(t)} for ${this.serverName} failed, retrying: ${e instanceof Error?e.message:String(e)}`),t+=1}}}async listTools(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listTools()).tools)}async listResources(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listResources()).resources)}async listPrompts(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listPrompts()).prompts)}async callTool(e,t,n){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>{let r=n?.timeout?{timeout:n.timeout}:void 0;return await this.client.callTool({name:e,arguments:t},void 0,r)})}async readResource(e){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>await this.client.readResource({uri:e}))}async getPrompt(e,t){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>await this.client.getPrompt({name:e,arguments:t}))}async close(){let e=this.childProcess,t=this.processLease;this.childProcess=void 0,this.processLease=void 0,this.connected=!1;try{e&&e.kill(),await this.client.close()}finally{await t?.release({kill:!1,releasePort:!1})}}},ct=class{clients=new Map;serverConfigs=new Map;connectionPromises=new Map;logger;repositoryPath;constructor(e=console,t=process.cwd()){this.logger=e,this.repositoryPath=t}async cleanupChildProcesses(){await this.disconnectAll()}async connectToServer(e,t){this.serverConfigs.set(e,t),await this.ensureConnected(e)}registerServerConfigs(e){for(let[t,n]of Object.entries(e))this.serverConfigs.set(t,n)}getKnownServerNames(){return Array.from(this.serverConfigs.keys())}getServerRequestTimeout(e){return this.serverConfigs.get(e)?.requestTimeout}async ensureConnected(e){let t=this.clients.get(e);if(t)return t;let n=this.connectionPromises.get(e);if(n)return await n;let r=this.serverConfigs.get(e);if(!r)throw Error(`No configuration found for server "${e}"`);let i=this.createConnection(e,r);this.connectionPromises.set(e,i);try{return await i}finally{this.connectionPromises.delete(e)}}async createConnection(e,t){let n=t.timeout??3e4,r=new x({name:`@agimon-ai/mcp-proxy-client`,version:`0.1.0`},{capabilities:{}}),i=new st(e,t.transport,r,this.logger,{instruction:t.instruction,toolBlacklist:t.toolBlacklist,omitToolDescription:t.omitToolDescription,prompts:t.prompts});try{if(await Promise.race([this.performConnection(i,t),new Promise((e,t)=>setTimeout(()=>t(Error(`Connection timeout after ${n}ms`)),n))]),i.setConnected(!0),(t.transport===`http`||t.transport===`sse`)&&i.setReconnectFn(async()=>{try{let n=new x({name:`@agimon-ai/mcp-proxy-client`,version:`0.1.0`},{capabilities:{}}),r=new st(e,t.transport,n,this.logger,{});return await this.performConnection(r,t),{client:n}}catch(t){throw this.logger.warn(`Failed to reconnect to ${e}`,t),t}}),!i.serverInstruction)try{let e=i.client.getInstructions();e&&(i.serverInstruction=e)}catch(t){this.logger.warn(`Failed to get server instruction from ${e}`,t)}return this.clients.set(e,i),i}catch(e){throw await i.close(),e}}async performConnection(e,t){if(t.transport===`stdio`)await this.connectStdioClient(e,t.config);else if(t.transport===`http`)await this.connectHttpClient(e,t.config);else if(t.transport===`sse`)await this.connectSseClient(e,t.config);else throw Error(`Unsupported transport type: ${t.transport}`)}async connectStdioClient(e,t){let n=new ne({command:t.command,args:t.args,env:{...process.env,...t.env??{}}});await e.client.connect(n);let r=n._process;if(r){if(typeof r.pid!=`number`||r.pid<=0)throw Error(`Failed to capture pid for stdio child process on server "${e.serverName}"`);e.setChildProcess(r);let n=await ie({repositoryPath:this.repositoryPath,serviceName:e.serverName,serviceType:`tool`,pid:r.pid,command:t.command,args:t.args,metadata:{transport:`stdio`}});e.setProcessLease(n);return}throw Error(`Failed to capture stdio child process for server "${e.serverName}"`)}async connectHttpClient(e,t){let n=new re(new URL(t.url),{requestInit:t.headers?{headers:t.headers}:void 0});await e.client.connect(n)}async connectSseClient(e,t){let n=new te(new URL(t.url));await e.client.connect(n)}getClient(e){return this.clients.get(e)}getAllClients(){return Array.from(this.clients.values())}async disconnectServer(e){let t=this.clients.get(e);t&&(await t.close(),this.clients.delete(e))}async disconnectAll(){let e=Array.from(this.clients.values()).map(e=>e.close());await Promise.all(e),this.clients.clear(),this.connectionPromises.clear()}isConnected(e){return this.clients.has(e)}};const lt=`install`,ut=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,dt=`pipe`;function ft(e){return typeof e==`object`&&!!e&&`command`in e}var pt=class{config;constructor(e){this.config=e}extractPackages(){let e=[],{mcpConfig:t,filter:n}=this.config;for(let[r,i]of Object.entries(t.mcpServers)){if(i.disabled||i.transport!==`stdio`||!ft(i.config))continue;let t=this.extractPackageInfo(r,i.config);if(t){if(n&&t.packageManager!==n)continue;e.push(t)}}return e}async prefetch(){try{let e=this.extractPackages(),t=[];if(e.length===0)return{totalPackages:0,successful:0,failed:0,results:[]};if(this.config.parallel){let n=e.map(async e=>this.prefetchPackage(e));t.push(...await Promise.all(n))}else for(let n of e){let e=await this.prefetchPackage(n);t.push(e)}let n=t.filter(e=>e.success).length,r=t.filter(e=>!e.success).length;return{totalPackages:e.length,successful:n,failed:r,results:t}}catch(e){throw Error(`Failed to prefetch packages: ${e instanceof Error?e.message:String(e)}`)}}async prefetchPackage(e){try{let[t,...n]=e.fullCommand,r=await this.runCommand(t,n);return{package:e,success:r.success,output:r.output}}catch(t){return{package:e,success:!1,output:t instanceof Error?t.message:String(t)}}}isValidPackageName(e){return ut.test(e)}extractPackageInfo(e,t){let n=t.command.toLowerCase(),r=t.args||[];if(n===`npx`||n.endsWith(`/npx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`npx`,packageName:t,fullCommand:[`npm`,lt,`-g`,t]}}if(n===`pnpx`||n.endsWith(`/pnpx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`pnpx`,packageName:t,fullCommand:[`pnpm`,`add`,`-g`,t]}}if(n===`uvx`||n.endsWith(`/uvx`)){let t=this.extractUvxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uvx`,packageName:t,fullCommand:[`uvx`,t]}}if((n===`uv`||n.endsWith(`/uv`))&&r.includes(`run`)){let t=this.extractUvRunPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uv`,packageName:t,fullCommand:[`uv`,`tool`,lt,t]}}return null}extractNpxPackage(e){for(let t=0;t<e.length;t++){let n=e[t];if(n.startsWith(`--package=`))return n.slice(10)||null;if(n===`--package`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}if(n===`-p`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}}for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvxPackage(e){for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvRunPackage(e){let t=e.indexOf(`run`);if(t===-1)return null;for(let n=t+1;n<e.length;n++){let t=e[n];if(!t.startsWith(`-`))return t}return null}runCommand(e,t){return new Promise(n=>{let r=ae(e,t,{stdio:[`ignore`,dt,dt],shell:process.platform===`win32`}),i=``,a=``;r.stdout?.on(`data`,e=>{i+=e.toString()}),r.stderr?.on(`data`,e=>{a+=e.toString()}),r.on(`close`,e=>{n({success:e===0,output:i||a})}),r.on(`error`,e=>{n({success:!1,output:e.message})})})}};const mt=`.runtime.json`;function I(e){return typeof e==`object`&&!!e}function ht(e){return I(e)?typeof e.serverId==`string`&&typeof e.host==`string`&&typeof e.port==`number`&&e.transport===`http`&&typeof e.shutdownToken==`string`&&typeof e.startedAt==`string`&&typeof e.pid==`number`&&(e.configPath===void 0||typeof e.configPath==`string`):!1}function gt(e){return e instanceof Error?e.message:String(e)}var L=class e{runtimeDir;logger;constructor(t,n=console){this.runtimeDir=t??e.getDefaultRuntimeDir(),this.logger=n}static getDefaultRuntimeDir(){return y(h(),`.aicode-toolkit`,`mcp-proxy`,`runtimes`)}getRecordPath(e){return y(this.runtimeDir,`${e}${mt}`)}async write(e){await n(this.runtimeDir,{recursive:!0}),await l(this.getRecordPath(e.serverId),JSON.stringify(e,null,2),`utf-8`)}async read(e){let t=this.getRecordPath(e);try{let e=await r(t,`utf-8`),n=JSON.parse(e);return ht(n)?n:null}catch(n){if(I(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${gt(n)}`)}}async list(){try{let e=(await i(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(mt));return(await Promise.all(e.map(async e=>{try{let t=await r(y(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return ht(n)?n:null}catch(t){return this.logger.debug(`Skipping unreadable runtime state file ${e.name}`,t),null}}))).filter(e=>e!==null)}catch(e){if(I(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${gt(e)}`)}}async remove(e){await a(this.getRecordPath(e),{force:!0})}},R=class extends Error{constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function z(e){try{return await t(e),!0}catch(t){if(t instanceof Error&&`code`in t&&t.code===`ENOENT`)return!1;throw Error(`Failed to check path existence for "${e}": ${t instanceof Error?t.message:`Unknown error`}`)}}var _t=class{cwd;skillPaths;cachedSkills=null;skillsByName=null;watchers=[];pollingTimers=[];onCacheInvalidated;logger;constructor(e,t,n,r=console){this.cwd=e,this.skillPaths=t,this.onCacheInvalidated=n?.onCacheInvalidated,this.logger=r}async getSkills(){if(this.cachedSkills!==null)return this.cachedSkills;let e=[],t=new Set,n=await Promise.all(this.skillPaths.map(async e=>{let t=v(e)?e:y(this.cwd,e);return this.loadSkillsFromDirectory(t,`project`)}));for(let r of n)for(let n of r)t.has(n.name)||(e.push(n),t.add(n.name));return this.cachedSkills=e,this.skillsByName=new Map(e.map(e=>[e.name,e])),e}async getSkill(e){return this.skillsByName===null&&await this.getSkills(),this.skillsByName?.get(e)}clearCache(){this.cachedSkills=null,this.skillsByName=null}async startWatching(){this.stopWatching();let e=await Promise.all(this.skillPaths.map(async e=>{let t=v(e)?e:y(this.cwd,e);return{skillsDir:t,exists:await z(t)}}));for(let{skillsDir:t,exists:n}of e){if(!n)continue;let e=new AbortController;this.watchers.push(e),this.watchDirectory(t,e.signal).catch(n=>{if(n?.name!==`AbortError`){if(this.isWatchResourceLimitError(n)){this.startPollingDirectory(t,e.signal);return}this.logger.warn(`[skill-watcher] Error watching ${t}: ${n instanceof Error?n.message:`Unknown error`}`)}})}}stopWatching(){for(let e of this.watchers)e.abort();this.watchers=[];for(let e of this.pollingTimers)clearInterval(e);this.pollingTimers=[]}async watchDirectory(e,t){let n=c(e,{recursive:!0,signal:t});for await(let e of n)e.filename?.endsWith(`SKILL.md`)&&this.invalidateCache()}invalidateCache(){this.clearCache(),this.onCacheInvalidated?.()}isWatchResourceLimitError(e){return e instanceof Error&&`code`in e&&(e.code===`EMFILE`||e.code===`ENOSPC`)}startPollingDirectory(e,t){this.createSkillSnapshot(e).then(n=>{let r=n,i=setInterval(()=>{if(t.aborted){clearInterval(i);return}this.createSkillSnapshot(e).then(e=>{this.snapshotsEqual(r,e)||(r=e,this.invalidateCache())}).catch(t=>{this.logger.warn(`[skill-watcher] Polling failed for ${e}: ${t instanceof Error?t.message:`Unknown error`}`)})},3e3);this.pollingTimers.push(i),t.addEventListener(`abort`,()=>{clearInterval(i),this.pollingTimers=this.pollingTimers.filter(e=>e!==i)},{once:!0})})}async createSkillSnapshot(e){let t=new Map;return await this.collectSkillSnapshots(e,t),t}async collectSkillSnapshots(e,t){let n;try{n=await i(e)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(n.map(async n=>{let r=y(e,n),i=await o(r);if(i.isDirectory()){await this.collectSkillSnapshots(r,t);return}n===`SKILL.md`&&t.set(r,i.mtimeMs)}))}snapshotsEqual(e,t){if(e.size!==t.size)return!1;for(let[n,r]of e)if(t.get(n)!==r)return!1;return!0}async loadSkillsFromDirectory(e,t){let n=[];try{if(!await z(e))return n}catch(t){throw new R(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await i(e)}catch(t){throw new R(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let a=await Promise.all(r.map(async t=>{let n=y(e,t);try{return{entry:t,entryPath:n,stat:await o(n),error:null}}catch(e){return this.logger.warn(`Skipping entry ${n}: ${e instanceof Error?e.message:`Unknown error`}`),{entry:t,entryPath:n,stat:null,error:e}}})),s=[];for(let{entry:e,entryPath:t,stat:n}of a)if(n)if(n.isDirectory()){let e=y(t,`SKILL.md`);s.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&s.push({filePath:t,isRootLevel:!0});let c=await Promise.all(s.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await z(e)?null:await this.loadSkillFile(e,t)}catch(t){return this.logger.warn(`Skipping skill at ${e}: ${t instanceof Error?t.message:`Unknown error`}`),null}}));for(let e of c)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await r(e,`utf-8`)}catch(t){throw new R(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:i,content:a}=Ze(n);return!i||!i.name||!i.description?null:{name:i.name,description:i.description,location:t,content:a,basePath:_(e)}}};const vt=new Set([`localhost`,`127.0.0.1`,`::1`]);function yt(e){return e}function bt(e){if(typeof e!=`object`||!e)return!1;let t=yt(e);return`status`in t&&t.status===`ok`&&`transport`in t&&t.transport===`http`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)}function xt(e){if(typeof e!=`object`||!e)return!1;let t=yt(e);return`ok`in t&&typeof t.ok==`boolean`&&`message`in t&&typeof t.message==`string`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)}function St(e,t){if(!vt.has(e.host))throw Error(`Refusing to connect to non-loopback host '${e.host}'. Only ${Array.from(vt).join(`, `)} are allowed.`);return`http://${e.host}:${e.port}${t}`}function Ct(e){return e instanceof Error?e.message:String(e)}function wt(e){return new Promise(t=>{setTimeout(t,e)})}var Tt=class{runtimeStateService;logger;constructor(e=new L,t=console){this.runtimeStateService=e,this.logger=t}async stop(e){let t=e.timeoutMs??5e3,n=await this.resolveRuntime(e),r=await this.fetchHealth(n,t);if(!r.reachable)throw await this.runtimeStateService.remove(n.serverId),Error(`Runtime '${n.serverId}' is not reachable at http://${n.host}:${n.port}. Removed stale runtime record.`);if(!e.force&&r.payload?.serverId&&r.payload.serverId!==n.serverId)throw Error(`Refusing to stop runtime at http://${n.host}:${n.port}: expected server ID '${n.serverId}' but health endpoint reported '${r.payload.serverId}'. Use --force to override.`);let i=e.token??n.shutdownToken;if(!i)throw Error(`No shutdown token available for runtime '${n.serverId}'.`);let a=await this.requestShutdown(n,i,t);return await this.waitForShutdown(n,t),await this.runtimeStateService.remove(n.serverId),{ok:!0,serverId:n.serverId,host:n.host,port:n.port,message:a.message}}async resolveRuntime(e){if(e.serverId){let t=await this.runtimeStateService.read(e.serverId);if(!t)throw Error(`No runtime record found for server ID '${e.serverId}'. Start the server with 'mcp-proxy mcp-serve --type http' first.`);return t}if(e.host===void 0||e.port===void 0)throw Error(`Provide --id or both --host and --port to select a runtime.`);let t=(await this.runtimeStateService.list()).filter(t=>t.host===e.host&&t.port===e.port);if(t.length===0)throw Error(`No runtime record found for http://${e.host}:${e.port}. Start the server with 'mcp-proxy mcp-serve --type http' first.`);if(t.length>1)throw Error(`Multiple runtime records match http://${e.host}:${e.port}. Retry with --id to avoid stopping the wrong server.`);return t[0]}async fetchHealth(e,t){try{let n=await this.fetchWithTimeout(St(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!bt(r))throw Error(`Received invalid health response payload.`);return{reachable:!0,payload:r}}catch(t){return this.logger.debug(`Health check failed for ${e.serverId}`,t),{reachable:!1}}}async requestShutdown(e,t,n){let r=await this.fetchWithTimeout(St(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!xt(i))throw Error(`Received invalid shutdown response payload.`);if(!r.ok||!i.ok)throw Error(i.message);return i}async waitForShutdown(e,t){let n=Date.now()+t;for(;Date.now()<n;){if(!(await this.fetchHealth(e,Math.max(250,n-Date.now()))).reachable)return;await wt(200)}throw Error(`Timed out waiting for runtime '${e.serverId}' to stop at http://${e.host}:${e.port}.`)}async fetchWithTimeout(e,t,n){let r=new AbortController,i=setTimeout(()=>{r.abort()},n);try{return await fetch(e,{...t,signal:r.signal})}catch(t){throw Error(`Request to '${e}' failed: ${Ct(t)}`)}finally{clearTimeout(i)}}},Et=`<toolkit id="{{ serverId }}">
6
+ <instruction>
7
+ Before you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:
8
+ - For tools: Arguments schema needed to pass to use_tool
9
+ - For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)
10
+
11
+ This tool is optimized for batch queries - you can request multiple capabilities at once for better performance.
12
+
13
+ How to invoke:
14
+ - For MCP tools: Use use_tool with toolName and toolArgs based on the schema
15
+ - For skills: Use this tool with the skill name to get expanded instructions
16
+ </instruction>
17
+
18
+ <available_capabilities>
19
+ {% for server in servers -%}
20
+ <group original-mcp-server="{{ server.name }}">
21
+ {% if server.instruction -%}
22
+ <group_instruction>{{ server.instruction }}</group_instruction>
23
+ {% endif -%}
24
+ {% if server.omitToolDescription -%}
25
+ {% for toolName in server.toolNames -%}
26
+ <item name="{{ toolName }}"></item>
27
+ {% endfor -%}
28
+ {% else -%}
29
+ {% for tool in server.tools -%}
30
+ <item name="{{ tool.displayName }}"><description>{{ tool.description | default: "No description" }}</description></item>
31
+ {% endfor -%}
32
+ {% endif -%}
33
+ </group>
34
+ {% endfor -%}
35
+ {% if skills.size > 0 -%}
36
+ <group name="skills">
37
+ {% for skill in skills -%}
38
+ <item name="{{ skill.displayName }}"><description>{{ skill.description }}</description></item>
39
+ {% endfor -%}
40
+ </group>
41
+ {% endif -%}
42
+ </available_capabilities>
43
+ </toolkit>
44
+ `;function B(e,t){return`<command-message>The "${e}" skill is loading</command-message>\n${t}`}const V=d.object({toolNames:d.array(d.string().min(1)).min(1).describe(`List of tool names to get detailed information about`)});var H=class e{static TOOL_NAME=`describe_tools`;clientManager;skillService;definitionsCacheService;liquid=new oe;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.serverId=n||`unknown`,this.definitionsCacheService=r||new N(e,t)}clearAutoDetectedSkillsCache(){this.definitionsCacheService.clearLiveCache()}async collectPromptSkills(){let e=[],t=await this.definitionsCacheService.getServerDefinitions();for(let n of t)for(let t of n.promptSkills)e.push({name:t.skill.name,displayName:t.skill.name,description:t.skill.description});return e}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}async getPromptSkillContent(e){let t=await this.findPromptSkill(e);if(t)try{let e=(await(await this.clientManager.ensureConnected(t.serverName)).getPrompt(t.promptName)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
45
+ `)||``;return{name:t.skill.name,location:t.skill.folder||`prompt:${t.serverName}/${t.promptName}`,instructions:B(t.skill.name,e)}}catch(t){console.error(`Failed to get prompt-based skill '${e}': ${t instanceof Error?t.message:`Unknown error`}`);return}}async buildToolkitDescription(){let e=await this.definitionsCacheService.getServerDefinitions(),t=new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=(e,n)=>(t.get(e)||[]).length>1?`${n}__${e}`:e,r=new Set,i=e.map(e=>{let t=e.tools.map(t=>({displayName:n(t.name,e.serverName),description:t.description}));for(let e of t)r.add(e.displayName);return{name:e.serverName,instruction:e.serverInstruction,omitToolDescription:e.omitToolDescription||!1,tools:t,toolNames:t.map(e=>e.displayName)}}),[a,o,s]=await Promise.all([this.skillService?this.skillService.getSkills():Promise.resolve([]),this.definitionsCacheService.getCachedFileSkills(),this.collectPromptSkills()]),c=new Set,l=[];for(let e of a)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of o)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of s)c.has(e.name)||(c.add(e.name),l.push(e));let u=l.map(e=>{let t=r.has(e.name);return{name:e.name,displayName:t?`skill__${e.name}`:e.name,description:e.description}});return{content:await this.liquid.parseAndRender(Et,{servers:i,skills:u,serverId:this.serverId}),toolNames:r}}getInputSchema(){return V}async getDefinition(){let{content:t}=await this.buildToolkitDescription();return{name:e.TOOL_NAME,description:t,inputSchema:d.toJSONSchema(V,{reused:`inline`})}}async runLookups(e,t){let n=new Map,r=new Map;for(let e of t){let t=e.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));n.set(e.serverName,t);for(let n of t)r.has(n.name)||r.set(n.name,[]),r.get(n.name)?.push(e.serverName)}let i=await Promise.all(e.map(async e=>{let t={tools:[],skills:[],notFound:null};if(e.startsWith(`skill__`)){let n=e.slice(7);if(this.skillService){let e=await this.skillService.getSkill(n);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:B(e.name,e.content)}),t}let r=await this.getPromptSkillContent(n);return r?(t.skills.push(r),t):(t.notFound=e,t)}let{serverName:i,actualToolName:a}=A(e);if(i){let r=n.get(i);if(!r){try{let n=(await(await this.clientManager.ensureConnected(i)).listTools()).find(e=>e.name===a);n?t.tools.push({server:i,tool:{name:n.name,description:n.description,inputSchema:n.inputSchema}}):t.notFound=e}catch{t.notFound=e}return t}let o=r.find(e=>e.name===a);return o?t.tools.push({server:i,tool:{name:o.name,description:o.description,inputSchema:o.inputSchema}}):t.notFound=e,t}let o=r.get(a);if(!o||o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:B(e.name,e.content)}),t}let n=await this.getPromptSkillContent(a);return n?(t.skills.push(n),t):(t.notFound=e,t)}for(let e of o){let r=n.get(e).find(e=>e.name===a);t.tools.push({server:e,tool:{name:r.name,description:r.description,inputSchema:r.inputSchema}})}return t})),a=[],o=[],s=[];for(let e of i)a.push(...e.tools),o.push(...e.skills),e.notFound&&s.push(e.notFound);return{foundTools:a,foundSkills:o,notFoundItems:s}}async execute(e){try{let{toolNames:t}=V.parse(e);if(!t||t.length===0)return{content:[{type:`text`,text:`No tool names provided. Please specify at least one tool name.`}],isError:!0};let n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions());n.notFoundItems.length>0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions()));let{foundTools:r,foundSkills:i,notFoundItems:a}=n;if(r.length===0&&i.length===0)return{content:[{type:`text`,text:`None of the requested tools/skills found.\nRequested: ${t.join(`, `)}\nUse describe_tools to see available tools and skills.`}],isError:!0};let o={},s=[];return r.length>0&&(o.tools=r,s.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`)),i.length>0&&(o.skills=i,s.push(`For skill, just follow skill's description to continue.`)),s.length>0&&(o.nextSteps=s),a.length>0&&(o.notFound=a,o.warnings=[`Items not found: ${a.join(`, `)}`]),{content:[{type:`text`,text:JSON.stringify(o,null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error describing tools: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};function U(e){let t=e._meta?.[`agiflowai/capabilities`];return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}function W(e){return Array.from(new Set(e.flatMap(e=>U(e)))).sort()}const G=d.object({capability:d.string().optional().describe(`Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions.`),serverName:d.string().optional().describe(`Optional server name filter.`)});var K=class e{static TOOL_NAME=`list_tools`;constructor(e,t){this._clientManager=e,this.definitionsCacheService=t}formatToolName(e,t,n){return(n.get(e)||[]).length>1?`${t}__${e}`:e}getInputSchema(){return G}async getDefinition(){let t=await this.definitionsCacheService.getServerDefinitions(),n=t.length>0?t.map(e=>{let t=W(e.tools),n=t.length>0?t.join(`, `):e.serverInstruction||`No capability summary available`;return`${e.serverName}: ${n}`}).join(`
46
+ `):`No proxied servers available.`;return{name:e.TOOL_NAME,description:`Search proxied MCP tools by server capability summary.\n\nAvailable capabilities:\n${n}`,inputSchema:d.toJSONSchema(G,{reused:`inline`})}}async execute(e){let t=G.parse(e),n=await this.definitionsCacheService.getServerDefinitions(),r=t.capability?.trim().toLowerCase(),i=t.serverName?.trim().toLowerCase(),a=new Map;for(let e of n)for(let t of e.tools)a.has(t.name)||a.set(t.name,[]),a.get(t.name)?.push(e.serverName);let o=n.filter(e=>i&&e.serverName.toLowerCase()!==i?!1:!r||(e.serverInstruction?.toLowerCase()||``).includes(r)||W(e.tools).some(e=>e.toLowerCase().includes(r))?!0:e.tools.some(t=>{let n=this.formatToolName(t.name,e.serverName,a),i=U(t);return n.toLowerCase().includes(r)||(t.description||``).toLowerCase().includes(r)||i.some(e=>e.toLowerCase().includes(r))})).map(e=>({server:e.serverName,capabilities:W(e.tools),summary:e.serverInstruction,tools:e.tools.map(t=>({name:this.formatToolName(t.name,e.serverName,a),description:e.omitToolDescription?void 0:t.description,capabilities:U(t)}))})).filter(e=>e.tools.length>0);return{content:[{type:`text`,text:JSON.stringify({servers:o},null,2)}],isError:o.length===0?!0:void 0}}};const q=d.object({toolName:d.string().min(1).describe(`Name of the tool to execute`),toolArgs:d.record(d.string(),d.unknown()).optional().describe(`Arguments to pass to the tool, as discovered from describe_tools`)});var J=class e{static TOOL_NAME=`use_tool`;clientManager;skillService;definitionsCacheService;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.definitionsCacheService=r||new N(e,t),this.serverId=n||`unknown`}getInputSchema(){return q}getDefinition(){return{name:e.TOOL_NAME,description:`Execute an MCP tool (NOT Skill) with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
47
+ - Provide toolName and toolArgs based on the schema
48
+ - If multiple servers provide the same tool, specify serverName
49
+
50
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
51
+ `,inputSchema:d.toJSONSchema(q,{reused:`inline`})}}async coerceToolArgs(e,t,n){let r=await this.definitionsCacheService.getToolSchema(e,t);return r?se(n,le(r)):n}executeSkill(e){return{content:[{type:`text`,text:`Skill "${e.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${e.basePath}\n\nThen follow the skill's instructions directly.`}]}}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}executePromptSkill(e){let t=e.skill.folder||`prompt:${e.serverName}/${e.promptName}`;return{content:[{type:`text`,text:`Skill "${e.skill.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${t}\n\nThen follow the skill's instructions directly.`}]}}async execute(e){try{let{toolName:t,toolArgs:n={}}=q.parse(e);if(t.startsWith(`skill__`)){let e=t.slice(7);if(this.skillService){let t=await this.skillService.getSkill(e);if(t)return this.executeSkill(t)}let n=await this.findPromptSkill(e);return n?this.executePromptSkill(n):{content:[{type:`text`,text:`Skill "${e}" not found. Use describe_tools to see available skills.`}],isError:!0}}let r=this.clientManager.getKnownServerNames(),{serverName:i,actualToolName:a}=A(t);if(i)try{let e=await this.clientManager.ensureConnected(i);if(e.toolBlacklist?.includes(a))return{content:[{type:`text`,text:`Tool "${a}" is blacklisted on server "${i}" and cannot be executed.`}],isError:!0};let t=this.clientManager.getServerRequestTimeout(i),r=await this.coerceToolArgs(i,a,n);return await e.callTool(a,r,t?{timeout:t}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}" on server "${i}". Available servers: ${r.join(`, `)}. ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}let o=await this.definitionsCacheService.getServersForTool(a);if(o.length===0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),o=await this.definitionsCacheService.getServersForTool(a)),o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return this.executeSkill(e)}let e=await this.findPromptSkill(a);return e?this.executePromptSkill(e):{content:[{type:`text`,text:`Tool or skill "${a}" not found. Use describe_tools to see available tools and skills.`}],isError:!0}}if(o.length>1)return{content:[{type:`text`,text:`Tool "${a}" found on multiple servers. Use prefixed format to specify: ${o.map(e=>`${e}__${a}`).join(`, `)}`}],isError:!0};try{let e=o[0],t=await this.clientManager.ensureConnected(e),r=this.clientManager.getServerRequestTimeout(e),i=await this.coerceToolArgs(e,a,n);return await t.callTool(a,i,r?{timeout:r}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}": ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}catch(e){return{content:[{type:`text`,text:`Error executing tool: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},Dt=class{sessions=new Map;closingSessions=new Set;cleanupTimer=null;logger;constructor(e=console){this.logger=e}getSession(e){let t=this.sessions.get(e);return t&&(t.lastActivity=Date.now()),t}setSession(e,t,n){this.sessions.set(e,{transport:t,server:n,lastActivity:Date.now()})}removeSession(e){this.sessions.delete(e)}isClosing(e){return this.closingSessions.has(e)}async closeSession(e){let t=this.sessions.get(e);if(t){this.closingSessions.add(e);try{await t.server.close()}catch(t){throw Error(`Failed to close MCP server for session '${e}': ${Y(t)}`)}finally{this.sessions.delete(e),this.closingSessions.delete(e)}}}hasSession(e){return this.sessions.has(e)}startCleanup(){this.cleanupTimer||=setInterval(()=>{this.cleanupStaleSessions()},3e5)}stopCleanup(){this.cleanupTimer&&=(clearInterval(this.cleanupTimer),null)}async cleanupStaleSessions(){let e=Date.now(),t=[];for(let[n,r]of this.sessions)e-r.lastActivity>18e5&&!this.closingSessions.has(n)&&t.push(n);for(let e of t)try{this.logger.info(`Closing inactive session '${e}'`),await this.closeSession(e)}catch(t){this.logger.warn(`Failed to close stale session '${e}': ${Y(t)}`)}}async clear(){this.stopCleanup();try{await Promise.all(Array.from(this.sessions.keys()).map(async e=>this.closeSession(e)))}catch(e){throw Error(`Failed to clear sessions: ${Y(e)}`)}}};function Y(e){return e instanceof Error?e.message:String(e)}var Ot=class{requests=new Map;isAllowed(e){let t=Date.now(),n=t-6e4,r=(this.requests.get(e)??[]).filter(e=>e>n);return r.length===0?(this.requests.delete(e),!0):r.length>=5?(this.requests.set(e,r),!1):(r.push(t),this.requests.set(e,r),!0)}};async function kt(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>{try{let e=Buffer.concat(r).toString(`utf-8`);t(e?JSON.parse(e):void 0)}catch(e){n(Error(`Failed to parse JSON body: ${Y(e)}`))}}),e.on(`error`,n)})}function At(e,t,n){let r=JSON.stringify(n);e.writeHead(t,{"Content-Type":`application/json`}),e.end(r)}var jt=class{serverFactory;honoApp;server=null;sessionManager;config;adminOptions;adminRateLimiter=new Ot;logger;constructor(e,t,n,r=console){this.serverFactory=e,this.honoApp=new Ce,this.sessionManager=new Dt(r),this.config={mode:t.mode,port:t.port,host:t.host??`localhost`},this.adminOptions=n,this.logger=r,this.setupHonoRoutes()}setupHonoRoutes(){this.honoApp.get(`/health`,e=>{let t={status:`ok`,transport:`http`,serverId:this.adminOptions?.serverId};return e.json(t)}),this.honoApp.post(`/admin/shutdown`,async e=>{try{let t=e.req.header(`x-forwarded-for`)??`unknown`;if(!this.adminRateLimiter.isAllowed(t)){let t={ok:!1,message:`Too many shutdown requests. Try again later.`,serverId:this.adminOptions?.serverId};return e.json(t,429)}return await this.handleAdminShutdownRequest(e)}catch(t){this.logger.error(`Failed to process shutdown request: ${Y(t)}`);let n={ok:!1,message:`Failed to process shutdown request.`,serverId:this.adminOptions?.serverId};return e.json(n,500)}})}isAuthorizedShutdownRequest(e){let t=this.adminOptions?.shutdownToken;if(!t)return!1;let n=e.authorization;if(typeof n==`string`&&n.startsWith(`Bearer `))return n.slice(7)===t;let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&r===t}async handleAdminShutdownRequest(e){if(!this.adminOptions?.onShutdownRequested){let t={ok:!1,message:`Shutdown endpoint is not enabled for this server instance.`,serverId:this.adminOptions?.serverId};return e.json(t,404)}let t={authorization:e.req.header(`authorization`),"x-mcp-proxy-shutdown-token":e.req.header(`x-mcp-proxy-shutdown-token`)};if(!this.isAuthorizedShutdownRequest(t)){let t={ok:!1,message:`Unauthorized shutdown request: invalid or missing shutdown token.`,serverId:this.adminOptions?.serverId};return e.json(t,401)}let n={ok:!0,message:`Shutdown request accepted. Stopping server gracefully.`,serverId:this.adminOptions?.serverId},r=e.json(n);return this.adminOptions.onShutdownRequested(),r}async handleMcpRequest(e,t){let n=e.method?.toUpperCase();try{n===`POST`?await this.handlePostRequest(e,t):n===`GET`?await this.handleGetRequest(e,t):n===`DELETE`?await this.handleDeleteRequest(e,t):(t.writeHead(405),t.end(`Method Not Allowed`))}catch(e){this.logger.error(`Failed to handle MCP ${n} request: ${Y(e)}`),t.headersSent||At(t,500,{jsonrpc:`2.0`,error:{code:-32603,message:`Failed to handle MCP ${n} request.`},id:null})}}async handlePostRequest(e,t){let n=e.headers[`mcp-session-id`],r=await kt(e),i;if(n&&this.sessionManager.hasSession(n))i=this.sessionManager.getSession(n).transport;else if(!n&&Se(r)){let e=await this.serverFactory();i=new me({sessionIdGenerator:()=>m(),enableJsonResponse:!0,onsessioninitialized:t=>{this.sessionManager.setSession(t,i,e)}}),i.onclose=async()=>{if(i.sessionId)try{this.sessionManager.isClosing(i.sessionId)||this.sessionManager.removeSession(i.sessionId)}catch(e){this.logger.warn(`Failed to clean up session '${i.sessionId}': ${Y(e)}`)}};try{await e.connect(i)}catch(e){throw Error(`Failed to connect MCP server transport for initialization request: ${Y(e)}`)}}else{At(t,400,{jsonrpc:`2.0`,error:{code:-32e3,message:n===void 0?`Bad Request: missing session ID and request body is not an initialize request.`:`Bad Request: unknown session ID '${n}'.`},id:null});return}try{await i.handleRequest(e,t,r)}catch(e){throw Error(`Failed handling MCP transport request: ${Y(e)}`)}}async handleGetRequest(e,t){let n=e.headers[`mcp-session-id`];if(!n||!this.sessionManager.hasSession(n)){t.writeHead(400),t.end(`Invalid or missing session ID`);return}let r=this.sessionManager.getSession(n);try{await r.transport.handleRequest(e,t)}catch(e){throw Error(`Failed handling MCP GET request for session '${n}': ${Y(e)}`)}}async handleDeleteRequest(e,t){let n=e.headers[`mcp-session-id`];if(!n||!this.sessionManager.hasSession(n)){t.writeHead(400),t.end(`Invalid or missing session ID`);return}let r=this.sessionManager.getSession(n);try{await r.transport.handleRequest(e,t)}catch(e){throw Error(`Failed handling MCP DELETE request for session '${n}': ${Y(e)}`)}this.sessionManager.removeSession(n)}async start(){try{let e=pe(this.honoApp.fetch),t=de(async(t,n)=>{new URL(t.url??`/`,`http://${t.headers.host??this.config.host}`).pathname===`/mcp`?await this.handleMcpRequest(t,n):e(t,n)});t.listen(this.config.port,this.config.host),this.server=t;let n=(async()=>{await ue(t,`listening`)})(),r=(async()=>{let[e]=await ue(t,`error`);throw e instanceof Error?e:Error(String(e))})();await Promise.race([n,r]),this.sessionManager.startCleanup(),this.logger.info(`@agimon-ai/mcp-proxy MCP server started on http://${this.config.host}:${this.config.port}/mcp`),this.logger.info(`Health check: http://${this.config.host}:${this.config.port}/health`)}catch(e){throw this.server=null,Error(`Failed to start HTTP transport: ${Y(e)}`)}}async stop(){if(!this.server)return;try{await this.sessionManager.clear()}catch(e){throw Error(`Failed to clear sessions during HTTP transport stop: ${Y(e)}`)}let e=fe(this.server.close.bind(this.server));try{await e(),this.server=null}catch(e){throw Error(`Failed to stop HTTP transport: ${Y(e)}`)}}getPort(){return this.config.port}getHost(){return this.config.host}},Mt=class{sessions=new Map;closingSessions=new Set;getSession(e){return this.sessions.get(e)?.transport}setSession(e,t,n){this.sessions.set(e,{transport:t,server:n})}removeSession(e){this.sessions.delete(e)}isClosing(e){return this.closingSessions.has(e)}async closeSession(e){let t=this.sessions.get(e);if(t){this.closingSessions.add(e);try{await t.server.close()}finally{this.sessions.delete(e),this.closingSessions.delete(e)}}}async clear(){await Promise.all(Array.from(this.sessions.keys()).map(async e=>this.closeSession(e)))}hasSession(e){return this.sessions.has(e)}};async function Nt(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>{try{let e=Buffer.concat(r).toString(`utf-8`);t(e?JSON.parse(e):void 0)}catch(e){n(Error(`Failed to parse JSON body: ${e instanceof Error?e.message:String(e)}`))}}),e.on(`error`,n)})}var Pt=class{serverFactory;honoApp;server=null;sessionManager;config;logger;constructor(e,t,n=console){this.serverFactory=typeof e==`function`?e:()=>e,this.honoApp=new Ce,this.sessionManager=new Mt,this.config={mode:t.mode,port:t.port,host:t.host??`localhost`},this.logger=n,this.setupHonoRoutes()}setupHonoRoutes(){this.honoApp.get(`/health`,e=>e.json({status:`ok`,transport:`sse`}))}async handleSseConnection(e){try{let t=this.serverFactory(),n=new we(`/messages`,e);this.sessionManager.setSession(n.sessionId,n,t),e.on(`close`,()=>{let e=n.sessionId;e&&!this.sessionManager.isClosing(e)&&this.sessionManager.removeSession(e)}),await t.connect(n),this.logger.info(`SSE session established: ${n.sessionId}`)}catch(t){this.logger.error(`Error handling SSE connection`,t),e.headersSent||(e.writeHead(500),e.end(`Internal Server Error`))}}async handlePostMessage(e,t){let n=new URL(e.url??`/`,`http://${e.headers.host??this.config.host}`).searchParams.get(`sessionId`);if(!n){t.writeHead(400),t.end(`Missing sessionId query parameter`);return}let r=this.sessionManager.getSession(n);if(!r){t.writeHead(404),t.end(`No transport found for sessionId`);return}try{let n=await Nt(e);await r.handlePostMessage(e,t,n)}catch(e){this.logger.error(`Error handling post message`,e),t.headersSent||(t.writeHead(500),t.end(`Internal Server Error`))}}async start(){return new Promise((e,t)=>{try{let n=pe(this.honoApp.fetch),r=de(async(e,t)=>{let r=new URL(e.url??`/`,`http://${e.headers.host??this.config.host}`),i=e.method?.toUpperCase();r.pathname===`/sse`&&i===`GET`?await this.handleSseConnection(t):r.pathname===`/messages`&&i===`POST`?await this.handlePostMessage(e,t):n(e,t)});r.listen(this.config.port,this.config.host,()=>{this.logger.info(`@agimon-ai/mcp-proxy MCP server started with SSE transport on http://${this.config.host}:${this.config.port}`),this.logger.info(`SSE endpoint: http://${this.config.host}:${this.config.port}/sse`),this.logger.info(`Messages endpoint: http://${this.config.host}:${this.config.port}/messages`),this.logger.info(`Health check: http://${this.config.host}:${this.config.port}/health`),e()}),r.on(`error`,e=>{t(e)}),this.server=r}catch(e){t(e)}})}async stop(){return new Promise((e,t)=>{if(this.server){let n=this.server;(async()=>{try{await this.sessionManager.clear(),n.close(n=>{n?t(n):(this.server=null,e())})}catch(e){t(e)}})()}else e()})}getPort(){return this.config.port}getHost(){return this.config.host}},Ft=class{server;transport=null;logger;constructor(e,t=console){this.server=e,this.logger=t}async start(){this.transport=new Te,await this.server.connect(this.transport),this.logger.info(`@agimon-ai/mcp-proxy MCP server started on stdio`)}async stop(){this.transport&&=(await this.transport.close(),null)}};const It=[`econnrefused`,`econnreset`,`enotfound`,`connection refused`,`fetch failed`,`socket hang up`,`network error`,`failed to fetch`];function Lt(e){if(!(e instanceof Error))return!1;let t=e.message.toLowerCase();return It.some(e=>t.includes(e))}function Rt(e){let t=new Set,n=[],r=e;for(;r&&!t.has(r);){if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause;continue}if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:String(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause;continue}n.push({message:String(r)});break}return n}function zt(e){return Rt(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=Bt(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function Bt(e){return typeof e==`string`?e.toLowerCase():void 0}var Vt=class{endpoint;resolveEndpoint;stdioProxyServer=null;stdioTransport=null;httpClient=null;logger;MAX_RECONNECT_ATTEMPTS=5;RECONNECT_BASE_MS=1e3;RECONNECT_MAX_MS=3e4;constructor(e,t=console){this.endpoint=e.endpoint,this.resolveEndpoint=e.resolveEndpoint,this.logger=t}async start(){try{let e=await this.createAndConnectClient();this.httpClient=e,this.stdioProxyServer=this.createProxyServer(),this.registerElicitationHandler(e),this.stdioTransport=new Te,await this.stdioProxyServer.connect(this.stdioTransport),this.logger.info(`@agimon-ai/mcp-proxy MCP stdio proxy connected to ${this.endpoint.toString()}`)}catch(e){throw await this.stop(),Error(`Failed to start stdio-http proxy transport: ${e instanceof Error?e.message:String(e)}`)}}async stop(){let e=this.stdioTransport,t=this.stdioProxyServer,n=this.httpClient;this.stdioTransport=null,this.stdioProxyServer=null,this.httpClient=null;let r=[];if(await Promise.all([(async()=>{try{e&&await e.close()}catch(e){r.push(`failed closing stdio transport: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{t&&await t.close()}catch(e){r.push(`failed closing stdio proxy server: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{n&&await n.close()}catch(e){r.push(`failed closing http client: ${e instanceof Error?e.message:String(e)}`)}})()]),r.length>0)throw Error(`Failed to stop stdio-http proxy transport: ${r.join(`; `)}`)}async createAndConnectClient(){let e=new re(this.endpoint),t=new x({name:`@agimon-ai/mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{elicitation:{}}});return await t.connect(e),t}registerElicitationHandler(e){let t=this.stdioProxyServer;t&&e.setRequestHandler(ge,async e=>await t.elicitInput(e.params))}async reconnectWithBackoff(){for(let e=0;e<this.MAX_RECONNECT_ATTEMPTS;e++){let t=Math.min(this.RECONNECT_BASE_MS*2**e,this.RECONNECT_MAX_MS);await new Promise(e=>setTimeout(e,t));try{this.resolveEndpoint&&(this.endpoint=await this.resolveEndpoint()),await this.httpClient?.close().catch(()=>void 0);let t=await this.createAndConnectClient();this.httpClient=t,this.registerElicitationHandler(t),this.logger.info(`Reconnected to HTTP backend at ${this.endpoint.toString()} (attempt ${e+1})`);return}catch{this.logger.info(`Reconnect attempt ${e+1}/${this.MAX_RECONNECT_ATTEMPTS} to ${this.endpoint.toString()} failed`)}}throw Error(`Failed to reconnect to HTTP backend at ${this.endpoint.toString()} after ${this.MAX_RECONNECT_ATTEMPTS} attempts`)}async withReconnect(e){if(!this.httpClient)throw Error(`HTTP client not connected`);try{return await e()}catch(t){if(Lt(t)||zt(t))return await this.reconnectWithBackoff(),await e();throw t}}createProxyServer(){let e=new Ee({name:`@agimon-ai/mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}}});return e.setRequestHandler(be,async()=>{try{return await this.withReconnect(()=>this.httpClient.listTools())}catch(e){throw Error(`Failed forwarding tools/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(he,async e=>{try{return await this.withReconnect(()=>this.httpClient.callTool({name:e.params.name,arguments:e.params.arguments}))}catch(t){throw Error(`Failed forwarding tools/call (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(ye,async()=>{try{return await this.withReconnect(()=>this.httpClient.listResources())}catch(e){throw Error(`Failed forwarding resources/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(xe,async e=>{try{return await this.withReconnect(()=>this.httpClient.readResource({uri:e.params.uri}))}catch(t){throw Error(`Failed forwarding resources/read (${e.params.uri}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(ve,async()=>{try{return await this.withReconnect(()=>this.httpClient.listPrompts())}catch(e){throw Error(`Failed forwarding prompts/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(_e,async e=>{try{return await this.withReconnect(()=>this.httpClient.getPrompt({name:e.params.name,arguments:e.params.arguments}))}catch(t){throw Error(`Failed forwarding prompts/get (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e}};function X(e=console){return{createConfigFetcherService:t=>new qe(t,e),createClientManagerService:()=>new ct(e),createRuntimeStateService:t=>new L(t,e),createStopServerService:t=>new Tt(t,e),createSkillService:(t,n,r)=>new _t(t,n,r,e),createDefinitionsCacheService:(t,n,r)=>new N(t,n,r,e),createPrefetchService:e=>new pt(e),createDescribeToolsTool:(e,t,n,r)=>new H(e,t,n,r),createUseToolTool:(e,t,n,r)=>new J(e,t,n,r),createSearchListToolsTool:(e,t)=>new K(e,t),createStdioTransportHandler:async t=>new Ft(await t(),e),createSseTransportHandler:async(t,n)=>new Pt(await t(),n,e),createHttpTransportHandler:(t,n,r)=>new jt(t,n,r,e),createStdioHttpTransportHandler:t=>new Vt({endpoint:t},e)}}async function Z(e){let t=await it({workspaceRoot:process.cwd(),serviceName:`@agimon-ai/mcp-proxy`}),n=t,r=X(n),i=r.createClientManagerService();try{let a,o,s,c,l=!1;if(e?.configFilePath){let t;try{t=await r.createConfigFetcherService({configFilePath:e.configFilePath,useCache:!e.noCache}).fetchConfiguration(e.noCache||!1)}catch(t){throw Error(`Failed to load MCP configuration from '${e.configFilePath}': ${t instanceof Error?t.message:String(t)}`)}if(a=t.skills,o=t.id,s=N.generateConfigHash(t),c=e.definitionsCachePath||N.getDefaultCachePath(e.configFilePath),i.registerServerConfigs(t.mcpServers),e.clearDefinitionsCache&&c&&(await N.clearFile(c),n.info(`[definitions-cache] Cleared ${c}`)),c)try{let e=await N.readFromFile(c);N.isCacheValid(e,{configHash:s,oneMcpVersion:S})&&(l=!0)}catch(e){n.warn(`[definitions-cache] Failed to inspect ${c}; falling back to live discovery`,e)}if(l)n.info(`[definitions-cache] Using cached definitions from ${c}`);else{let e=[],r=Object.entries(t.mcpServers).map(async([t,r])=>{try{await i.connectToServer(t,r),n.info(`Connected to MCP server: ${t}`)}catch(r){let i=r instanceof Error?r:Error(String(r));e.push({serverName:t,error:i}),n.warn(`Failed to connect to ${t}`,r)}});if(await Promise.all(r),e.length>0&&e.length<Object.keys(t.mcpServers).length&&n.warn(`Warning: Some MCP server connections failed: ${e.map(e=>e.serverName).join(`, `)}`),e.length>0&&e.length===Object.keys(t.mcpServers).length)throw Error(`All MCP server connections failed: ${e.map(e=>`${e.serverName}: ${e.error.message}`).join(`, `)}`)}}let u=e?.serverId||o||Xe();n.info(`[mcp-proxy] Server ID: ${u}`);let d=(e?.skills||a)?.paths??[],f={describeTools:null},p=d.length>0?r.createSkillService(process.cwd(),d,{onCacheInvalidated:()=>{f.describeTools?.clearAutoDetectedSkillsCache()}}):void 0,m;if(c)try{let e=await N.readFromFile(c);m=N.isCacheValid(e,{configHash:s,oneMcpVersion:S})?r.createDefinitionsCacheService(i,p,{cacheData:e}):r.createDefinitionsCacheService(i,p)}catch(e){n.warn(`[definitions-cache] Failed to load ${c}, falling back to live discovery: ${e instanceof Error?e.message:`Unknown error`}`),m=r.createDefinitionsCacheService(i,p)}else m=r.createDefinitionsCacheService(i,p);let h=e?.proxyMode||`meta`,g=r.createDescribeToolsTool(i,p,u,m),_=r.createUseToolTool(i,p,u,m),v=r.createSearchListToolsTool(i,m);return f.describeTools=g,p&&p.startWatching().catch(e=>{n.warn(`[skill-watcher] File watcher failed (non-critical): ${e instanceof Error?e.message:`Unknown error`}`)}),!l&&c&&e?.configFilePath&&m.collectForCache({configPath:e.configFilePath,configHash:s,oneMcpVersion:S,serverId:u}).then(e=>N.writeToFile(c,e)).then(()=>{n.info(`[definitions-cache] Wrote ${c}`)}).catch(e=>{n.warn(`[definitions-cache] Failed to persist ${c}: ${e instanceof Error?e.message:`Unknown error`}`)}),{clientManager:i,definitionsCacheService:m,skillService:p,describeTools:g,useTool:_,searchListTools:v,serverId:u,proxyMode:h,dispose:async()=>{try{await i.disconnectAll()}finally{p&&p.stopWatching(),await t.shutdown()}}}}catch(e){throw await t.shutdown(),e}}async function Ht(e){let t=await e();return X().createStdioTransportHandler(()=>Promise.resolve(t))}async function Ut(e,t){let n=await e();return X().createSseTransportHandler(()=>Promise.resolve(n),t)}function Wt(e,t,n){return X().createHttpTransportHandler(e,t,n)}function Gt(e){return X().createStdioHttpTransportHandler(e)}async function Kt(e){return Z(e)}function Q(e){let t=e.tools.map(e=>e.name),n=W(e.tools),r=n.length>0?`; capabilities: ${n.join(`, `)}`:``;return t.length===0?`${e.serverName} (no tools cached${r})`:`${e.serverName} (${t.join(`, `)})${r}`}function qt(e,t){let n=[`Proxied from server "${e.serverName}" as tool "${t.name}".`];e.serverInstruction&&n.push(`Server summary: ${e.serverInstruction}`),t.description&&!e.omitToolDescription&&n.push(t.description);let r=U(t);return r.length>0&&n.push(`Capabilities: ${r.join(`, `)}`),n.join(`
52
+
53
+ `)}function Jt(e){let t=new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=[];for(let r of e)for(let e of r.tools){let i=(t.get(e.name)||[]).length>1;n.push({name:i?`${r.serverName}__${e.name}`:e.name,description:qt(r,e),inputSchema:e.inputSchema,_meta:e._meta})}return n}async function Yt(e,t){let[n,r]=await Promise.all([t?t.getSkills():e.getCachedFileSkills(),e.getServerDefinitions()]);return n.length>0||r.some(e=>e.promptSkills.length>0)}function Xt(e,t){let n=e.length>0?e.map(Q).join(`; `):`No proxied servers available.`;return{name:H.TOOL_NAME,description:`Get detailed skill instructions for file-based skills and prompt-based skills proxied by mcp-proxy.\n\nProxy summary: ${n}\n\nUse this when you need the full instructions for a skill. For MCP tools, call the flat tool names directly. Only use skills discovered from describe_tools with id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function Zt(e,t){let n=e.length>0?e.map(Q).join(`; `):`No proxied servers available.`;return{name:H.TOOL_NAME,description:`Get detailed schemas and skill instructions for proxied MCP capabilities.\n\nProxy summary: ${n}\n\nUse list_tools first to search capability summaries and discover tool names. Then use describe_tools to fetch full schemas or skill instructions. Only use capabilities discovered from mcp-proxy id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of tool or skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function Qt(e,t,n){let r=e.length>0?e.map(Q).join(`; `):`No proxied servers available.`;return t===`flat`?[`mcp-proxy proxies downstream MCP servers and exposes their tools and resources directly.`,`Proxied servers and tools: ${r}`,n?`Skills are still exposed through describe_tools when file-based skills or prompt-backed skills are configured.`:`No skills are currently exposed through describe_tools.`].join(`
54
+
55
+ `):t===`search`?[`mcp-proxy proxies downstream MCP servers in search mode.`,`Proxied servers and tools: ${r}`,`Use list_tools to search capability summaries and discover tool names, describe_tools to fetch schemas or skill instructions, and use_tool to execute tools.`].join(`
56
+
57
+ `):[`mcp-proxy proxies downstream MCP servers in meta mode.`,`Proxied servers and tools: ${r}`,`Use describe_tools to inspect capabilities and use_tool to execute them.`].join(`
58
+
59
+ `)}async function $(e){let{clientManager:t,definitionsCacheService:n,skillService:r,describeTools:i,useTool:a,searchListTools:o,serverId:s,proxyMode:c}=e,l=new Ee({name:`@agimon-ai/mcp-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}},instructions:Qt(await n.getServerDefinitions(),c,await Yt(n,r))});return l.setRequestHandler(be,async()=>({tools:c===`flat`?await(async()=>{let e=await n.getServerDefinitions(),t=await Yt(n,r);return[...Jt(e),...t?[Xt(e,s)]:[]]})():c===`search`?await(async()=>[Zt(await n.getServerDefinitions(),s),await o.getDefinition(),a.getDefinition()])():[await i.getDefinition(),a.getDefinition()]})),l.setRequestHandler(he,async e=>{let{name:t,arguments:n}=e.params,r=async(e,t)=>{let r=se(n??{},e.getInputSchema());try{return await e.execute(r)}catch(n){if(n instanceof d.ZodError)return{content:[{type:`text`,text:ce(n,{schemaName:t,schema:e.getInputSchema()})}],isError:!0};throw Error(`Failed to execute ${t}: ${n instanceof Error?n.message:String(n)}`)}};if(t===H.TOOL_NAME)return await r(i,t);if(t===J.TOOL_NAME)return await r(a,t);if(t===K.TOOL_NAME&&c===`search`)return await r(o,t);if(c===`flat`)return await a.execute({toolName:t,toolArgs:n||{}});throw Error(`Unknown tool: ${t}`)}),l.setRequestHandler(ye,async()=>{let e=await n.getServerDefinitions(),t=new Map;for(let n of e)for(let e of n.resources)t.has(e.uri)||t.set(e.uri,[]),t.get(e.uri)?.push(n.serverName);let r=[];for(let n of e)for(let e of n.resources){let i=(t.get(e.uri)||[]).length>1;r.push({...e,uri:i?`${n.serverName}__${e.uri}`:e.uri})}return{resources:r}}),l.setRequestHandler(xe,async e=>{let{uri:r}=e.params,{serverName:i,actualToolName:a}=A(r);if(i)return await(await t.ensureConnected(i)).readResource(a);let o=await n.getServersForResource(a);if(o.length===0)throw Error(`Resource not found: ${r}`);if(o.length>1)throw Error(`Resource "${a}" exists on multiple servers: ${o.join(`, `)}. Use the prefixed format (e.g., "${o[0]}__${a}") to specify which server to use.`);return await(await t.ensureConnected(o[0])).readResource(a)}),l.setRequestHandler(ve,async()=>{let e=await n.getServerDefinitions(),t=new Map,r=new Map;for(let n of e){r.set(n.serverName,n.prompts);for(let e of n.prompts)t.has(e.name)||t.set(e.name,[]),t.get(e.name).push(n.serverName)}let i=[];for(let n of e){let e=r.get(n.serverName)||[];for(let r of e){let e=(t.get(r.name)||[]).length>1;i.push({name:e?`${n.serverName}__${r.name}`:r.name,description:r.description,arguments:r.arguments})}}return{prompts:i}}),l.setRequestHandler(_e,async e=>{let{name:r,arguments:i}=e.params,a=await n.getServerDefinitions(),{serverName:o,actualToolName:s}=A(r);if(o)return await(await t.ensureConnected(o)).getPrompt(s,i);let c=[];for(let e of a)e.prompts.some(e=>e.name===r)&&c.push(e.serverName);if(c.length===0)throw Error(`Prompt not found: ${r}`);if(c.length>1)throw Error(`Prompt "${r}" exists on multiple servers: ${c.join(`, `)}. Use the prefixed format (e.g., "${c[0]}__${r}") to specify which server to use.`);let l=t.getClient(c[0]);return l?await l.getPrompt(r,i):await(await t.ensureConnected(c[0])).getPrompt(r,i)}),l}async function $t(e){let t=await Z(e),n=await $(t);return Object.assign(n,{dispose:t.dispose}),n}const en={STDIO:`stdio`,HTTP:`http`,SSE:`sse`};export{N as C,S as D,qe as E,it as S,Ye as T,H as _,Z as a,L as b,Gt as c,Vt as d,Ft as f,K as g,J as h,Wt as i,Ht as l,jt as m,$t as n,X as o,Pt as p,$ as r,Ut as s,en as t,Kt as u,Tt as v,Xe as w,ct as x,_t as y};
@@ -0,0 +1,59 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`node:fs`),l=require(`node:fs/promises`),u=require(`js-yaml`);u=s(u);let d=require(`zod`),f=require(`node:crypto`),p=require(`node:os`),m=require(`node:path`),ee=require(`@agimon-ai/log-sink-mcp`),h=require(`@modelcontextprotocol/sdk/client/index.js`),te=require(`@modelcontextprotocol/sdk/client/sse.js`),ne=require(`@modelcontextprotocol/sdk/client/stdio.js`),re=require(`@modelcontextprotocol/sdk/client/streamableHttp.js`),ie=require(`@agimon-ai/foundation-process-registry`),ae=require(`node:child_process`),oe=require(`liquidjs`),g=require(`@agimon-ai/foundation-validator`),se=require(`node:events`),ce=require(`node:http`),le=require(`node:util`),ue=require(`@hono/node-server`),de=require(`@modelcontextprotocol/sdk/server/streamableHttp.js`),_=require(`@modelcontextprotocol/sdk/types.js`),fe=require(`hono`),pe=require(`@modelcontextprotocol/sdk/server/sse.js`),me=require(`@modelcontextprotocol/sdk/server/stdio.js`),v=require(`@modelcontextprotocol/sdk/server/index.js`);var y=`0.10.5`;function b(e){return e.replace(/\$\{([^}]+)\}/g,(e,t)=>{let n=process.env[t];return n===void 0?(console.warn(`Environment variable ${t} is not defined, keeping placeholder`),`\${${t}}`):n})}function x(e){if(typeof e==`string`)return b(e);if(Array.isArray(e))return e.map(e=>x(e));if(typeof e==`object`&&e){let t={};for(let[n,r]of Object.entries(e))t[n]=x(r);return t}return e}const he=[/^127\./,/^10\./,/^172\.(1[6-9]|2\d|3[01])\./,/^192\.168\./,/^169\.254\./,/^0\./,/^224\./,/^240\./,/^localhost$/i,/^.*\.localhost$/i,/^\[::\]/,/^\[::1\]/,/^\[0:0:0:0:0:0:0:1\]/,/^\[0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:0{1,4}:1\]/i,/^\[fe80:/i,/^\[fc00:/i,/^\[fd00:/i,/^\[::ffff:127\./i,/^\[::ffff:7f[0-9a-f]{2}:/i,/^\[::ffff:10\./i,/^\[::ffff:a[0-9a-f]{2}:/i,/^\[::ffff:172\.(1[6-9]|2\d|3[01])\./i,/^\[::ffff:ac1[0-9a-f]:/i,/^\[::ffff:192\.168\./i,/^\[::ffff:c0a8:/i,/^\[::ffff:169\.254\./i,/^\[::ffff:a9fe:/i,/^\[::ffff:0\./i,/^\[::127\./i,/^\[::7f[0-9a-f]{2}:/i,/^\[::10\./i,/^\[::a[0-9a-f]{2}:/i,/^\[::192\.168\./i,/^\[::c0a8:/i];function ge(e,t){let n=t?.allowPrivateIPs??!1,r=t?.enforceHttps??!0,i;try{i=new URL(e)}catch{throw Error(`Invalid URL format: ${e}`)}let a=i.protocol.replace(`:`,``);if(r&&a!==`https`)throw Error(`HTTPS is required for security. URL uses '${a}://'. Set security.enforceHttps: false to allow HTTP.`);if(a!==`http`&&a!==`https`)throw Error(`Invalid URL protocol '${a}://'. Only http:// and https:// are allowed.`);if(!n){let e=i.hostname.toLowerCase();if(he.some(t=>t.test(e)))throw Error(`Private IP addresses and localhost are blocked for security (${e}). Set security.allowPrivateIPs: true to allow internal networks.`)}}function _e(e){let t=b(e.url);if(ge(t,e.security),e.validation){if(e.validation.url&&!new RegExp(e.validation.url).test(t))throw Error(`Remote config URL "${t}" does not match validation pattern: ${e.validation.url}`);if(e.validation.headers&&Object.keys(e.validation.headers).length>0){if(!e.headers){let t=Object.keys(e.validation.headers);throw Error(`Remote config is missing required headers: ${t.join(`, `)}`)}for(let[t,n]of Object.entries(e.validation.headers)){if(!(t in e.headers))throw Error(`Remote config is missing required header: ${t}`);let r=b(e.headers[t]);if(!new RegExp(n).test(r))throw Error(`Remote config header "${t}" value "${r}" does not match validation pattern: ${n}`)}}}}const ve=d.z.object({name:d.z.string(),description:d.z.string(),folder:d.z.string().optional()}),ye=d.z.object({skill:ve.optional()}),be=d.z.object({instruction:d.z.string().optional(),toolBlacklist:d.z.array(d.z.string()).optional(),omitToolDescription:d.z.boolean().optional(),prompts:d.z.record(d.z.string(),ye).optional()}).optional(),xe=d.z.object({command:d.z.string(),args:d.z.array(d.z.string()).optional(),env:d.z.record(d.z.string(),d.z.string()).optional(),disabled:d.z.boolean().optional(),instruction:d.z.string().optional(),timeout:d.z.number().positive().optional(),requestTimeout:d.z.number().positive().optional(),config:be}),Se=d.z.object({url:d.z.string().url(),headers:d.z.record(d.z.string(),d.z.string()).optional(),type:d.z.enum([`http`,`sse`]).optional(),disabled:d.z.boolean().optional(),instruction:d.z.string().optional(),timeout:d.z.number().positive().optional(),requestTimeout:d.z.number().positive().optional(),config:be}),Ce=d.z.union([xe,Se]),we=d.z.object({url:d.z.string().optional(),headers:d.z.record(d.z.string(),d.z.string()).optional()}).optional(),Te=d.z.object({allowPrivateIPs:d.z.boolean().optional(),enforceHttps:d.z.boolean().optional()}).optional(),Ee=d.z.object({url:d.z.string(),headers:d.z.record(d.z.string(),d.z.string()).optional(),validation:we,security:Te,mergeStrategy:d.z.enum([`local-priority`,`remote-priority`,`merge-deep`]).optional()}),De=d.z.object({paths:d.z.array(d.z.string())}),Oe=d.z.object({type:d.z.enum([`stdio`,`http`,`sse`,`stdio-http`]).optional(),port:d.z.number().int().positive().optional(),host:d.z.string().optional(),keepAlive:d.z.boolean().optional()}).optional(),ke=d.z.object({id:d.z.string().optional(),proxy:Oe,mcpServers:d.z.record(d.z.string(),Ce),remoteConfigs:d.z.array(Ee).optional(),skills:De.optional()}),Ae=d.z.object({command:d.z.string(),args:d.z.array(d.z.string()).optional(),env:d.z.record(d.z.string(),d.z.string()).optional()}),je=d.z.object({url:d.z.string().url(),headers:d.z.record(d.z.string(),d.z.string()).optional()}),Me=d.z.object({url:d.z.string().url(),headers:d.z.record(d.z.string(),d.z.string()).optional()}),Ne=d.z.object({name:d.z.string(),description:d.z.string(),folder:d.z.string().optional()}),S=d.z.object({skill:Ne.optional()}),Pe=d.z.discriminatedUnion(`transport`,[d.z.object({name:d.z.string(),instruction:d.z.string().optional(),toolBlacklist:d.z.array(d.z.string()).optional(),omitToolDescription:d.z.boolean().optional(),prompts:d.z.record(d.z.string(),S).optional(),timeout:d.z.number().positive().optional(),requestTimeout:d.z.number().positive().optional(),transport:d.z.literal(`stdio`),config:Ae}),d.z.object({name:d.z.string(),instruction:d.z.string().optional(),toolBlacklist:d.z.array(d.z.string()).optional(),omitToolDescription:d.z.boolean().optional(),prompts:d.z.record(d.z.string(),S).optional(),timeout:d.z.number().positive().optional(),requestTimeout:d.z.number().positive().optional(),transport:d.z.literal(`http`),config:je}),d.z.object({name:d.z.string(),instruction:d.z.string().optional(),toolBlacklist:d.z.array(d.z.string()).optional(),omitToolDescription:d.z.boolean().optional(),prompts:d.z.record(d.z.string(),S).optional(),timeout:d.z.number().positive().optional(),requestTimeout:d.z.number().positive().optional(),transport:d.z.literal(`sse`),config:Me})]),Fe=d.z.object({id:d.z.string().optional(),proxy:Oe,mcpServers:d.z.record(d.z.string(),Pe),skills:De.optional()});function Ie(e){let t={};for(let[n,r]of Object.entries(e.mcpServers))if(!(`disabled`in r&&r.disabled===!0)){if(`command`in r){let e=r,i=b(e.command),a=e.args?.map(e=>b(e)),o=e.env?x(e.env):void 0;t[n]={name:n,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:`stdio`,config:{command:i,args:a,env:o}}}else if(`url`in r){let e=r,i=e.type===`sse`?`sse`:`http`,a=b(e.url),o=e.headers?x(e.headers):void 0;t[n]={name:n,instruction:e.instruction||e.config?.instruction,toolBlacklist:e.config?.toolBlacklist,omitToolDescription:e.config?.omitToolDescription,prompts:e.config?.prompts,timeout:e.timeout,requestTimeout:e.requestTimeout,transport:i,config:{url:a,headers:o}}}}return{id:e.id,proxy:e.proxy,mcpServers:t,skills:e.skills}}function Le(e){let t=Ie(ke.parse(e));return Fe.parse(t)}var Re=class{cacheDir;cacheTTL;readEnabled;writeEnabled;logger;constructor(e,t=console){this.cacheDir=(0,m.join)((0,p.tmpdir)(),`mcp-proxy-cache`,`remote-configs`),this.cacheTTL=e?.ttl||3600*1e3,this.readEnabled=e?.readEnabled===void 0?!0:e.readEnabled,this.writeEnabled=e?.writeEnabled===void 0?!0:e.writeEnabled,this.logger=t}generateCacheKey(e){return(0,f.createHash)(`sha256`).update(e).digest(`hex`)}getCacheFilePath(e){return(0,m.join)(this.cacheDir,`${e}.json`)}async ensureCacheDir(){try{await(0,l.mkdir)(this.cacheDir,{recursive:!0})}catch(e){if(e?.code!==`EEXIST`)throw e}}async get(e){if(!this.readEnabled)return null;try{await this.ensureCacheDir();let t=this.generateCacheKey(e),n=this.getCacheFilePath(t);if(!(0,c.existsSync)(n))return null;let r=await(0,l.readFile)(n,`utf-8`),i=JSON.parse(r),a=Date.now();if(a>i.expiresAt)return await(0,l.unlink)(n).catch(()=>{}),null;let o=Math.round((i.expiresAt-a)/1e3);return this.logger.debug(`Remote config cache hit for ${e} (expires in ${o}s)`),i.data}catch(t){return this.logger.warn(`Failed to read remote config cache for ${e}`,t),null}}async set(e,t){if(this.writeEnabled)try{await this.ensureCacheDir();let n=this.generateCacheKey(e),r=this.getCacheFilePath(n),i=Date.now(),a={data:t,timestamp:i,expiresAt:i+this.cacheTTL,url:e};await(0,l.writeFile)(r,JSON.stringify(a,null,2),`utf-8`),this.logger.debug(`Cached remote config for ${e} (TTL: ${Math.round(this.cacheTTL/1e3)}s)`)}catch(t){this.logger.warn(`Failed to write remote config cache for ${e}`,t)}}async clear(e){try{let t=this.generateCacheKey(e),n=this.getCacheFilePath(t);(0,c.existsSync)(n)&&(await(0,l.unlink)(n),this.logger.info(`Cleared remote config cache for ${e}`))}catch(t){this.logger.warn(`Failed to clear remote config cache for ${e}`,t)}}async clearAll(){try{if(!(0,c.existsSync)(this.cacheDir))return;let e=await(0,l.readdir)(this.cacheDir),t=e.filter(e=>e.endsWith(`.json`)).map(e=>(0,l.unlink)((0,m.join)(this.cacheDir,e)).catch(t=>{this.logger.debug(`Failed to delete remote config cache file ${e}`,t)}));await Promise.all(t),this.logger.info(`Cleared all remote config cache entries (${e.length} files)`)}catch(e){this.logger.warn(`Failed to clear all remote config cache`,e)}}async cleanExpired(){try{if(!(0,c.existsSync)(this.cacheDir))return;let e=Date.now(),t=(await(0,l.readdir)(this.cacheDir)).filter(e=>e.endsWith(`.json`)),n=(await Promise.all(t.map(async t=>{let n=(0,m.join)(this.cacheDir,t);try{let t=await(0,l.readFile)(n,`utf-8`);return e>JSON.parse(t).expiresAt?(await(0,l.unlink)(n),!0):!1}catch(e){return await(0,l.unlink)(n).catch(()=>{this.logger.debug(`Failed to delete corrupt cache file ${n}`,e)}),this.logger.warn(`Removed unreadable remote config cache file ${n}`,e),!0}}))).filter(Boolean).length;n>0&&this.logger.info(`Cleaned up ${n} expired remote config cache entries`)}catch(e){this.logger.warn(`Failed to clean expired remote config cache`,e)}}async getStats(){try{if(!(0,c.existsSync)(this.cacheDir))return{totalEntries:0,totalSize:0};let e=(await(0,l.readdir)(this.cacheDir)).filter(e=>e.endsWith(`.json`)),t=(await Promise.all(e.map(async e=>{let t=(0,m.join)(this.cacheDir,e);try{let e=await(0,l.readFile)(t,`utf-8`);return Buffer.byteLength(e,`utf-8`)}catch{return 0}}))).reduce((e,t)=>e+t,0);return{totalEntries:e.length,totalSize:t}}catch(e){return this.logger.warn(`Failed to get remote config cache stats`,e),{totalEntries:0,totalSize:0}}}isReadEnabled(){return this.readEnabled}isWriteEnabled(){return this.writeEnabled}setReadEnabled(e){this.readEnabled=e}setWriteEnabled(e){this.writeEnabled=e}},ze=class{configFilePath;cacheTtlMs;cachedConfig=null;lastFetchTime=0;remoteConfigCache;logger;constructor(e,t=console){this.configFilePath=e.configFilePath,this.cacheTtlMs=e.cacheTtlMs||6e4,this.logger=t;let n=e.useCache===void 0?!0:e.useCache;if(this.remoteConfigCache=new Re({ttl:e.remoteCacheTtlMs||3600*1e3,readEnabled:n,writeEnabled:!0},t),!this.configFilePath)throw Error(`configFilePath must be provided`)}async fetchConfiguration(e=!1){let t=Date.now();if(!e&&this.cachedConfig&&t-this.lastFetchTime<this.cacheTtlMs)return this.cachedConfig;let n=await this.loadRawConfigFromFile(),r=n.remoteConfigs||[],i=await this.parseConfig(n),a=r.map(async e=>{try{return _e(e),{config:await this.loadFromUrl(e),mergeStrategy:e.mergeStrategy||`local-priority`,url:e.url}}catch(t){return this.logger.warn(`Failed to fetch remote config from ${e.url}`,t),null}}),o=await Promise.all(a);for(let e of o)e!==null&&(i=this.mergeConfigurations(i,e.config,e.mergeStrategy));if(!i.mcpServers||typeof i.mcpServers!=`object`)throw Error(`Invalid MCP configuration: missing or invalid mcpServers`);return this.cachedConfig=i,this.lastFetchTime=t,i}async loadRawConfigFromFile(){if(!this.configFilePath)throw Error(`No config file path provided`);if(!(0,c.existsSync)(this.configFilePath))throw Error(`Config file not found: ${this.configFilePath}`);try{let e=await(0,l.readFile)(this.configFilePath,`utf-8`),t;return t=this.configFilePath.endsWith(`.yaml`)||this.configFilePath.endsWith(`.yml`)?u.default.load(e):JSON.parse(e),t}catch(e){throw e instanceof Error?Error(`Failed to load config file: ${e.message}`):Error(`Failed to load config file: Unknown error`)}}async parseConfig(e){try{let{remoteConfigs:t,...n}=e;return Le(n)}catch(e){throw e instanceof Error?Error(`Failed to parse config: ${e.message}`):Error(`Failed to parse config: Unknown error`)}}async loadFromUrl(e){try{let t=this.interpolateEnvVars(e.url),n=await this.remoteConfigCache.get(t);if(n)return n;let r=e.headers?Object.fromEntries(Object.entries(e.headers).map(([e,t])=>[e,this.interpolateEnvVars(t)])):{},i=await fetch(t,{headers:r,signal:AbortSignal.timeout(3e4)});if(!i.ok)throw Error(`Failed to fetch remote config: ${i.status} ${i.statusText}`);let a=Le(await i.json());return await this.remoteConfigCache.set(t,a),a}catch(t){throw t instanceof Error?Error(`Failed to fetch remote config from ${e.url}: ${t.message}`,{cause:t}):Error(`Failed to fetch remote config from ${e.url}: Unknown error`)}}interpolateEnvVars(e){return e.replace(/\$\{([^}]+)\}/g,(e,t)=>{let n=process.env[t];return n===void 0?(this.logger.warn(`Environment variable ${t} is not defined, keeping placeholder`),`\${${t}}`):n})}mergeConfigurations(e,t,n){switch(n){case`local-priority`:return{id:e.id??t.id,mcpServers:{...t.mcpServers,...e.mcpServers},skills:e.skills??t.skills};case`remote-priority`:return{id:t.id??e.id,mcpServers:{...e.mcpServers,...t.mcpServers},skills:t.skills??e.skills};case`merge-deep`:{let n={...t.mcpServers};for(let[t,r]of Object.entries(e.mcpServers))if(n[t]){let e=n[t],i={...e.config,...r.config},a=`env`in e.config?e.config.env:void 0,o=`env`in r.config?r.config.env:void 0;(a||o)&&(i.env={...a||{},...o||{}});let s=`headers`in e.config?e.config.headers:void 0,c=`headers`in r.config?r.config.headers:void 0;(s||c)&&(i.headers={...s||{},...c||{}}),n[t]={...e,...r,config:i}}else n[t]=r;return{id:e.id??t.id,mcpServers:n,skills:e.skills??t.skills}}default:throw Error(`Unknown merge strategy: ${n}`)}}clearCache(){this.cachedConfig=null,this.lastFetchTime=0}isCacheValid(){let e=Date.now();return this.cachedConfig!==null&&e-this.lastFetchTime<this.cacheTtlMs}};const Be=`[skill-detection]`;function Ve(){let e=[`mcp-config.yaml`,`mcp-config.yml`,`mcp-config.json`],t=process.env.PROJECT_PATH;if(t)for(let n of e){let e=(0,m.resolve)(t,n);if((0,c.existsSync)(e))return e}let n=process.cwd();for(let t=0;t<=3;t++){for(let t of e){let e=(0,m.join)(n,t);if((0,c.existsSync)(e))return e}let t=(0,m.dirname)(n);if(t===n)break;n=t}return null}function He(e=6){let t=``,n=e;for(;n>0;){let e=(0,f.randomBytes)(n);for(let r=0;r<e.length&&n>0;r++){let i=e[r];i>247||(t+=`23456789abcdefghjkmnpqrstuvwxyz`[i%31],n--)}}return t}function Ue(e){let t=e.trimStart();if(!t.startsWith(`---`))return{frontMatter:null,content:e};let n=t.indexOf(`
2
+ ---`,3);if(n===-1)return{frontMatter:null,content:e};let r=t.slice(4,n).trim();if(!r)return{frontMatter:null,content:e};let i={},a=r.split(`
3
+ `),o=null,s=[],c=null,l=0,u=()=>{o&&s.length>0&&(c===`literal`?i[o]=s.join(`
4
+ `).trimEnd():c===`folded`?i[o]=s.join(` `).trim():i[o]=s.join(``).trim()),o=null,s=[],c=null,l=0};for(let e=0;e<a.length;e++){let t=a[e],n=t.trim(),r=t.indexOf(`:`);if(r!==-1&&!t.startsWith(` `)&&!t.startsWith(` `)){u();let n=t.slice(0,r).trim(),s=t.slice(r+1).trim();if(s===`|`||s===`|-`){if(o=n,c=`literal`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else if(s===`>`||s===`>-`){if(o=n,c=`folded`,e+1<a.length){let t=a[e+1].match(/^(\s+)/);l=t?t[1].length:2}}else (s.startsWith(`"`)&&s.endsWith(`"`)||s.startsWith(`'`)&&s.endsWith(`'`))&&(s=s.slice(1,-1)),n&&s&&(i[n]=s)}else if(c&&o){let e=t.match(/^(\s*)/)?.[1].length||0;if(n===``)s.push(``);else if(e>=l){let e=t.slice(l);s.push(e)}else u()}}return u(),{frontMatter:i,content:t.slice(n+4).trimStart()}}function We(e){return e!==null&&typeof e.name==`string`&&e.name.length>0&&typeof e.description==`string`&&e.description.length>0}function Ge(e){let{frontMatter:t,content:n}=Ue(e);return t&&We(t)?{skill:{name:t.name,description:t.description},content:n}:null}function C(e){let t=e.indexOf(`__`);return t>0?{serverName:e.substring(0,t),actualToolName:e.substring(t+2)}:{actualToolName:e}}function Ke(e){return e.endsWith(`.yaml`)||e.endsWith(`.yml`)}function w(e){return e instanceof Error?e.message:String(e)}function qe(e){let t=(0,m.resolve)(e),n=t.length>=2&&t[1]===`:`&&(t[0]>=`A`&&t[0]<=`Z`||t[0]>=`a`&&t[0]<=`z`)?`${t[0].toLowerCase()}${t.slice(1)}`:t,r=``,i=!1;for(let e of n){if(e>=`a`&&e<=`z`||e>=`A`&&e<=`Z`||e>=`0`&&e<=`9`||e===`.`||e===`_`||e===`-`){r+=e,i=!1;continue}i||=(r+=`_`,!0)}let a=0,o=r.length;for(;a<o&&r[a]===`_`;)a+=1;for(;o>a&&r[o-1]===`_`;)--o;return r.slice(a,o)}function T(e){return{...e,failures:[...e.failures??[]],skills:(e.skills??[]).map(e=>({...e})),servers:Object.fromEntries(Object.entries(e.servers).map(([e,t])=>[e,{...t,tools:(t.tools??[]).map(e=>({...e})),resources:(t.resources??[]).map(e=>({...e})),prompts:(t.prompts??[]).map(e=>({...e,arguments:e.arguments?.map(e=>({...e}))})),promptSkills:(t.promptSkills??[]).map(e=>({...e,skill:{...e.skill}}))}]))}}var E=class{clientManager;skillService;cacheData;liveDefinitionsPromise=null;mergedDefinitionsPromise=null;logger;constructor(e,t,n,r=console){this.clientManager=e,this.skillService=t,this.cacheData=n?.cacheData,this.logger=r}static async readFromFile(e){let t=await(0,l.readFile)(e,`utf-8`),n=Ke(e)?u.default.load(t):JSON.parse(t);if(!n||typeof n!=`object`)throw Error(`Definitions cache must be an object`);let r=n;if(r.version!==1||!r.servers)throw Error(`Definitions cache is missing required fields`);return{...r,failures:Array.isArray(r.failures)?r.failures:[],skills:Array.isArray(r.skills)?r.skills:[],servers:Object.fromEntries(Object.entries(r.servers).map(([e,t])=>[e,{...t,tools:Array.isArray(t.tools)?t.tools:[],resources:Array.isArray(t.resources)?t.resources:[],prompts:Array.isArray(t.prompts)?t.prompts:[],promptSkills:Array.isArray(t.promptSkills)?t.promptSkills:[]}]))}}static async writeToFile(e,t){let n=Ke(e)?u.default.dump(t,{noRefs:!0}):JSON.stringify(t,null,2);await(0,l.mkdir)((0,m.dirname)(e),{recursive:!0}),await(0,l.writeFile)(e,n,`utf-8`)}static getDefaultCachePath(e){let t=qe(e);return(0,m.join)((0,p.homedir)(),`.aicode-toolkit`,`${t}.definitions-cache.json`)}static generateConfigHash(e){return(0,f.createHash)(`sha256`).update(JSON.stringify(e)).digest(`hex`)}static isCacheValid(e,t){return!(t.configHash&&e.configHash&&e.configHash!==t.configHash||t.oneMcpVersion&&e.oneMcpVersion&&e.oneMcpVersion!==t.oneMcpVersion)}static async clearFile(e){await(0,l.rm)(e,{force:!0})}clearLiveCache(){this.liveDefinitionsPromise=null,this.mergedDefinitionsPromise=null}setCacheData(e){this.cacheData=e,this.mergedDefinitionsPromise=null}async collectForCache(e){let t=await this.collectLiveDefinitions(e);return this.setCacheData(t),this.liveDefinitionsPromise=Promise.resolve(T(t)),T(t)}async getDefinitions(){return this.mergedDefinitionsPromise||=(async()=>{let e=this.clientManager.getAllClients();if(!this.cacheData)return this.getLiveDefinitions();let t=e.map(e=>e.serverName).filter(e=>!this.cacheData?.servers[e]);if(t.length===0)return T(this.cacheData);let n=await this.getLiveDefinitions(),r=T(this.cacheData);for(let e of t){let t=n.servers[e];t&&(r.servers[e]=t)}let i=new Map;for(let e of[...r.failures,...n.failures])i.set(e.serverName,e.error);return r.failures=Array.from(i.entries()).map(([e,t])=>({serverName:e,error:t})),r.skills.length===0&&n.skills.length>0&&(r.skills=n.skills.map(e=>({...e}))),r})(),this.mergedDefinitionsPromise}async getServerDefinitions(){let e=await this.getDefinitions(),t=this.clientManager.getKnownServerNames();return t.length===0?Object.values(e.servers):t.map(t=>e.servers[t]).filter(e=>e!==void 0)}async getServersForTool(e){return(await this.getServerDefinitions()).filter(t=>t.tools.some(t=>t.name===e)).map(e=>e.serverName)}async getToolSchema(e,t){return(await this.getDefinitions()).servers[e]?.tools.find(e=>e.name===t)?.inputSchema}async getServersForResource(e){return(await this.getServerDefinitions()).filter(t=>t.resources.some(t=>t.uri===e)).map(e=>e.serverName)}async getPromptSkillByName(e){let t=await this.getDefinitions();for(let[n,r]of Object.entries(t.servers))for(let t of r.promptSkills)if(t.skill.name===e)return{serverName:n,promptName:t.promptName,skill:t.skill,autoDetected:t.autoDetected}}async getCachedFileSkills(){return(await this.getDefinitions()).skills.map(e=>({...e}))}async getLiveDefinitions(){return this.liveDefinitionsPromise||=this.collectLiveDefinitions(),this.liveDefinitionsPromise}async collectLiveDefinitions(e){let t=this.clientManager.getAllClients(),n=[],r={},i=await Promise.all(t.map(async e=>{try{let t=await e.listTools(),n=await this.listResourcesSafe(e),r=await this.listPromptsSafe(e),i=new Set(e.toolBlacklist||[]),a=t.filter(e=>!i.has(e.name)),o=await this.collectPromptSkillsForClient(e,r);return{serverName:e.serverName,serverInstruction:e.serverInstruction,omitToolDescription:e.omitToolDescription,toolBlacklist:e.toolBlacklist,tools:a.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema,_meta:e._meta})),resources:n,prompts:r,promptSkills:o}}catch(t){return n.push({serverName:e.serverName,error:w(t)}),null}}));for(let e of i)e&&(r[e.serverName]=e);return{version:1,oneMcpVersion:e?.oneMcpVersion,generatedAt:new Date().toISOString(),configPath:e?.configPath,configHash:e?.configHash,serverId:e?.serverId,servers:r,skills:await this.collectFileSkills(),failures:n}}async collectFileSkills(){return this.skillService?(await this.skillService.getSkills()).map(e=>this.toCachedFileSkill(e)):[]}toCachedFileSkill(e){return{name:e.name,description:e.description,location:e.location,basePath:e.basePath}}async listPromptsSafe(e){try{return(await e.listPrompts()).map(e=>({name:e.name,description:e.description,arguments:e.arguments?.map(e=>({...e}))}))}catch(t){return this.logger.warn(`${Be} Failed to list prompts from ${e.serverName}: ${w(t)}`),[]}}async listResourcesSafe(e){try{return(await e.listResources()).map(e=>({uri:e.uri,name:e.name,description:e.description,mimeType:e.mimeType}))}catch(t){return this.logger.warn(`[capability-discovery] Failed to list resources from ${e.serverName}: ${w(t)}`),[]}}async collectPromptSkillsForClient(e,t){let n=new Set(e.prompts?Object.keys(e.prompts):[]),r=[];if(e.prompts)for(let[t,n]of Object.entries(e.prompts))n.skill&&r.push({promptName:t,skill:{...n.skill}});let i=t.filter(e=>!n.has(e.name)).slice(0,50),a=await Promise.all(i.map(async t=>{try{let n=Ge((await e.getPrompt(t.name)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
5
+ `)||``);return n?{promptName:t.name,skill:n.skill,autoDetected:!0}:null}catch(n){return this.logger.warn(`${Be} Failed to fetch prompt '${t.name}' from ${e.serverName}: ${w(n)}`),null}}));for(let e of a)e&&r.push(e);return r}};function Je(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function D(e){if(e!==void 0)return e instanceof Error?{exception:e}:Je(e)&&(`attributes`in e||`exception`in e||`context`in e)?e:Je(e)?{attributes:e}:{attributes:{value:e}}}function Ye(e){let t=e.logger;return{backend:e.backend,enabled:e.enabled,endpoint:e.endpoint,filePath:e.filePath,trace(e,n){t.trace(e,D(n))},debug(e,n){t.debug(e,D(n))},info(e,n){t.info(e,D(n))},warn(e,n){t.warn(e,D(n))},error(e,n){t.error(e,D(n))},getTraceContext(){return t.getTraceContext()},flush:()=>e.flush(),shutdown:()=>e.shutdown()}}async function O(e={}){return Ye(await(0,ee.createNodeTelemetry)({env:e.env,workspaceRoot:e.workspaceRoot,serviceName:e.serviceName??`@agimon-ai/mcp-proxy`,serviceVersion:e.serviceVersion,logDir:e.logDir,logFileName:e.logFileName,maxFileSizeBytes:e.maxFileSizeBytes,maxFileCount:e.maxFileCount}))}function k(e){return Ze(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=Xe(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function Xe(e){return typeof e==`string`?e.toLowerCase():void 0}function Ze(e){let t=new Set,n=[],r=e;for(;r&&!t.has(r);){if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause;continue}if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:String(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause;continue}n.push({message:String(r)});break}return n}var A=class{serverName;serverInstruction;toolBlacklist;omitToolDescription;prompts;transport;logger;client;childProcess;processLease;connected=!1;reconnectFn;reconnectPromise;constructor(e,t,n,r,i){this.serverName=e,this.serverInstruction=i.instruction,this.toolBlacklist=i.toolBlacklist,this.omitToolDescription=i.omitToolDescription,this.prompts=i.prompts,this.transport=t,this.logger=r,this.client=n}setChildProcess(e){this.childProcess=e}setProcessLease(e){this.processLease=e}setConnected(e){this.connected=e}setReconnectFn(e){this.reconnectFn=e}async reconnectClient(){if(!this.reconnectFn)throw Error(`No reconnect function configured for ${this.serverName}`);let e=this.reconnectFn;this.reconnectPromise||=(async()=>{try{await this.client.close()}catch(e){this.logger.warn(`Failed to close stale client for ${this.serverName}`,e)}let t=await e();this.client=t.client,t.childProcess&&(this.childProcess=t.childProcess)})();try{await this.reconnectPromise}finally{this.reconnectPromise&&=void 0}}async withSessionRetry(e){let t=0;for(;;)try{return await e()}catch(e){if(!this.reconnectFn||!k(e)||t>=2)throw e;for(t+=1,this.logger.warn(`Session error for ${this.serverName}, reconnecting: ${e instanceof Error?e.message:String(e)}`);;)try{await this.reconnectClient();break}catch(e){if(!k(e)||t>=2)throw e;this.logger.warn(`Reconnect attempt ${String(t)} for ${this.serverName} failed, retrying: ${e instanceof Error?e.message:String(e)}`),t+=1}}}async listTools(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listTools()).tools)}async listResources(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listResources()).resources)}async listPrompts(){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>(await this.client.listPrompts()).prompts)}async callTool(e,t,n){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>{let r=n?.timeout?{timeout:n.timeout}:void 0;return await this.client.callTool({name:e,arguments:t},void 0,r)})}async readResource(e){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>await this.client.readResource({uri:e}))}async getPrompt(e,t){if(!this.connected)throw Error(`Client for ${this.serverName} is not connected`);return this.withSessionRetry(async()=>await this.client.getPrompt({name:e,arguments:t}))}async close(){let e=this.childProcess,t=this.processLease;this.childProcess=void 0,this.processLease=void 0,this.connected=!1;try{e&&e.kill(),await this.client.close()}finally{await t?.release({kill:!1,releasePort:!1})}}},j=class{clients=new Map;serverConfigs=new Map;connectionPromises=new Map;logger;repositoryPath;constructor(e=console,t=process.cwd()){this.logger=e,this.repositoryPath=t}async cleanupChildProcesses(){await this.disconnectAll()}async connectToServer(e,t){this.serverConfigs.set(e,t),await this.ensureConnected(e)}registerServerConfigs(e){for(let[t,n]of Object.entries(e))this.serverConfigs.set(t,n)}getKnownServerNames(){return Array.from(this.serverConfigs.keys())}getServerRequestTimeout(e){return this.serverConfigs.get(e)?.requestTimeout}async ensureConnected(e){let t=this.clients.get(e);if(t)return t;let n=this.connectionPromises.get(e);if(n)return await n;let r=this.serverConfigs.get(e);if(!r)throw Error(`No configuration found for server "${e}"`);let i=this.createConnection(e,r);this.connectionPromises.set(e,i);try{return await i}finally{this.connectionPromises.delete(e)}}async createConnection(e,t){let n=t.timeout??3e4,r=new h.Client({name:`@agimon-ai/mcp-proxy-client`,version:`0.1.0`},{capabilities:{}}),i=new A(e,t.transport,r,this.logger,{instruction:t.instruction,toolBlacklist:t.toolBlacklist,omitToolDescription:t.omitToolDescription,prompts:t.prompts});try{if(await Promise.race([this.performConnection(i,t),new Promise((e,t)=>setTimeout(()=>t(Error(`Connection timeout after ${n}ms`)),n))]),i.setConnected(!0),(t.transport===`http`||t.transport===`sse`)&&i.setReconnectFn(async()=>{try{let n=new h.Client({name:`@agimon-ai/mcp-proxy-client`,version:`0.1.0`},{capabilities:{}}),r=new A(e,t.transport,n,this.logger,{});return await this.performConnection(r,t),{client:n}}catch(t){throw this.logger.warn(`Failed to reconnect to ${e}`,t),t}}),!i.serverInstruction)try{let e=i.client.getInstructions();e&&(i.serverInstruction=e)}catch(t){this.logger.warn(`Failed to get server instruction from ${e}`,t)}return this.clients.set(e,i),i}catch(e){throw await i.close(),e}}async performConnection(e,t){if(t.transport===`stdio`)await this.connectStdioClient(e,t.config);else if(t.transport===`http`)await this.connectHttpClient(e,t.config);else if(t.transport===`sse`)await this.connectSseClient(e,t.config);else throw Error(`Unsupported transport type: ${t.transport}`)}async connectStdioClient(e,t){let n=new ne.StdioClientTransport({command:t.command,args:t.args,env:{...process.env,...t.env??{}}});await e.client.connect(n);let r=n._process;if(r){if(typeof r.pid!=`number`||r.pid<=0)throw Error(`Failed to capture pid for stdio child process on server "${e.serverName}"`);e.setChildProcess(r);let n=await(0,ie.createProcessLease)({repositoryPath:this.repositoryPath,serviceName:e.serverName,serviceType:`tool`,pid:r.pid,command:t.command,args:t.args,metadata:{transport:`stdio`}});e.setProcessLease(n);return}throw Error(`Failed to capture stdio child process for server "${e.serverName}"`)}async connectHttpClient(e,t){let n=new re.StreamableHTTPClientTransport(new URL(t.url),{requestInit:t.headers?{headers:t.headers}:void 0});await e.client.connect(n)}async connectSseClient(e,t){let n=new te.SSEClientTransport(new URL(t.url));await e.client.connect(n)}getClient(e){return this.clients.get(e)}getAllClients(){return Array.from(this.clients.values())}async disconnectServer(e){let t=this.clients.get(e);t&&(await t.close(),this.clients.delete(e))}async disconnectAll(){let e=Array.from(this.clients.values()).map(e=>e.close());await Promise.all(e),this.clients.clear(),this.connectionPromises.clear()}isConnected(e){return this.clients.has(e)}};const M=`install`,Qe=/^(@[a-zA-Z0-9_-]+\/)?[a-zA-Z0-9._-]+(@[a-zA-Z0-9._-]+)?$/,N=`pipe`;function $e(e){return typeof e==`object`&&!!e&&`command`in e}var et=class{config;constructor(e){this.config=e}extractPackages(){let e=[],{mcpConfig:t,filter:n}=this.config;for(let[r,i]of Object.entries(t.mcpServers)){if(i.disabled||i.transport!==`stdio`||!$e(i.config))continue;let t=this.extractPackageInfo(r,i.config);if(t){if(n&&t.packageManager!==n)continue;e.push(t)}}return e}async prefetch(){try{let e=this.extractPackages(),t=[];if(e.length===0)return{totalPackages:0,successful:0,failed:0,results:[]};if(this.config.parallel){let n=e.map(async e=>this.prefetchPackage(e));t.push(...await Promise.all(n))}else for(let n of e){let e=await this.prefetchPackage(n);t.push(e)}let n=t.filter(e=>e.success).length,r=t.filter(e=>!e.success).length;return{totalPackages:e.length,successful:n,failed:r,results:t}}catch(e){throw Error(`Failed to prefetch packages: ${e instanceof Error?e.message:String(e)}`)}}async prefetchPackage(e){try{let[t,...n]=e.fullCommand,r=await this.runCommand(t,n);return{package:e,success:r.success,output:r.output}}catch(t){return{package:e,success:!1,output:t instanceof Error?t.message:String(t)}}}isValidPackageName(e){return Qe.test(e)}extractPackageInfo(e,t){let n=t.command.toLowerCase(),r=t.args||[];if(n===`npx`||n.endsWith(`/npx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`npx`,packageName:t,fullCommand:[`npm`,M,`-g`,t]}}if(n===`pnpx`||n.endsWith(`/pnpx`)){let t=this.extractNpxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`pnpx`,packageName:t,fullCommand:[`pnpm`,`add`,`-g`,t]}}if(n===`uvx`||n.endsWith(`/uvx`)){let t=this.extractUvxPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uvx`,packageName:t,fullCommand:[`uvx`,t]}}if((n===`uv`||n.endsWith(`/uv`))&&r.includes(`run`)){let t=this.extractUvRunPackage(r);if(t&&this.isValidPackageName(t))return{serverName:e,packageManager:`uv`,packageName:t,fullCommand:[`uv`,`tool`,M,t]}}return null}extractNpxPackage(e){for(let t=0;t<e.length;t++){let n=e[t];if(n.startsWith(`--package=`))return n.slice(10)||null;if(n===`--package`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}if(n===`-p`&&t+1<e.length){let n=e[t+1];if(!n.startsWith(`-`))return n}}for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvxPackage(e){for(let t of e)if(!t.startsWith(`-`))return t;return null}extractUvRunPackage(e){let t=e.indexOf(`run`);if(t===-1)return null;for(let n=t+1;n<e.length;n++){let t=e[n];if(!t.startsWith(`-`))return t}return null}runCommand(e,t){return new Promise(n=>{let r=(0,ae.spawn)(e,t,{stdio:[`ignore`,N,N],shell:process.platform===`win32`}),i=``,a=``;r.stdout?.on(`data`,e=>{i+=e.toString()}),r.stderr?.on(`data`,e=>{a+=e.toString()}),r.on(`close`,e=>{n({success:e===0,output:i||a})}),r.on(`error`,e=>{n({success:!1,output:e.message})})})}};const P=`.runtime.json`;function F(e){return typeof e==`object`&&!!e}function I(e){return F(e)?typeof e.serverId==`string`&&typeof e.host==`string`&&typeof e.port==`number`&&e.transport===`http`&&typeof e.shutdownToken==`string`&&typeof e.startedAt==`string`&&typeof e.pid==`number`&&(e.configPath===void 0||typeof e.configPath==`string`):!1}function tt(e){return e instanceof Error?e.message:String(e)}var L=class e{runtimeDir;logger;constructor(t,n=console){this.runtimeDir=t??e.getDefaultRuntimeDir(),this.logger=n}static getDefaultRuntimeDir(){return(0,m.join)((0,p.homedir)(),`.aicode-toolkit`,`mcp-proxy`,`runtimes`)}getRecordPath(e){return(0,m.join)(this.runtimeDir,`${e}${P}`)}async write(e){await(0,l.mkdir)(this.runtimeDir,{recursive:!0}),await(0,l.writeFile)(this.getRecordPath(e.serverId),JSON.stringify(e,null,2),`utf-8`)}async read(e){let t=this.getRecordPath(e);try{let e=await(0,l.readFile)(t,`utf-8`),n=JSON.parse(e);return I(n)?n:null}catch(n){if(F(n)&&`code`in n&&n.code===`ENOENT`)return null;throw Error(`Failed to read runtime state for server '${e}' from '${t}': ${tt(n)}`)}}async list(){try{let e=(await(0,l.readdir)(this.runtimeDir,{withFileTypes:!0})).filter(e=>e.isFile()&&e.name.endsWith(P));return(await Promise.all(e.map(async e=>{try{let t=await(0,l.readFile)((0,m.join)(this.runtimeDir,e.name),`utf-8`),n=JSON.parse(t);return I(n)?n:null}catch(t){return this.logger.debug(`Skipping unreadable runtime state file ${e.name}`,t),null}}))).filter(e=>e!==null)}catch(e){if(F(e)&&`code`in e&&e.code===`ENOENT`)return[];throw Error(`Failed to list runtime states from '${this.runtimeDir}': ${tt(e)}`)}}async remove(e){await(0,l.rm)(this.getRecordPath(e),{force:!0})}},R=class extends Error{constructor(e,t,n){super(e),this.filePath=t,this.cause=n,this.name=`SkillLoadError`}};async function z(e){try{return await(0,l.access)(e),!0}catch(t){if(t instanceof Error&&`code`in t&&t.code===`ENOENT`)return!1;throw Error(`Failed to check path existence for "${e}": ${t instanceof Error?t.message:`Unknown error`}`)}}var nt=class{cwd;skillPaths;cachedSkills=null;skillsByName=null;watchers=[];pollingTimers=[];onCacheInvalidated;logger;constructor(e,t,n,r=console){this.cwd=e,this.skillPaths=t,this.onCacheInvalidated=n?.onCacheInvalidated,this.logger=r}async getSkills(){if(this.cachedSkills!==null)return this.cachedSkills;let e=[],t=new Set,n=await Promise.all(this.skillPaths.map(async e=>{let t=(0,m.isAbsolute)(e)?e:(0,m.join)(this.cwd,e);return this.loadSkillsFromDirectory(t,`project`)}));for(let r of n)for(let n of r)t.has(n.name)||(e.push(n),t.add(n.name));return this.cachedSkills=e,this.skillsByName=new Map(e.map(e=>[e.name,e])),e}async getSkill(e){return this.skillsByName===null&&await this.getSkills(),this.skillsByName?.get(e)}clearCache(){this.cachedSkills=null,this.skillsByName=null}async startWatching(){this.stopWatching();let e=await Promise.all(this.skillPaths.map(async e=>{let t=(0,m.isAbsolute)(e)?e:(0,m.join)(this.cwd,e);return{skillsDir:t,exists:await z(t)}}));for(let{skillsDir:t,exists:n}of e){if(!n)continue;let e=new AbortController;this.watchers.push(e),this.watchDirectory(t,e.signal).catch(n=>{if(n?.name!==`AbortError`){if(this.isWatchResourceLimitError(n)){this.startPollingDirectory(t,e.signal);return}this.logger.warn(`[skill-watcher] Error watching ${t}: ${n instanceof Error?n.message:`Unknown error`}`)}})}}stopWatching(){for(let e of this.watchers)e.abort();this.watchers=[];for(let e of this.pollingTimers)clearInterval(e);this.pollingTimers=[]}async watchDirectory(e,t){let n=(0,l.watch)(e,{recursive:!0,signal:t});for await(let e of n)e.filename?.endsWith(`SKILL.md`)&&this.invalidateCache()}invalidateCache(){this.clearCache(),this.onCacheInvalidated?.()}isWatchResourceLimitError(e){return e instanceof Error&&`code`in e&&(e.code===`EMFILE`||e.code===`ENOSPC`)}startPollingDirectory(e,t){this.createSkillSnapshot(e).then(n=>{let r=n,i=setInterval(()=>{if(t.aborted){clearInterval(i);return}this.createSkillSnapshot(e).then(e=>{this.snapshotsEqual(r,e)||(r=e,this.invalidateCache())}).catch(t=>{this.logger.warn(`[skill-watcher] Polling failed for ${e}: ${t instanceof Error?t.message:`Unknown error`}`)})},3e3);this.pollingTimers.push(i),t.addEventListener(`abort`,()=>{clearInterval(i),this.pollingTimers=this.pollingTimers.filter(e=>e!==i)},{once:!0})})}async createSkillSnapshot(e){let t=new Map;return await this.collectSkillSnapshots(e,t),t}async collectSkillSnapshots(e,t){let n;try{n=await(0,l.readdir)(e)}catch(e){if(e instanceof Error&&`code`in e&&e.code===`ENOENT`)return;throw e}await Promise.all(n.map(async n=>{let r=(0,m.join)(e,n),i=await(0,l.stat)(r);if(i.isDirectory()){await this.collectSkillSnapshots(r,t);return}n===`SKILL.md`&&t.set(r,i.mtimeMs)}))}snapshotsEqual(e,t){if(e.size!==t.size)return!1;for(let[n,r]of e)if(t.get(n)!==r)return!1;return!0}async loadSkillsFromDirectory(e,t){let n=[];try{if(!await z(e))return n}catch(t){throw new R(`Cannot access skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let r;try{r=await(0,l.readdir)(e)}catch(t){throw new R(`Failed to read skills directory: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let i=await Promise.all(r.map(async t=>{let n=(0,m.join)(e,t);try{return{entry:t,entryPath:n,stat:await(0,l.stat)(n),error:null}}catch(e){return this.logger.warn(`Skipping entry ${n}: ${e instanceof Error?e.message:`Unknown error`}`),{entry:t,entryPath:n,stat:null,error:e}}})),a=[];for(let{entry:e,entryPath:t,stat:n}of i)if(n)if(n.isDirectory()){let e=(0,m.join)(t,`SKILL.md`);a.push({filePath:e,isRootLevel:!1})}else e===`SKILL.md`&&a.push({filePath:t,isRootLevel:!0});let o=await Promise.all(a.map(async({filePath:e,isRootLevel:n})=>{try{return!n&&!await z(e)?null:await this.loadSkillFile(e,t)}catch(t){return this.logger.warn(`Skipping skill at ${e}: ${t instanceof Error?t.message:`Unknown error`}`),null}}));for(let e of o)e&&n.push(e);return n}async loadSkillFile(e,t){let n;try{n=await(0,l.readFile)(e,`utf-8`)}catch(t){throw new R(`Failed to read skill file: ${t instanceof Error?t.message:`Unknown error`}`,e,t instanceof Error?t:void 0)}let{frontMatter:r,content:i}=Ue(n);return!r||!r.name||!r.description?null:{name:r.name,description:r.description,location:t,content:i,basePath:(0,m.dirname)(e)}}};const rt=new Set([`localhost`,`127.0.0.1`,`::1`]);function it(e){return e}function at(e){if(typeof e!=`object`||!e)return!1;let t=it(e);return`status`in t&&t.status===`ok`&&`transport`in t&&t.transport===`http`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)}function ot(e){if(typeof e!=`object`||!e)return!1;let t=it(e);return`ok`in t&&typeof t.ok==`boolean`&&`message`in t&&typeof t.message==`string`&&(!(`serverId`in t)||t.serverId===void 0||typeof t.serverId==`string`)}function st(e,t){if(!rt.has(e.host))throw Error(`Refusing to connect to non-loopback host '${e.host}'. Only ${Array.from(rt).join(`, `)} are allowed.`);return`http://${e.host}:${e.port}${t}`}function ct(e){return e instanceof Error?e.message:String(e)}function lt(e){return new Promise(t=>{setTimeout(t,e)})}var ut=class{runtimeStateService;logger;constructor(e=new L,t=console){this.runtimeStateService=e,this.logger=t}async stop(e){let t=e.timeoutMs??5e3,n=await this.resolveRuntime(e),r=await this.fetchHealth(n,t);if(!r.reachable)throw await this.runtimeStateService.remove(n.serverId),Error(`Runtime '${n.serverId}' is not reachable at http://${n.host}:${n.port}. Removed stale runtime record.`);if(!e.force&&r.payload?.serverId&&r.payload.serverId!==n.serverId)throw Error(`Refusing to stop runtime at http://${n.host}:${n.port}: expected server ID '${n.serverId}' but health endpoint reported '${r.payload.serverId}'. Use --force to override.`);let i=e.token??n.shutdownToken;if(!i)throw Error(`No shutdown token available for runtime '${n.serverId}'.`);let a=await this.requestShutdown(n,i,t);return await this.waitForShutdown(n,t),await this.runtimeStateService.remove(n.serverId),{ok:!0,serverId:n.serverId,host:n.host,port:n.port,message:a.message}}async resolveRuntime(e){if(e.serverId){let t=await this.runtimeStateService.read(e.serverId);if(!t)throw Error(`No runtime record found for server ID '${e.serverId}'. Start the server with 'mcp-proxy mcp-serve --type http' first.`);return t}if(e.host===void 0||e.port===void 0)throw Error(`Provide --id or both --host and --port to select a runtime.`);let t=(await this.runtimeStateService.list()).filter(t=>t.host===e.host&&t.port===e.port);if(t.length===0)throw Error(`No runtime record found for http://${e.host}:${e.port}. Start the server with 'mcp-proxy mcp-serve --type http' first.`);if(t.length>1)throw Error(`Multiple runtime records match http://${e.host}:${e.port}. Retry with --id to avoid stopping the wrong server.`);return t[0]}async fetchHealth(e,t){try{let n=await this.fetchWithTimeout(st(e,`/health`),{method:`GET`},t);if(!n.ok)return{reachable:!1};let r=await n.json();if(!at(r))throw Error(`Received invalid health response payload.`);return{reachable:!0,payload:r}}catch(t){return this.logger.debug(`Health check failed for ${e.serverId}`,t),{reachable:!1}}}async requestShutdown(e,t,n){let r=await this.fetchWithTimeout(st(e,`/admin/shutdown`),{method:`POST`,headers:{Authorization:`Bearer ${t}`}},n),i=await r.json();if(!ot(i))throw Error(`Received invalid shutdown response payload.`);if(!r.ok||!i.ok)throw Error(i.message);return i}async waitForShutdown(e,t){let n=Date.now()+t;for(;Date.now()<n;){if(!(await this.fetchHealth(e,Math.max(250,n-Date.now()))).reachable)return;await lt(200)}throw Error(`Timed out waiting for runtime '${e.serverId}' to stop at http://${e.host}:${e.port}.`)}async fetchWithTimeout(e,t,n){let r=new AbortController,i=setTimeout(()=>{r.abort()},n);try{return await fetch(e,{...t,signal:r.signal})}catch(t){throw Error(`Request to '${e}' failed: ${ct(t)}`)}finally{clearTimeout(i)}}},dt=`<toolkit id="{{ serverId }}">
6
+ <instruction>
7
+ Before you use any capabilities below, you MUST call this tool with a list of names to learn how to use them properly; this includes:
8
+ - For tools: Arguments schema needed to pass to use_tool
9
+ - For skills: Detailed instructions that will expand when invoked (Prefer to be explored first when relevant)
10
+
11
+ This tool is optimized for batch queries - you can request multiple capabilities at once for better performance.
12
+
13
+ How to invoke:
14
+ - For MCP tools: Use use_tool with toolName and toolArgs based on the schema
15
+ - For skills: Use this tool with the skill name to get expanded instructions
16
+ </instruction>
17
+
18
+ <available_capabilities>
19
+ {% for server in servers -%}
20
+ <group original-mcp-server="{{ server.name }}">
21
+ {% if server.instruction -%}
22
+ <group_instruction>{{ server.instruction }}</group_instruction>
23
+ {% endif -%}
24
+ {% if server.omitToolDescription -%}
25
+ {% for toolName in server.toolNames -%}
26
+ <item name="{{ toolName }}"></item>
27
+ {% endfor -%}
28
+ {% else -%}
29
+ {% for tool in server.tools -%}
30
+ <item name="{{ tool.displayName }}"><description>{{ tool.description | default: "No description" }}</description></item>
31
+ {% endfor -%}
32
+ {% endif -%}
33
+ </group>
34
+ {% endfor -%}
35
+ {% if skills.size > 0 -%}
36
+ <group name="skills">
37
+ {% for skill in skills -%}
38
+ <item name="{{ skill.displayName }}"><description>{{ skill.description }}</description></item>
39
+ {% endfor -%}
40
+ </group>
41
+ {% endif -%}
42
+ </available_capabilities>
43
+ </toolkit>
44
+ `;function B(e,t){return`<command-message>The "${e}" skill is loading</command-message>\n${t}`}const V=d.z.object({toolNames:d.z.array(d.z.string().min(1)).min(1).describe(`List of tool names to get detailed information about`)});var H=class e{static TOOL_NAME=`describe_tools`;clientManager;skillService;definitionsCacheService;liquid=new oe.Liquid;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.serverId=n||`unknown`,this.definitionsCacheService=r||new E(e,t)}clearAutoDetectedSkillsCache(){this.definitionsCacheService.clearLiveCache()}async collectPromptSkills(){let e=[],t=await this.definitionsCacheService.getServerDefinitions();for(let n of t)for(let t of n.promptSkills)e.push({name:t.skill.name,displayName:t.skill.name,description:t.skill.description});return e}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}async getPromptSkillContent(e){let t=await this.findPromptSkill(e);if(t)try{let e=(await(await this.clientManager.ensureConnected(t.serverName)).getPrompt(t.promptName)).messages?.map(e=>{let t=e.content;return typeof t==`string`?t:t&&typeof t==`object`&&`text`in t?String(t.text):``}).join(`
45
+ `)||``;return{name:t.skill.name,location:t.skill.folder||`prompt:${t.serverName}/${t.promptName}`,instructions:B(t.skill.name,e)}}catch(t){console.error(`Failed to get prompt-based skill '${e}': ${t instanceof Error?t.message:`Unknown error`}`);return}}async buildToolkitDescription(){let e=await this.definitionsCacheService.getServerDefinitions(),t=new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=(e,n)=>(t.get(e)||[]).length>1?`${n}__${e}`:e,r=new Set,i=e.map(e=>{let t=e.tools.map(t=>({displayName:n(t.name,e.serverName),description:t.description}));for(let e of t)r.add(e.displayName);return{name:e.serverName,instruction:e.serverInstruction,omitToolDescription:e.omitToolDescription||!1,tools:t,toolNames:t.map(e=>e.displayName)}}),[a,o,s]=await Promise.all([this.skillService?this.skillService.getSkills():Promise.resolve([]),this.definitionsCacheService.getCachedFileSkills(),this.collectPromptSkills()]),c=new Set,l=[];for(let e of a)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of o)c.has(e.name)||(c.add(e.name),l.push({name:e.name,displayName:e.name,description:e.description}));for(let e of s)c.has(e.name)||(c.add(e.name),l.push(e));let u=l.map(e=>{let t=r.has(e.name);return{name:e.name,displayName:t?`skill__${e.name}`:e.name,description:e.description}});return{content:await this.liquid.parseAndRender(dt,{servers:i,skills:u,serverId:this.serverId}),toolNames:r}}getInputSchema(){return V}async getDefinition(){let{content:t}=await this.buildToolkitDescription();return{name:e.TOOL_NAME,description:t,inputSchema:d.z.toJSONSchema(V,{reused:`inline`})}}async runLookups(e,t){let n=new Map,r=new Map;for(let e of t){let t=e.tools.map(e=>({name:e.name,description:e.description,inputSchema:e.inputSchema}));n.set(e.serverName,t);for(let n of t)r.has(n.name)||r.set(n.name,[]),r.get(n.name)?.push(e.serverName)}let i=await Promise.all(e.map(async e=>{let t={tools:[],skills:[],notFound:null};if(e.startsWith(`skill__`)){let n=e.slice(7);if(this.skillService){let e=await this.skillService.getSkill(n);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:B(e.name,e.content)}),t}let r=await this.getPromptSkillContent(n);return r?(t.skills.push(r),t):(t.notFound=e,t)}let{serverName:i,actualToolName:a}=C(e);if(i){let r=n.get(i);if(!r){try{let n=(await(await this.clientManager.ensureConnected(i)).listTools()).find(e=>e.name===a);n?t.tools.push({server:i,tool:{name:n.name,description:n.description,inputSchema:n.inputSchema}}):t.notFound=e}catch{t.notFound=e}return t}let o=r.find(e=>e.name===a);return o?t.tools.push({server:i,tool:{name:o.name,description:o.description,inputSchema:o.inputSchema}}):t.notFound=e,t}let o=r.get(a);if(!o||o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return t.skills.push({name:e.name,location:e.basePath,instructions:B(e.name,e.content)}),t}let n=await this.getPromptSkillContent(a);return n?(t.skills.push(n),t):(t.notFound=e,t)}for(let e of o){let r=n.get(e).find(e=>e.name===a);t.tools.push({server:e,tool:{name:r.name,description:r.description,inputSchema:r.inputSchema}})}return t})),a=[],o=[],s=[];for(let e of i)a.push(...e.tools),o.push(...e.skills),e.notFound&&s.push(e.notFound);return{foundTools:a,foundSkills:o,notFoundItems:s}}async execute(e){try{let{toolNames:t}=V.parse(e);if(!t||t.length===0)return{content:[{type:`text`,text:`No tool names provided. Please specify at least one tool name.`}],isError:!0};let n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions());n.notFoundItems.length>0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),n=await this.runLookups(t,await this.definitionsCacheService.getServerDefinitions()));let{foundTools:r,foundSkills:i,notFoundItems:a}=n;if(r.length===0&&i.length===0)return{content:[{type:`text`,text:`None of the requested tools/skills found.\nRequested: ${t.join(`, `)}\nUse describe_tools to see available tools and skills.`}],isError:!0};let o={},s=[];return r.length>0&&(o.tools=r,s.push(`For MCP tools: Use the use_tool function with toolName and toolArgs based on the inputSchema above.`)),i.length>0&&(o.skills=i,s.push(`For skill, just follow skill's description to continue.`)),s.length>0&&(o.nextSteps=s),a.length>0&&(o.notFound=a,o.warnings=[`Items not found: ${a.join(`, `)}`]),{content:[{type:`text`,text:JSON.stringify(o,null,2)}]}}catch(e){return{content:[{type:`text`,text:`Error describing tools: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}};function U(e){let t=e._meta?.[`agiflowai/capabilities`];return Array.isArray(t)?t.filter(e=>typeof e==`string`):[]}function W(e){return Array.from(new Set(e.flatMap(e=>U(e)))).sort()}const G=d.z.object({capability:d.z.string().optional().describe(`Optional capability filter. Matches explicit capability tags first, then server summaries, server names, tool names, and tool descriptions.`),serverName:d.z.string().optional().describe(`Optional server name filter.`)});var K=class e{static TOOL_NAME=`list_tools`;constructor(e,t){this._clientManager=e,this.definitionsCacheService=t}formatToolName(e,t,n){return(n.get(e)||[]).length>1?`${t}__${e}`:e}getInputSchema(){return G}async getDefinition(){let t=await this.definitionsCacheService.getServerDefinitions(),n=t.length>0?t.map(e=>{let t=W(e.tools),n=t.length>0?t.join(`, `):e.serverInstruction||`No capability summary available`;return`${e.serverName}: ${n}`}).join(`
46
+ `):`No proxied servers available.`;return{name:e.TOOL_NAME,description:`Search proxied MCP tools by server capability summary.\n\nAvailable capabilities:\n${n}`,inputSchema:d.z.toJSONSchema(G,{reused:`inline`})}}async execute(e){let t=G.parse(e),n=await this.definitionsCacheService.getServerDefinitions(),r=t.capability?.trim().toLowerCase(),i=t.serverName?.trim().toLowerCase(),a=new Map;for(let e of n)for(let t of e.tools)a.has(t.name)||a.set(t.name,[]),a.get(t.name)?.push(e.serverName);let o=n.filter(e=>i&&e.serverName.toLowerCase()!==i?!1:!r||(e.serverInstruction?.toLowerCase()||``).includes(r)||W(e.tools).some(e=>e.toLowerCase().includes(r))?!0:e.tools.some(t=>{let n=this.formatToolName(t.name,e.serverName,a),i=U(t);return n.toLowerCase().includes(r)||(t.description||``).toLowerCase().includes(r)||i.some(e=>e.toLowerCase().includes(r))})).map(e=>({server:e.serverName,capabilities:W(e.tools),summary:e.serverInstruction,tools:e.tools.map(t=>({name:this.formatToolName(t.name,e.serverName,a),description:e.omitToolDescription?void 0:t.description,capabilities:U(t)}))})).filter(e=>e.tools.length>0);return{content:[{type:`text`,text:JSON.stringify({servers:o},null,2)}],isError:o.length===0?!0:void 0}}};const q=d.z.object({toolName:d.z.string().min(1).describe(`Name of the tool to execute`),toolArgs:d.z.record(d.z.string(),d.z.unknown()).optional().describe(`Arguments to pass to the tool, as discovered from describe_tools`)});var J=class e{static TOOL_NAME=`use_tool`;clientManager;skillService;definitionsCacheService;serverId;constructor(e,t,n,r){this.clientManager=e,this.skillService=t,this.definitionsCacheService=r||new E(e,t),this.serverId=n||`unknown`}getInputSchema(){return q}getDefinition(){return{name:e.TOOL_NAME,description:`Execute an MCP tool (NOT Skill) with provided arguments. You MUST call describe_tools first to discover the tool's correct arguments. Then to use tool:
47
+ - Provide toolName and toolArgs based on the schema
48
+ - If multiple servers provide the same tool, specify serverName
49
+
50
+ IMPORTANT: Only use tools discovered from describe_tools with id="${this.serverId}".
51
+ `,inputSchema:d.z.toJSONSchema(q,{reused:`inline`})}}async coerceToolArgs(e,t,n){let r=await this.definitionsCacheService.getToolSchema(e,t);return r?(0,g.coerceArgs)(n,(0,g.jsonSchemaToZod)(r)):n}executeSkill(e){return{content:[{type:`text`,text:`Skill "${e.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${e.basePath}\n\nThen follow the skill's instructions directly.`}]}}async findPromptSkill(e){if(e)return await this.definitionsCacheService.getPromptSkillByName(e)}executePromptSkill(e){let t=e.skill.folder||`prompt:${e.serverName}/${e.promptName}`;return{content:[{type:`text`,text:`Skill "${e.skill.name}" found. Skills provide instructions and should not be executed via use_tool.\n\nUse describe_tools to view the skill details at: ${t}\n\nThen follow the skill's instructions directly.`}]}}async execute(e){try{let{toolName:t,toolArgs:n={}}=q.parse(e);if(t.startsWith(`skill__`)){let e=t.slice(7);if(this.skillService){let t=await this.skillService.getSkill(e);if(t)return this.executeSkill(t)}let n=await this.findPromptSkill(e);return n?this.executePromptSkill(n):{content:[{type:`text`,text:`Skill "${e}" not found. Use describe_tools to see available skills.`}],isError:!0}}let r=this.clientManager.getKnownServerNames(),{serverName:i,actualToolName:a}=C(t);if(i)try{let e=await this.clientManager.ensureConnected(i);if(e.toolBlacklist?.includes(a))return{content:[{type:`text`,text:`Tool "${a}" is blacklisted on server "${i}" and cannot be executed.`}],isError:!0};let t=this.clientManager.getServerRequestTimeout(i),r=await this.coerceToolArgs(i,a,n);return await e.callTool(a,r,t?{timeout:t}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}" on server "${i}". Available servers: ${r.join(`, `)}. ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}let o=await this.definitionsCacheService.getServersForTool(a);if(o.length===0&&(this.definitionsCacheService.clearLiveCache(),await this.definitionsCacheService.collectForCache(),o=await this.definitionsCacheService.getServersForTool(a)),o.length===0){if(this.skillService){let e=await this.skillService.getSkill(a);if(e)return this.executeSkill(e)}let e=await this.findPromptSkill(a);return e?this.executePromptSkill(e):{content:[{type:`text`,text:`Tool or skill "${a}" not found. Use describe_tools to see available tools and skills.`}],isError:!0}}if(o.length>1)return{content:[{type:`text`,text:`Tool "${a}" found on multiple servers. Use prefixed format to specify: ${o.map(e=>`${e}__${a}`).join(`, `)}`}],isError:!0};try{let e=o[0],t=await this.clientManager.ensureConnected(e),r=this.clientManager.getServerRequestTimeout(e),i=await this.coerceToolArgs(e,a,n);return await t.callTool(a,i,r?{timeout:r}:void 0)}catch(e){return{content:[{type:`text`,text:`Failed to call tool "${a}": ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}catch(e){return{content:[{type:`text`,text:`Error executing tool: ${e instanceof Error?e.message:`Unknown error`}`}],isError:!0}}}},ft=class{sessions=new Map;closingSessions=new Set;cleanupTimer=null;logger;constructor(e=console){this.logger=e}getSession(e){let t=this.sessions.get(e);return t&&(t.lastActivity=Date.now()),t}setSession(e,t,n){this.sessions.set(e,{transport:t,server:n,lastActivity:Date.now()})}removeSession(e){this.sessions.delete(e)}isClosing(e){return this.closingSessions.has(e)}async closeSession(e){let t=this.sessions.get(e);if(t){this.closingSessions.add(e);try{await t.server.close()}catch(t){throw Error(`Failed to close MCP server for session '${e}': ${Y(t)}`)}finally{this.sessions.delete(e),this.closingSessions.delete(e)}}}hasSession(e){return this.sessions.has(e)}startCleanup(){this.cleanupTimer||=setInterval(()=>{this.cleanupStaleSessions()},3e5)}stopCleanup(){this.cleanupTimer&&=(clearInterval(this.cleanupTimer),null)}async cleanupStaleSessions(){let e=Date.now(),t=[];for(let[n,r]of this.sessions)e-r.lastActivity>18e5&&!this.closingSessions.has(n)&&t.push(n);for(let e of t)try{this.logger.info(`Closing inactive session '${e}'`),await this.closeSession(e)}catch(t){this.logger.warn(`Failed to close stale session '${e}': ${Y(t)}`)}}async clear(){this.stopCleanup();try{await Promise.all(Array.from(this.sessions.keys()).map(async e=>this.closeSession(e)))}catch(e){throw Error(`Failed to clear sessions: ${Y(e)}`)}}};function Y(e){return e instanceof Error?e.message:String(e)}var pt=class{requests=new Map;isAllowed(e){let t=Date.now(),n=t-6e4,r=(this.requests.get(e)??[]).filter(e=>e>n);return r.length===0?(this.requests.delete(e),!0):r.length>=5?(this.requests.set(e,r),!1):(r.push(t),this.requests.set(e,r),!0)}};async function mt(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>{try{let e=Buffer.concat(r).toString(`utf-8`);t(e?JSON.parse(e):void 0)}catch(e){n(Error(`Failed to parse JSON body: ${Y(e)}`))}}),e.on(`error`,n)})}function ht(e,t,n){let r=JSON.stringify(n);e.writeHead(t,{"Content-Type":`application/json`}),e.end(r)}var gt=class{serverFactory;honoApp;server=null;sessionManager;config;adminOptions;adminRateLimiter=new pt;logger;constructor(e,t,n,r=console){this.serverFactory=e,this.honoApp=new fe.Hono,this.sessionManager=new ft(r),this.config={mode:t.mode,port:t.port,host:t.host??`localhost`},this.adminOptions=n,this.logger=r,this.setupHonoRoutes()}setupHonoRoutes(){this.honoApp.get(`/health`,e=>{let t={status:`ok`,transport:`http`,serverId:this.adminOptions?.serverId};return e.json(t)}),this.honoApp.post(`/admin/shutdown`,async e=>{try{let t=e.req.header(`x-forwarded-for`)??`unknown`;if(!this.adminRateLimiter.isAllowed(t)){let t={ok:!1,message:`Too many shutdown requests. Try again later.`,serverId:this.adminOptions?.serverId};return e.json(t,429)}return await this.handleAdminShutdownRequest(e)}catch(t){this.logger.error(`Failed to process shutdown request: ${Y(t)}`);let n={ok:!1,message:`Failed to process shutdown request.`,serverId:this.adminOptions?.serverId};return e.json(n,500)}})}isAuthorizedShutdownRequest(e){let t=this.adminOptions?.shutdownToken;if(!t)return!1;let n=e.authorization;if(typeof n==`string`&&n.startsWith(`Bearer `))return n.slice(7)===t;let r=e[`x-mcp-proxy-shutdown-token`];return typeof r==`string`&&r===t}async handleAdminShutdownRequest(e){if(!this.adminOptions?.onShutdownRequested){let t={ok:!1,message:`Shutdown endpoint is not enabled for this server instance.`,serverId:this.adminOptions?.serverId};return e.json(t,404)}let t={authorization:e.req.header(`authorization`),"x-mcp-proxy-shutdown-token":e.req.header(`x-mcp-proxy-shutdown-token`)};if(!this.isAuthorizedShutdownRequest(t)){let t={ok:!1,message:`Unauthorized shutdown request: invalid or missing shutdown token.`,serverId:this.adminOptions?.serverId};return e.json(t,401)}let n={ok:!0,message:`Shutdown request accepted. Stopping server gracefully.`,serverId:this.adminOptions?.serverId},r=e.json(n);return this.adminOptions.onShutdownRequested(),r}async handleMcpRequest(e,t){let n=e.method?.toUpperCase();try{n===`POST`?await this.handlePostRequest(e,t):n===`GET`?await this.handleGetRequest(e,t):n===`DELETE`?await this.handleDeleteRequest(e,t):(t.writeHead(405),t.end(`Method Not Allowed`))}catch(e){this.logger.error(`Failed to handle MCP ${n} request: ${Y(e)}`),t.headersSent||ht(t,500,{jsonrpc:`2.0`,error:{code:-32603,message:`Failed to handle MCP ${n} request.`},id:null})}}async handlePostRequest(e,t){let n=e.headers[`mcp-session-id`],r=await mt(e),i;if(n&&this.sessionManager.hasSession(n))i=this.sessionManager.getSession(n).transport;else if(!n&&(0,_.isInitializeRequest)(r)){let e=await this.serverFactory();i=new de.StreamableHTTPServerTransport({sessionIdGenerator:()=>(0,f.randomUUID)(),enableJsonResponse:!0,onsessioninitialized:t=>{this.sessionManager.setSession(t,i,e)}}),i.onclose=async()=>{if(i.sessionId)try{this.sessionManager.isClosing(i.sessionId)||this.sessionManager.removeSession(i.sessionId)}catch(e){this.logger.warn(`Failed to clean up session '${i.sessionId}': ${Y(e)}`)}};try{await e.connect(i)}catch(e){throw Error(`Failed to connect MCP server transport for initialization request: ${Y(e)}`)}}else{ht(t,400,{jsonrpc:`2.0`,error:{code:-32e3,message:n===void 0?`Bad Request: missing session ID and request body is not an initialize request.`:`Bad Request: unknown session ID '${n}'.`},id:null});return}try{await i.handleRequest(e,t,r)}catch(e){throw Error(`Failed handling MCP transport request: ${Y(e)}`)}}async handleGetRequest(e,t){let n=e.headers[`mcp-session-id`];if(!n||!this.sessionManager.hasSession(n)){t.writeHead(400),t.end(`Invalid or missing session ID`);return}let r=this.sessionManager.getSession(n);try{await r.transport.handleRequest(e,t)}catch(e){throw Error(`Failed handling MCP GET request for session '${n}': ${Y(e)}`)}}async handleDeleteRequest(e,t){let n=e.headers[`mcp-session-id`];if(!n||!this.sessionManager.hasSession(n)){t.writeHead(400),t.end(`Invalid or missing session ID`);return}let r=this.sessionManager.getSession(n);try{await r.transport.handleRequest(e,t)}catch(e){throw Error(`Failed handling MCP DELETE request for session '${n}': ${Y(e)}`)}this.sessionManager.removeSession(n)}async start(){try{let e=(0,ue.getRequestListener)(this.honoApp.fetch),t=(0,ce.createServer)(async(t,n)=>{new URL(t.url??`/`,`http://${t.headers.host??this.config.host}`).pathname===`/mcp`?await this.handleMcpRequest(t,n):e(t,n)});t.listen(this.config.port,this.config.host),this.server=t;let n=(async()=>{await(0,se.once)(t,`listening`)})(),r=(async()=>{let[e]=await(0,se.once)(t,`error`);throw e instanceof Error?e:Error(String(e))})();await Promise.race([n,r]),this.sessionManager.startCleanup(),this.logger.info(`@agimon-ai/mcp-proxy MCP server started on http://${this.config.host}:${this.config.port}/mcp`),this.logger.info(`Health check: http://${this.config.host}:${this.config.port}/health`)}catch(e){throw this.server=null,Error(`Failed to start HTTP transport: ${Y(e)}`)}}async stop(){if(!this.server)return;try{await this.sessionManager.clear()}catch(e){throw Error(`Failed to clear sessions during HTTP transport stop: ${Y(e)}`)}let e=(0,le.promisify)(this.server.close.bind(this.server));try{await e(),this.server=null}catch(e){throw Error(`Failed to stop HTTP transport: ${Y(e)}`)}}getPort(){return this.config.port}getHost(){return this.config.host}},_t=class{sessions=new Map;closingSessions=new Set;getSession(e){return this.sessions.get(e)?.transport}setSession(e,t,n){this.sessions.set(e,{transport:t,server:n})}removeSession(e){this.sessions.delete(e)}isClosing(e){return this.closingSessions.has(e)}async closeSession(e){let t=this.sessions.get(e);if(t){this.closingSessions.add(e);try{await t.server.close()}finally{this.sessions.delete(e),this.closingSessions.delete(e)}}}async clear(){await Promise.all(Array.from(this.sessions.keys()).map(async e=>this.closeSession(e)))}hasSession(e){return this.sessions.has(e)}};async function vt(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>{try{let e=Buffer.concat(r).toString(`utf-8`);t(e?JSON.parse(e):void 0)}catch(e){n(Error(`Failed to parse JSON body: ${e instanceof Error?e.message:String(e)}`))}}),e.on(`error`,n)})}var yt=class{serverFactory;honoApp;server=null;sessionManager;config;logger;constructor(e,t,n=console){this.serverFactory=typeof e==`function`?e:()=>e,this.honoApp=new fe.Hono,this.sessionManager=new _t,this.config={mode:t.mode,port:t.port,host:t.host??`localhost`},this.logger=n,this.setupHonoRoutes()}setupHonoRoutes(){this.honoApp.get(`/health`,e=>e.json({status:`ok`,transport:`sse`}))}async handleSseConnection(e){try{let t=this.serverFactory(),n=new pe.SSEServerTransport(`/messages`,e);this.sessionManager.setSession(n.sessionId,n,t),e.on(`close`,()=>{let e=n.sessionId;e&&!this.sessionManager.isClosing(e)&&this.sessionManager.removeSession(e)}),await t.connect(n),this.logger.info(`SSE session established: ${n.sessionId}`)}catch(t){this.logger.error(`Error handling SSE connection`,t),e.headersSent||(e.writeHead(500),e.end(`Internal Server Error`))}}async handlePostMessage(e,t){let n=new URL(e.url??`/`,`http://${e.headers.host??this.config.host}`).searchParams.get(`sessionId`);if(!n){t.writeHead(400),t.end(`Missing sessionId query parameter`);return}let r=this.sessionManager.getSession(n);if(!r){t.writeHead(404),t.end(`No transport found for sessionId`);return}try{let n=await vt(e);await r.handlePostMessage(e,t,n)}catch(e){this.logger.error(`Error handling post message`,e),t.headersSent||(t.writeHead(500),t.end(`Internal Server Error`))}}async start(){return new Promise((e,t)=>{try{let n=(0,ue.getRequestListener)(this.honoApp.fetch),r=(0,ce.createServer)(async(e,t)=>{let r=new URL(e.url??`/`,`http://${e.headers.host??this.config.host}`),i=e.method?.toUpperCase();r.pathname===`/sse`&&i===`GET`?await this.handleSseConnection(t):r.pathname===`/messages`&&i===`POST`?await this.handlePostMessage(e,t):n(e,t)});r.listen(this.config.port,this.config.host,()=>{this.logger.info(`@agimon-ai/mcp-proxy MCP server started with SSE transport on http://${this.config.host}:${this.config.port}`),this.logger.info(`SSE endpoint: http://${this.config.host}:${this.config.port}/sse`),this.logger.info(`Messages endpoint: http://${this.config.host}:${this.config.port}/messages`),this.logger.info(`Health check: http://${this.config.host}:${this.config.port}/health`),e()}),r.on(`error`,e=>{t(e)}),this.server=r}catch(e){t(e)}})}async stop(){return new Promise((e,t)=>{if(this.server){let n=this.server;(async()=>{try{await this.sessionManager.clear(),n.close(n=>{n?t(n):(this.server=null,e())})}catch(e){t(e)}})()}else e()})}getPort(){return this.config.port}getHost(){return this.config.host}},X=class{server;transport=null;logger;constructor(e,t=console){this.server=e,this.logger=t}async start(){this.transport=new me.StdioServerTransport,await this.server.connect(this.transport),this.logger.info(`@agimon-ai/mcp-proxy MCP server started on stdio`)}async stop(){this.transport&&=(await this.transport.close(),null)}};const bt=[`econnrefused`,`econnreset`,`enotfound`,`connection refused`,`fetch failed`,`socket hang up`,`network error`,`failed to fetch`];function xt(e){if(!(e instanceof Error))return!1;let t=e.message.toLowerCase();return bt.some(e=>t.includes(e))}function St(e){let t=new Set,n=[],r=e;for(;r&&!t.has(r);){if(t.add(r),r instanceof Error){let e=r;n.push({message:r.message,code:e.code}),r=e.cause;continue}if(typeof r==`object`){let e=r;n.push({message:typeof e.message==`string`?e.message:String(r),code:typeof e.code==`string`?e.code:void 0}),r=e.cause;continue}n.push({message:String(r)});break}return n}function Ct(e){return St(e).some(({message:e,code:t})=>{let n=e.toLowerCase(),r=wt(t);return n.includes(`unknown session`)||n.includes(`session not found`)||n.includes(`transport closed`)||n.includes(`connection closed`)||n.includes(`socket hang up`)||n.includes(`fetch failed`)||r===`econnreset`})}function wt(e){return typeof e==`string`?e.toLowerCase():void 0}var Tt=class{endpoint;resolveEndpoint;stdioProxyServer=null;stdioTransport=null;httpClient=null;logger;MAX_RECONNECT_ATTEMPTS=5;RECONNECT_BASE_MS=1e3;RECONNECT_MAX_MS=3e4;constructor(e,t=console){this.endpoint=e.endpoint,this.resolveEndpoint=e.resolveEndpoint,this.logger=t}async start(){try{let e=await this.createAndConnectClient();this.httpClient=e,this.stdioProxyServer=this.createProxyServer(),this.registerElicitationHandler(e),this.stdioTransport=new me.StdioServerTransport,await this.stdioProxyServer.connect(this.stdioTransport),this.logger.info(`@agimon-ai/mcp-proxy MCP stdio proxy connected to ${this.endpoint.toString()}`)}catch(e){throw await this.stop(),Error(`Failed to start stdio-http proxy transport: ${e instanceof Error?e.message:String(e)}`)}}async stop(){let e=this.stdioTransport,t=this.stdioProxyServer,n=this.httpClient;this.stdioTransport=null,this.stdioProxyServer=null,this.httpClient=null;let r=[];if(await Promise.all([(async()=>{try{e&&await e.close()}catch(e){r.push(`failed closing stdio transport: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{t&&await t.close()}catch(e){r.push(`failed closing stdio proxy server: ${e instanceof Error?e.message:String(e)}`)}})(),(async()=>{try{n&&await n.close()}catch(e){r.push(`failed closing http client: ${e instanceof Error?e.message:String(e)}`)}})()]),r.length>0)throw Error(`Failed to stop stdio-http proxy transport: ${r.join(`; `)}`)}async createAndConnectClient(){let e=new re.StreamableHTTPClientTransport(this.endpoint),t=new h.Client({name:`@agimon-ai/mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{elicitation:{}}});return await t.connect(e),t}registerElicitationHandler(e){let t=this.stdioProxyServer;t&&e.setRequestHandler(_.ElicitRequestSchema,async e=>await t.elicitInput(e.params))}async reconnectWithBackoff(){for(let e=0;e<this.MAX_RECONNECT_ATTEMPTS;e++){let t=Math.min(this.RECONNECT_BASE_MS*2**e,this.RECONNECT_MAX_MS);await new Promise(e=>setTimeout(e,t));try{this.resolveEndpoint&&(this.endpoint=await this.resolveEndpoint()),await this.httpClient?.close().catch(()=>void 0);let t=await this.createAndConnectClient();this.httpClient=t,this.registerElicitationHandler(t),this.logger.info(`Reconnected to HTTP backend at ${this.endpoint.toString()} (attempt ${e+1})`);return}catch{this.logger.info(`Reconnect attempt ${e+1}/${this.MAX_RECONNECT_ATTEMPTS} to ${this.endpoint.toString()} failed`)}}throw Error(`Failed to reconnect to HTTP backend at ${this.endpoint.toString()} after ${this.MAX_RECONNECT_ATTEMPTS} attempts`)}async withReconnect(e){if(!this.httpClient)throw Error(`HTTP client not connected`);try{return await e()}catch(t){if(xt(t)||Ct(t))return await this.reconnectWithBackoff(),await e();throw t}}createProxyServer(){let e=new v.Server({name:`@agimon-ai/mcp-proxy-stdio-http-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}}});return e.setRequestHandler(_.ListToolsRequestSchema,async()=>{try{return await this.withReconnect(()=>this.httpClient.listTools())}catch(e){throw Error(`Failed forwarding tools/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(_.CallToolRequestSchema,async e=>{try{return await this.withReconnect(()=>this.httpClient.callTool({name:e.params.name,arguments:e.params.arguments}))}catch(t){throw Error(`Failed forwarding tools/call (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(_.ListResourcesRequestSchema,async()=>{try{return await this.withReconnect(()=>this.httpClient.listResources())}catch(e){throw Error(`Failed forwarding resources/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(_.ReadResourceRequestSchema,async e=>{try{return await this.withReconnect(()=>this.httpClient.readResource({uri:e.params.uri}))}catch(t){throw Error(`Failed forwarding resources/read (${e.params.uri}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e.setRequestHandler(_.ListPromptsRequestSchema,async()=>{try{return await this.withReconnect(()=>this.httpClient.listPrompts())}catch(e){throw Error(`Failed forwarding prompts/list to HTTP backend: ${e instanceof Error?e.message:String(e)}`)}}),e.setRequestHandler(_.GetPromptRequestSchema,async e=>{try{return await this.withReconnect(()=>this.httpClient.getPrompt({name:e.params.name,arguments:e.params.arguments}))}catch(t){throw Error(`Failed forwarding prompts/get (${e.params.name}) to HTTP backend: ${t instanceof Error?t.message:String(t)}`)}}),e}};function Z(e=console){return{createConfigFetcherService:t=>new ze(t,e),createClientManagerService:()=>new j(e),createRuntimeStateService:t=>new L(t,e),createStopServerService:t=>new ut(t,e),createSkillService:(t,n,r)=>new nt(t,n,r,e),createDefinitionsCacheService:(t,n,r)=>new E(t,n,r,e),createPrefetchService:e=>new et(e),createDescribeToolsTool:(e,t,n,r)=>new H(e,t,n,r),createUseToolTool:(e,t,n,r)=>new J(e,t,n,r),createSearchListToolsTool:(e,t)=>new K(e,t),createStdioTransportHandler:async t=>new X(await t(),e),createSseTransportHandler:async(t,n)=>new yt(await t(),n,e),createHttpTransportHandler:(t,n,r)=>new gt(t,n,r,e),createStdioHttpTransportHandler:t=>new Tt({endpoint:t},e)}}async function Q(e){let t=await O({workspaceRoot:process.cwd(),serviceName:`@agimon-ai/mcp-proxy`}),n=t,r=Z(n),i=r.createClientManagerService();try{let a,o,s,c,l=!1;if(e?.configFilePath){let t;try{t=await r.createConfigFetcherService({configFilePath:e.configFilePath,useCache:!e.noCache}).fetchConfiguration(e.noCache||!1)}catch(t){throw Error(`Failed to load MCP configuration from '${e.configFilePath}': ${t instanceof Error?t.message:String(t)}`)}if(a=t.skills,o=t.id,s=E.generateConfigHash(t),c=e.definitionsCachePath||E.getDefaultCachePath(e.configFilePath),i.registerServerConfigs(t.mcpServers),e.clearDefinitionsCache&&c&&(await E.clearFile(c),n.info(`[definitions-cache] Cleared ${c}`)),c)try{let e=await E.readFromFile(c);E.isCacheValid(e,{configHash:s,oneMcpVersion:y})&&(l=!0)}catch(e){n.warn(`[definitions-cache] Failed to inspect ${c}; falling back to live discovery`,e)}if(l)n.info(`[definitions-cache] Using cached definitions from ${c}`);else{let e=[],r=Object.entries(t.mcpServers).map(async([t,r])=>{try{await i.connectToServer(t,r),n.info(`Connected to MCP server: ${t}`)}catch(r){let i=r instanceof Error?r:Error(String(r));e.push({serverName:t,error:i}),n.warn(`Failed to connect to ${t}`,r)}});if(await Promise.all(r),e.length>0&&e.length<Object.keys(t.mcpServers).length&&n.warn(`Warning: Some MCP server connections failed: ${e.map(e=>e.serverName).join(`, `)}`),e.length>0&&e.length===Object.keys(t.mcpServers).length)throw Error(`All MCP server connections failed: ${e.map(e=>`${e.serverName}: ${e.error.message}`).join(`, `)}`)}}let u=e?.serverId||o||He();n.info(`[mcp-proxy] Server ID: ${u}`);let d=(e?.skills||a)?.paths??[],f={describeTools:null},p=d.length>0?r.createSkillService(process.cwd(),d,{onCacheInvalidated:()=>{f.describeTools?.clearAutoDetectedSkillsCache()}}):void 0,m;if(c)try{let e=await E.readFromFile(c);m=E.isCacheValid(e,{configHash:s,oneMcpVersion:y})?r.createDefinitionsCacheService(i,p,{cacheData:e}):r.createDefinitionsCacheService(i,p)}catch(e){n.warn(`[definitions-cache] Failed to load ${c}, falling back to live discovery: ${e instanceof Error?e.message:`Unknown error`}`),m=r.createDefinitionsCacheService(i,p)}else m=r.createDefinitionsCacheService(i,p);let ee=e?.proxyMode||`meta`,h=r.createDescribeToolsTool(i,p,u,m),te=r.createUseToolTool(i,p,u,m),ne=r.createSearchListToolsTool(i,m);return f.describeTools=h,p&&p.startWatching().catch(e=>{n.warn(`[skill-watcher] File watcher failed (non-critical): ${e instanceof Error?e.message:`Unknown error`}`)}),!l&&c&&e?.configFilePath&&m.collectForCache({configPath:e.configFilePath,configHash:s,oneMcpVersion:y,serverId:u}).then(e=>E.writeToFile(c,e)).then(()=>{n.info(`[definitions-cache] Wrote ${c}`)}).catch(e=>{n.warn(`[definitions-cache] Failed to persist ${c}: ${e instanceof Error?e.message:`Unknown error`}`)}),{clientManager:i,definitionsCacheService:m,skillService:p,describeTools:h,useTool:te,searchListTools:ne,serverId:u,proxyMode:ee,dispose:async()=>{try{await i.disconnectAll()}finally{p&&p.stopWatching(),await t.shutdown()}}}}catch(e){throw await t.shutdown(),e}}async function Et(e){let t=await e();return Z().createStdioTransportHandler(()=>Promise.resolve(t))}async function Dt(e,t){let n=await e();return Z().createSseTransportHandler(()=>Promise.resolve(n),t)}function Ot(e,t,n){return Z().createHttpTransportHandler(e,t,n)}function kt(e){return Z().createStdioHttpTransportHandler(e)}async function At(e){return Q(e)}function $(e){let t=e.tools.map(e=>e.name),n=W(e.tools),r=n.length>0?`; capabilities: ${n.join(`, `)}`:``;return t.length===0?`${e.serverName} (no tools cached${r})`:`${e.serverName} (${t.join(`, `)})${r}`}function jt(e,t){let n=[`Proxied from server "${e.serverName}" as tool "${t.name}".`];e.serverInstruction&&n.push(`Server summary: ${e.serverInstruction}`),t.description&&!e.omitToolDescription&&n.push(t.description);let r=U(t);return r.length>0&&n.push(`Capabilities: ${r.join(`, `)}`),n.join(`
52
+
53
+ `)}function Mt(e){let t=new Map;for(let n of e)for(let e of n.tools)t.has(e.name)||t.set(e.name,[]),t.get(e.name)?.push(n.serverName);let n=[];for(let r of e)for(let e of r.tools){let i=(t.get(e.name)||[]).length>1;n.push({name:i?`${r.serverName}__${e.name}`:e.name,description:jt(r,e),inputSchema:e.inputSchema,_meta:e._meta})}return n}async function Nt(e,t){let[n,r]=await Promise.all([t?t.getSkills():e.getCachedFileSkills(),e.getServerDefinitions()]);return n.length>0||r.some(e=>e.promptSkills.length>0)}function Pt(e,t){let n=e.length>0?e.map($).join(`; `):`No proxied servers available.`;return{name:H.TOOL_NAME,description:`Get detailed skill instructions for file-based skills and prompt-based skills proxied by mcp-proxy.\n\nProxy summary: ${n}\n\nUse this when you need the full instructions for a skill. For MCP tools, call the flat tool names directly. Only use skills discovered from describe_tools with id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function Ft(e,t){let n=e.length>0?e.map($).join(`; `):`No proxied servers available.`;return{name:H.TOOL_NAME,description:`Get detailed schemas and skill instructions for proxied MCP capabilities.\n\nProxy summary: ${n}\n\nUse list_tools first to search capability summaries and discover tool names. Then use describe_tools to fetch full schemas or skill instructions. Only use capabilities discovered from mcp-proxy id="${t}".`,inputSchema:{type:`object`,properties:{toolNames:{type:`array`,items:{type:`string`,minLength:1},description:`List of tool or skill names to get detailed information about`,minItems:1}},required:[`toolNames`],additionalProperties:!1}}}function It(e,t,n){let r=e.length>0?e.map($).join(`; `):`No proxied servers available.`;return t===`flat`?[`mcp-proxy proxies downstream MCP servers and exposes their tools and resources directly.`,`Proxied servers and tools: ${r}`,n?`Skills are still exposed through describe_tools when file-based skills or prompt-backed skills are configured.`:`No skills are currently exposed through describe_tools.`].join(`
54
+
55
+ `):t===`search`?[`mcp-proxy proxies downstream MCP servers in search mode.`,`Proxied servers and tools: ${r}`,`Use list_tools to search capability summaries and discover tool names, describe_tools to fetch schemas or skill instructions, and use_tool to execute tools.`].join(`
56
+
57
+ `):[`mcp-proxy proxies downstream MCP servers in meta mode.`,`Proxied servers and tools: ${r}`,`Use describe_tools to inspect capabilities and use_tool to execute them.`].join(`
58
+
59
+ `)}async function Lt(e){let{clientManager:t,definitionsCacheService:n,skillService:r,describeTools:i,useTool:a,searchListTools:o,serverId:s,proxyMode:c}=e,l=new v.Server({name:`@agimon-ai/mcp-proxy`,version:`0.1.0`},{capabilities:{tools:{},resources:{},prompts:{}},instructions:It(await n.getServerDefinitions(),c,await Nt(n,r))});return l.setRequestHandler(_.ListToolsRequestSchema,async()=>({tools:c===`flat`?await(async()=>{let e=await n.getServerDefinitions(),t=await Nt(n,r);return[...Mt(e),...t?[Pt(e,s)]:[]]})():c===`search`?await(async()=>[Ft(await n.getServerDefinitions(),s),await o.getDefinition(),a.getDefinition()])():[await i.getDefinition(),a.getDefinition()]})),l.setRequestHandler(_.CallToolRequestSchema,async e=>{let{name:t,arguments:n}=e.params,r=async(e,t)=>{let r=(0,g.coerceArgs)(n??{},e.getInputSchema());try{return await e.execute(r)}catch(n){if(n instanceof d.z.ZodError)return{content:[{type:`text`,text:(0,g.formatZodError)(n,{schemaName:t,schema:e.getInputSchema()})}],isError:!0};throw Error(`Failed to execute ${t}: ${n instanceof Error?n.message:String(n)}`)}};if(t===H.TOOL_NAME)return await r(i,t);if(t===J.TOOL_NAME)return await r(a,t);if(t===K.TOOL_NAME&&c===`search`)return await r(o,t);if(c===`flat`)return await a.execute({toolName:t,toolArgs:n||{}});throw Error(`Unknown tool: ${t}`)}),l.setRequestHandler(_.ListResourcesRequestSchema,async()=>{let e=await n.getServerDefinitions(),t=new Map;for(let n of e)for(let e of n.resources)t.has(e.uri)||t.set(e.uri,[]),t.get(e.uri)?.push(n.serverName);let r=[];for(let n of e)for(let e of n.resources){let i=(t.get(e.uri)||[]).length>1;r.push({...e,uri:i?`${n.serverName}__${e.uri}`:e.uri})}return{resources:r}}),l.setRequestHandler(_.ReadResourceRequestSchema,async e=>{let{uri:r}=e.params,{serverName:i,actualToolName:a}=C(r);if(i)return await(await t.ensureConnected(i)).readResource(a);let o=await n.getServersForResource(a);if(o.length===0)throw Error(`Resource not found: ${r}`);if(o.length>1)throw Error(`Resource "${a}" exists on multiple servers: ${o.join(`, `)}. Use the prefixed format (e.g., "${o[0]}__${a}") to specify which server to use.`);return await(await t.ensureConnected(o[0])).readResource(a)}),l.setRequestHandler(_.ListPromptsRequestSchema,async()=>{let e=await n.getServerDefinitions(),t=new Map,r=new Map;for(let n of e){r.set(n.serverName,n.prompts);for(let e of n.prompts)t.has(e.name)||t.set(e.name,[]),t.get(e.name).push(n.serverName)}let i=[];for(let n of e){let e=r.get(n.serverName)||[];for(let r of e){let e=(t.get(r.name)||[]).length>1;i.push({name:e?`${n.serverName}__${r.name}`:r.name,description:r.description,arguments:r.arguments})}}return{prompts:i}}),l.setRequestHandler(_.GetPromptRequestSchema,async e=>{let{name:r,arguments:i}=e.params,a=await n.getServerDefinitions(),{serverName:o,actualToolName:s}=C(r);if(o)return await(await t.ensureConnected(o)).getPrompt(s,i);let c=[];for(let e of a)e.prompts.some(e=>e.name===r)&&c.push(e.serverName);if(c.length===0)throw Error(`Prompt not found: ${r}`);if(c.length>1)throw Error(`Prompt "${r}" exists on multiple servers: ${c.join(`, `)}. Use the prefixed format (e.g., "${c[0]}__${r}") to specify which server to use.`);let l=t.getClient(c[0]);return l?await l.getPrompt(r,i):await(await t.ensureConnected(c[0])).getPrompt(r,i)}),l}async function Rt(e){let t=await Q(e),n=await Lt(t);return Object.assign(n,{dispose:t.dispose}),n}const zt={STDIO:`stdio`,HTTP:`http`,SSE:`sse`};Object.defineProperty(exports,`C`,{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,`D`,{enumerable:!0,get:function(){return y}}),Object.defineProperty(exports,`E`,{enumerable:!0,get:function(){return ze}}),Object.defineProperty(exports,`O`,{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,`S`,{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,`T`,{enumerable:!0,get:function(){return Ve}}),Object.defineProperty(exports,`_`,{enumerable:!0,get:function(){return H}}),Object.defineProperty(exports,`a`,{enumerable:!0,get:function(){return Q}}),Object.defineProperty(exports,`b`,{enumerable:!0,get:function(){return L}}),Object.defineProperty(exports,`c`,{enumerable:!0,get:function(){return kt}}),Object.defineProperty(exports,`d`,{enumerable:!0,get:function(){return Tt}}),Object.defineProperty(exports,`f`,{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,`g`,{enumerable:!0,get:function(){return K}}),Object.defineProperty(exports,`h`,{enumerable:!0,get:function(){return J}}),Object.defineProperty(exports,`i`,{enumerable:!0,get:function(){return Ot}}),Object.defineProperty(exports,`l`,{enumerable:!0,get:function(){return Et}}),Object.defineProperty(exports,`m`,{enumerable:!0,get:function(){return gt}}),Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return Rt}}),Object.defineProperty(exports,`o`,{enumerable:!0,get:function(){return Z}}),Object.defineProperty(exports,`p`,{enumerable:!0,get:function(){return yt}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return Lt}}),Object.defineProperty(exports,`s`,{enumerable:!0,get:function(){return Dt}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return zt}}),Object.defineProperty(exports,`u`,{enumerable:!0,get:function(){return At}}),Object.defineProperty(exports,`v`,{enumerable:!0,get:function(){return ut}}),Object.defineProperty(exports,`w`,{enumerable:!0,get:function(){return He}}),Object.defineProperty(exports,`x`,{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,`y`,{enumerable:!0,get:function(){return nt}});
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@agimon-ai/mcp-proxy",
3
3
  "description": "MCP proxy server package",
4
- "version": "0.10.5",
4
+ "version": "0.10.7",
5
5
  "license": "AGPL-3.0",
6
6
  "keywords": [
7
7
  "mcp",
@@ -28,10 +28,10 @@
28
28
  "js-yaml": "4.1.1",
29
29
  "liquidjs": "10.25.5",
30
30
  "zod": "4.3.6",
31
- "@agimon-ai/foundation-validator": "0.5.0",
32
- "@agimon-ai/log-sink-mcp": "0.8.0",
33
- "@agimon-ai/foundation-port-registry": "0.8.0",
34
- "@agimon-ai/foundation-process-registry": "0.8.0"
31
+ "@agimon-ai/foundation-validator": "0.5.2",
32
+ "@agimon-ai/foundation-process-registry": "0.8.2",
33
+ "@agimon-ai/foundation-port-registry": "0.8.2",
34
+ "@agimon-ai/log-sink-mcp": "0.8.2"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/js-yaml": "4.0.9",
package/dist/cli.d.cts DELETED
@@ -1 +0,0 @@
1
- export { };
package/dist/cli.d.mts DELETED
@@ -1 +0,0 @@
1
- export { };