@routecraft/ai 0.4.0 → 0.5.0-canary.10

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,3 +1,3 @@
1
- 'use strict';var routecraft=require('@routecraft/routecraft'),ai=require('ai'),crypto$1=require('crypto'),async_hooks=require('async_hooks'),http=require('http');var te={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function Te(t,e){return typeof t=="object"&&t!==null&&t[e]===true}function Ce(t){return Te(t,te.McpAdapter)}function L(t,e){throw new Error(`The ${e} LLM provider requires the "${t}" package. Install it with: pnpm add ${t}`)}function I(t,e){if(!(t instanceof Error))return false;let n=t.message??"";return (n.includes("ERR_MODULE_NOT_FOUND")||n.includes("Cannot find module")||n.includes("Cannot find package"))&&n.includes(e)}var xe={ollama:{baseURL:"http://localhost:11434/api"}};function D(t){return {...t.inputTokens!==void 0&&{inputTokens:t.inputTokens},...t.outputTokens!==void 0&&{outputTokens:t.outputTokens},...t.totalTokens!==void 0&&{totalTokens:t.totalTokens}}}function _(t){try{if("output"in t&&t.output!==void 0)return t.output}catch{}}function ne(t,e,n){if(t===null||typeof t!="object")throw new Error(`[${e}] Invalid model: expected an object, got ${typeof t}. Model id: ${n}`);let r=t;if(typeof r.doGenerate!="function")throw new Error(`[${e}] Invalid model: missing or invalid doGenerate method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`);if(typeof r.doStream!="function")throw new Error(`[${e}] Invalid model: missing or invalid doStream method. Model id: ${n}. Ensure the provider returns an AI SDK-compatible language model.`)}async function re(t){let{config:e,modelId:n,options:r,systemPrompt:o,userPrompt:i,output:a}=t;switch(e.provider){case "openai":return ke(e,n,r,o,i,a);case "anthropic":return Oe(e,n,r,o,i,a);case "gemini":return Ae(e,n,r,o,i,a);case "openrouter":return Le(e,n,r,o,i,a);case "ollama":return Ie(e,n,r,o,i,a);default:{let u=e;throw new Error(`LLM provider not implemented: ${u.provider}`)}}}async function ke(t,e,n,r,o,i){let a;try{a=(await import('@ai-sdk/openai')).createOpenAI;}catch(h){throw I(h,"@ai-sdk/openai")&&L("@ai-sdk/openai","OpenAI"),h}let{generateText:u}=await import('ai'),d={apiKey:t.apiKey};t.baseURL!==void 0&&(d.baseURL=t.baseURL);let p={model:a(d)(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(p.system=r),n.topP!==void 0&&(p.topP=n.topP),n.frequencyPenalty!==void 0&&(p.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(p.presencePenalty=n.presencePenalty);let l=i!==void 0?{...p,output:i}:p,m=await u(l),g={text:m.text??"",raw:m};m.usage&&(g.usage=D(m.usage));let c=_(m);return c!==void 0&&(g.output=c),g}async function Oe(t,e,n,r,o,i){let a;try{a=(await import('@ai-sdk/anthropic')).createAnthropic;}catch(c){throw I(c,"@ai-sdk/anthropic")&&L("@ai-sdk/anthropic","Anthropic"),c}let{generateText:u}=await import('ai'),s={model:a({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(s.system=r),n.topP!==void 0&&(s.topP=n.topP),n.frequencyPenalty!==void 0&&(s.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(s.presencePenalty=n.presencePenalty);let p=i!==void 0?{...s,output:i}:s,l=await u(p),m={text:l.text??"",raw:l};l.usage&&(m.usage=D(l.usage));let g=_(l);return g!==void 0&&(m.output=g),m}async function Ae(t,e,n,r,o,i){let a;try{a=(await import('@ai-sdk/google')).createGoogleGenerativeAI;}catch(c){throw I(c,"@ai-sdk/google")&&L("@ai-sdk/google","Gemini"),c}let{generateText:u}=await import('ai'),s={model:a({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(s.system=r),n.topP!==void 0&&(s.topP=n.topP),n.frequencyPenalty!==void 0&&(s.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(s.presencePenalty=n.presencePenalty);let p=i!==void 0?{...s,output:i}:s,l=await u(p),m={text:l.text??"",raw:l};l.usage&&(m.usage=D(l.usage));let g=_(l);return g!==void 0&&(m.output=g),m}async function Le(t,e,n,r,o,i){let a;try{a=(await import('@openrouter/ai-sdk-provider')).createOpenRouter;}catch(y){throw I(y,"@openrouter/ai-sdk-provider")&&L("@openrouter/ai-sdk-provider","OpenRouter"),y}let{generateText:u}=await import('ai'),d=a({apiKey:t.apiKey}),f=t.modelId??e,s=d.chat(f);ne(s,"OpenRouter",f);let l={model:s,prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(l.system=r),n.topP!==void 0&&(l.topP=n.topP),n.frequencyPenalty!==void 0&&(l.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(l.presencePenalty=n.presencePenalty);let m=i!==void 0?{...l,output:i}:l,g=await u(m),c={text:g.text??"",raw:g};g.usage&&(c.usage=D(g.usage));let h=_(g);return h!==void 0&&(c.output=h),c}async function Ie(t,e,n,r,o,i){let a;try{a=(await import('ollama-ai-provider-v2')).createOllama;}catch(y){throw I(y,"ollama-ai-provider-v2")&&L("ollama-ai-provider-v2","Ollama"),y}let{generateText:u}=await import('ai'),d=a({baseURL:t.baseURL??xe.ollama.baseURL}),f=t.modelId??e,s=d(f);ne(s,"Ollama",f);let l={model:s,prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(l.system=r),n.topP!==void 0&&(l.topP=n.topP),n.frequencyPenalty!==void 0&&(l.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(l.presencePenalty=n.presencePenalty);let m=i!==void 0?{...l,output:i}:l,g=await u(m),c={text:g.text??"",raw:g};g.usage&&(c.usage=D(g.usage));let h=_(g);return h!==void 0&&(c.output=h),c}function oe(t){let e=t["~standard"];if(!e?.validate)throw new Error("LLM outputSchema must be a StandardSchemaV1 with ~standard.validate");let n=e.jsonSchema?.output?.({target:"draft-2020-12"})??e.jsonSchema?.input?.({target:"draft-2020-12"});if(!n||typeof n!="object")throw new Error("LLM outputSchema must expose ~standard.jsonSchema.output or .input for provider structured output");function r(i){let a;try{a=e.validate(i);}catch(d){return {success:false,error:d instanceof Error?d:new Error(String(d))}}return a instanceof Promise?{success:false,error:new Error("Async output schema is not supported for LLM structured output")}:a.issues!=null&&(Array.isArray(a.issues)?a.issues.length>0:typeof a.issues=="object"&&a.issues!==null?Object.keys(a.issues).length>0:!!a.issues)?{success:false,error:new Error(routecraft.formatSchemaIssues(a.issues))}:{success:true,value:a.value}}let o=ai.jsonSchema(n,{validate:r});return ai.Output.object({schema:o})}var M=Symbol.for("routecraft.adapter.llm.providers"),S=Symbol.for("routecraft.adapter.llm.options");async function Ue(t,e){let n;try{n=JSON.parse(t);}catch{return}let r=e["~standard"];if(!r?.validate)return;let o=r.validate(n);if(o instanceof Promise&&(o=await o),!(o&&typeof o=="object"&&"issues"in o&&o.issues))return o&&typeof o=="object"&&"value"in o?o.value:void 0}var Ne=0,$e=1024;function ie(t,e){return t===void 0||t===""?"":typeof t=="function"?t(e):t}function qe(t){let e=t.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}function se(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`LLM adapter: model id must be "providerId:modelName" (e.g. ollama:lfm2.5-thinking). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function Ge(t,e){if(!e)throw new Error(`LLM adapter: model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${M.description}" can be read.`);let n=e.getStore(M);if(!n)throw new Error('LLM provider not found: no providers registered. Add llmPlugin({ providers: { ollama: { provider: "ollama" }, ... } }) to your config.');let{providerId:r,modelName:o}=se(t),i=n.get(r);if(!i)throw new Error(`LLM provider "${r}" not found. Register it with llmPlugin({ providers: { "${r}": { provider, apiKey?, baseURL? } } }).`);return {config:i,modelName:o}}var E=class{constructor(e,n={}){this.modelId=e;this.options=n;}adapterId="routecraft.adapter.llm";options;mergedOptions(e){let n=e.getStore(S);return {temperature:Ne,maxTokens:$e,...n,...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=Ge(this.modelId,n),i=this.mergedOptions(n),a=ie(i.systemPrompt,e),u=ie(i.userPrompt,e)||qe(e),d={temperature:i.temperature,maxTokens:i.maxTokens};i.topP!==void 0&&(d.topP=i.topP),i.frequencyPenalty!==void 0&&(d.frequencyPenalty=i.frequencyPenalty),i.presencePenalty!==void 0&&(d.presencePenalty=i.presencePenalty);let f=i.outputSchema!==void 0?oe(i.outputSchema):void 0,s=await re({config:r,modelId:o,options:d,systemPrompt:a,userPrompt:u,output:f});if(s.output===void 0&&s.text&&i.outputSchema!==void 0){let p=await Ue(s.text,i.outputSchema);p!==void 0&&(s.output=p);}return s}getMetadata(e){let n=e,{providerId:r}=se(this.modelId),o={model:this.modelId,provider:r};return n.usage&&(n.usage.inputTokens!==void 0&&(o.inputTokens=n.usage.inputTokens),n.usage.outputTokens!==void 0&&(o.outputTokens=n.usage.outputTokens)),o}};function ae(t,e){return new E(t,e)}var le=["openai","anthropic","openrouter","ollama","gemini"];function Be(t){return le.includes(t)}function j(t){if(!t||typeof t!="object")throw new TypeError("llmPlugin: options must be an object");if(!t.providers||typeof t.providers!="object")throw new TypeError("llmPlugin: options.providers must be an object (record of provider id \u2192 options)");for(let[e,n]of Object.entries(t.providers))if(n!==void 0){if(!n||typeof n!="object")throw new TypeError(`llmPlugin: providers["${e}"] must be an object`);if(!Be(e))throw new TypeError(`llmPlugin: providers["${e}"] is not a supported provider. Supported: ${le.join(", ")}`);switch(e){case "openai":case "anthropic":case "openrouter":case "gemini":if(typeof n.apiKey!="string"||!n.apiKey.trim())throw new TypeError(`llmPlugin: providers["${e}"].apiKey is required`);break;case "ollama":if(n.baseURL!==void 0&&typeof n.baseURL!="string")throw new TypeError(`llmPlugin: providers["${e}"].baseURL must be a string when provided`);if(n.modelId!==void 0&&(typeof n.modelId!="string"||!n.modelId.trim()))throw new TypeError(`llmPlugin: providers["${e}"].modelId must be a non-empty string when provided`);break}}if(t.defaultOptions!==void 0&&(typeof t.defaultOptions!="object"||t.defaultOptions===null))throw new TypeError("llmPlugin: defaultOptions must be an object when provided")}var Ve=["openai","anthropic","openrouter","ollama","gemini"];function Fe(t,e){return {provider:t,...e}}function pe(t={providers:{}}){return j(t),{apply(e){let n=new Map;for(let r of Ve){let o=t.providers[r];o!==void 0&&n.set(r,Fe(r,o));}e.setStore(M,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(S,t.defaultOptions);}}}var b=Symbol.for("routecraft.mcp.plugin.registered"),v=Symbol.for("routecraft.mcp.client.servers"),U=Symbol.for("routecraft.mcp.tool.registry"),T=Symbol.for("routecraft.mcp.stdio.managers"),N=(s=>(s.TOOL="routecraft.mcp.tool",s.SESSION="routecraft.mcp.session",s.AUTH_SUBJECT="routecraft.auth.subject",s.AUTH_SCHEME="routecraft.auth.scheme",s.AUTH_ROLES="routecraft.auth.roles",s.AUTH_SCOPES="routecraft.auth.scopes",s.AUTH_EMAIL="routecraft.auth.email",s.AUTH_NAME="routecraft.auth.name",s.AUTH_ISSUER="routecraft.auth.issuer",s.AUTH_AUDIENCE="routecraft.auth.audience",s))(N||{});var R=Symbol.for("routecraft.mcp.adapter");var q=class{adapterId="routecraft.adapter.mcp";endpoint;options;constructor(e,n){if(this[R]=true,typeof e!="string")throw routecraft.rcError("RC5003",void 0,{message:"Dynamic endpoints cannot be used as source",suggestion:"Use a static string endpoint for source: .from(mcp('endpoint', options))."});if("url"in n||"serverId"in n)throw routecraft.rcError("RC5003",void 0,{message:"mcp() with url or serverId must be used as destination: .to(mcp({ url, tool }))",suggestion:"Use .to(mcp({ url: '...', tool: '...' })) to call a remote MCP server."});if("args"in n&&n.args!==void 0&&!("description"in n))throw routecraft.rcError("RC5003",void 0,{message:"mcp(endpoint, { args }) is for client usage with a 'server:tool' target, not for defining a source",suggestion:"Use .to(mcp('server:tool', { args })) to call a remote tool, or .from(mcp('endpoint', { description: '...' })) to define a source."});if(!("description"in n)||typeof n.description!="string")throw routecraft.rcError("RC5003",void 0,{message:"mcp(endpoint, options) as source requires options.description",suggestion:"Use .from(mcp('endpoint', { description: '...' })) to define a source."});this.endpoint=e,this.options=n;}async subscribe(e,n,r,o){if(e.getStore(b)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");return routecraft.direct(this.endpoint,this.options).subscribe(e,n,r,o)}};function G(t){let e=t?.content;if(!Array.isArray(e)||e.length===0)return t;if(e.length===1){let n=e[0];if(n.type==="text"&&typeof n.text=="string")return n.text;if(typeof n.data=="string")return n.data}return e}var ce=new WeakMap;async function Ke(t){if(typeof t=="function")return t();if(Array.isArray(t)){if(t.length===0)throw new Error("McpClientAuthOptions.token array must not be empty");let e=(ce.get(t)??0)%t.length;return ce.set(t,e+1),t[e]}return t}async function B(t){if(!t)return;let e={},n=t.headers??{},r=Object.entries(n).find(([o])=>o.toLowerCase()==="authorization")?.[1];if(r)e.Authorization=r;else if(t.token!==void 0){let o=await Ke(t.token);if(o.length===0)throw new Error("McpClientAuthOptions.token must be a non-empty string when provided");e.Authorization=`Bearer ${o}`;}for(let[o,i]of Object.entries(n))o.toLowerCase()!=="authorization"&&(e[o]=i);return Object.keys(e).length>0?e:void 0}function ze(t){let e=t.trim().toLowerCase();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new Error(`MCP client: url must be HTTP or HTTPS. Stdio is not supported in routes; register stdio clients via mcpPlugin({ clients: { name: { command, args } } }). Got: "${t.slice(0,50)}${t.length>50?"...":""}"`)}function Ye(t,e){return !t.serverId||!e?void 0:e.getStore(v)?.get(t.serverId)}function Xe(t,e){if(t.url)return ze(t.url),{url:t.url,auth:t.auth};if(t.serverId&&!e)throw new Error(`MCP client: serverId "${t.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${String(v)}" can be read.`);if(t.serverId&&e){let n=Ye(t,e);if(!n)throw new Error(`MCP client: serverId "${t.serverId}" not found in context store. Register it with context store key "${String(v)}".`);let r=typeof n=="string"?n:n.url,o=t.auth??(typeof n=="object"&&"auth"in n?n.auth:void 0);return {url:r,auth:o}}throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.")}var V=t=>typeof t.body=="object"&&t.body!==null?t.body:{input:t.body},H=class{constructor(e){this.options=e;if(this[R]=true,!e.url&&!e.serverId)throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.");if(e.url&&e.serverId)throw new Error("MCP client: cannot provide both url and serverId. Use either url for direct HTTP or serverId for registered servers.")}adapterId="routecraft.adapter.mcp";async send(e){let n=routecraft.getExchangeContext(e),r=this.options.tool??(typeof e.body=="object"&&e.body!==null&&"tool"in e.body&&typeof e.body.tool=="string"?e.body.tool:void 0);if(!r)throw new Error("MCP client: tool name required. Set options.tool or exchange.body.tool.");let i=(this.options.args??V)(e);if(this.options.serverId&&n){let s=n.getStore(T)?.get(this.options.serverId);if(s){let m=await s.callTool(r,i);return m&&typeof m=="object"&&(m.metadata={toolName:r,transport:"stdio",serverId:this.options.serverId}),m}let l=n.getStore(v)?.get(this.options.serverId);if(l&&typeof l=="object"&&"transport"in l&&l.transport==="stdio")throw new Error(`MCP client: stdio server "${this.options.serverId}" is not running. Ensure mcpPlugin is applied and the stdio client started successfully.`)}let{url:a,auth:u}=Xe(this.options,n),d=await this.callRemoteTool(a,r,i,u);return d&&typeof d=="object"&&(d.metadata={toolName:r,url:a,transport:"http",...this.options.serverId?{serverId:this.options.serverId}:{}}),d}getMetadata(e){return e&&typeof e=="object"&&"metadata"in e?e.metadata:{toolName:"unknown",transport:"unknown"}}async callRemoteTool(e,n,r,o){let i,a;try{i=await import('@modelcontextprotocol/sdk/client/index.js'),a=await import('@modelcontextprotocol/sdk/client/streamableHttp.js');}catch{throw new Error('MCP client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk')}let u=i.Client,d=a.StreamableHTTPClientTransport,f=new URL(e),s=await B(o),p=s?{requestInit:{headers:s}}:void 0,l=new d(f,p),m={name:"routecraft-mcp-client",version:"1.0.0"},g=new u(m,{capabilities:{}});try{await g.connect.call(g,l);let y=await g.callTool.call(g,{name:n,arguments:r});return G(y)}finally{let c=g,h=c.close??c.disconnect;if(typeof h=="function")try{await Promise.resolve(h.call(g));}catch{}let y=l,w=y.close??y.destroy;if(typeof w=="function")try{await Promise.resolve(w.call(l));}catch{}}}};function ue(t,e){if(typeof t=="object"&&t!==null&&("url"in t||"serverId"in t)){let o=t;if(typeof o.auth?.token=="string"&&o.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(o.auth?.token)){if(o.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let i=0;i<o.auth.token.length;i++){let a=o.auth.token[i];if(typeof a!="string"||a.trim().length===0)throw new TypeError(`mcp(): auth.token[${i}] must be a non-empty string`)}}return new H(o)}let n=e===void 0||typeof e=="object"&&e!==null&&!("description"in e);if(typeof t=="string"&&t.includes(":")&&n){let o=t.indexOf(":"),i=t.slice(0,o),a=t.slice(o+1),u={serverId:i,tool:a};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(u.args=e.args),new H(u)}let r=t;if(e!==void 0)return new q(r,e);throw routecraft.rcError("RC5003",void 0,{message:"mcp() with only an endpoint is not supported. Use direct('endpoint') for in-process. For MCP server use .from(mcp('endpoint', { description: '...' })); for client use .to(mcp({ url, tool })) or .to(mcp('server:tool', { args })).",suggestion:"Use .from(mcp('endpoint', { description: '...' })) or .to(mcp({ url, tool })) or direct('endpoint')."})}var X={HS256:"sha256",HS384:"sha384",HS512:"sha512"},Q={RS256:"RSA-SHA256",RS384:"RSA-SHA384",RS512:"RSA-SHA512"};function de(t){let e=t.split(".");if(e.length!==3)return null;let[n,r,o]=e;try{let i=JSON.parse(Buffer.from(n,"base64url").toString()),a=JSON.parse(Buffer.from(r,"base64url").toString());return {headerB64:n,payloadB64:r,signatureB64:o,header:i,payload:a}}catch{return null}}function me(t,e){let n=Math.floor(Date.now()/1e3);return !(typeof t.exp=="number"&&n>t.exp+e||typeof t.nbf=="number"&&n<t.nbf-e)}function ge(t){let e=t.sub;if(typeof e!="string"||e.length===0)return null;let n={subject:e,scheme:"bearer",claims:t};typeof t.iss=="string"&&(n.issuer=t.iss),typeof t.exp=="number"&&(n.expiresAt=t.exp),typeof t.email=="string"&&(n.email=t.email),typeof t.name=="string"&&(n.name=t.name);let r=t.aud;Array.isArray(r)?n.audience=r.filter(i=>typeof i=="string"):typeof r=="string"&&(n.audience=[r]);let o=t.scope;return typeof o=="string"&&(n.scopes=o.split(" ").filter(Boolean)),Array.isArray(t.roles)&&(n.roles=t.roles.filter(i=>typeof i=="string")),n}function nt(t){return "secret"in t}function rt(t){let{secret:e,algorithm:n="HS256",clockToleranceSec:r=0}=t;if(!e||typeof e!="string")throw new TypeError("jwt: secret must be a non-empty string");if(!(n in X))throw new TypeError(`jwt: unsupported algorithm "${n}". Supported: ${Object.keys(X).join(", ")}`);let o=X[n];return i=>{let a=de(i);if(!a)return null;let{headerB64:u,payloadB64:d,signatureB64:f,header:s,payload:p}=a;if(s.alg!==n)return null;let l=crypto$1.createHmac(o,e);l.update(`${u}.${d}`);let m=l.digest("base64url"),g=Buffer.from(m),c=Buffer.from(f);return g.length!==c.length||!crypto$1.timingSafeEqual(g,c)||!me(p,r)?null:ge(p)}}function ot(t){let{publicKey:e,algorithm:n="RS256",clockToleranceSec:r=0}=t;if(!e||typeof e!="string")throw new TypeError("jwt: publicKey must be a non-empty PEM string");if(!(n in Q))throw new TypeError(`jwt: unsupported algorithm "${n}". Supported: ${Object.keys(Q).join(", ")}`);let o=Q[n];return i=>{let a=de(i);if(!a)return null;let{headerB64:u,payloadB64:d,signatureB64:f,header:s,payload:p}=a;if(s.alg!==n)return null;let l=crypto$1.createVerify(o);return l.update(`${u}.${d}`),!l.verify(e,f,"base64url")||!me(p,r)?null:ge(p)}}function fe(t){return {validator:nt(t)?rt(t):ot(t)}}var he=new async_hooks.AsyncLocalStorage,Z='MCP server requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',x=class{context;options;server=null;transport=null;httpServer=null;httpSessions=new Map;running=false;toolsListLogged=false;constructor(e,n={}){this.context=e,this.options={name:"routecraft",version:"1.0.0",transport:"stdio",port:3001,host:"localhost",...n};}async start(){if(this.running){this.context.logger.warn({},"MCP server already running");return}try{let e=this.options.transport;e==="http"?await this.startHttp():await this.startStdio(),this.running=!0,this.context.logger.info({name:this.options.name,version:this.options.version,transport:e},"MCP server started"),this.logExposedToolsOnce();}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Failed to start MCP server";throw this.context.logger.error({err:e},n),e}}async startStdio(){let e,n;try{e=(await import('@modelcontextprotocol/sdk/server/index.js')).Server,n=(await import('@modelcontextprotocol/sdk/server/stdio.js')).StdioServerTransport;}catch{throw new Error(Z)}this.server=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}}),await this.setupRequestHandlers(),this.transport=new n,await this.server.connect(this.transport);}async startHttp(){let e;try{e=(await import('@modelcontextprotocol/sdk/server/index.js')).Server;}catch{throw new Error(Z)}let r=(await import('@modelcontextprotocol/sdk/server/streamableHttp.js').catch(()=>null))?.StreamableHTTPServerTransport;if(!r)throw new Error("StreamableHTTPServerTransport not found in MCP SDK - ensure @modelcontextprotocol/sdk v1.26.0+ is installed");let o=this.options.port,i=this.options.host,a=async()=>{let f=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}});await this.setupRequestHandlersOn(f);let s=new r({sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:c=>{this.httpSessions.set(c,{server:f,transport:s}),this.context.logger.debug({sessionId:c},"MCP session created"),this.context.emit("plugin:mcp:session:created",{sessionId:c});},enableJsonResponse:true});await f.connect(s);let l=s,m=l.onclose;l.onclose=()=>{let c=s.sessionId;c&&(this.httpSessions.delete(c),this.context.logger.debug({sessionId:c},"MCP session closed"),this.context.emit("plugin:mcp:session:closed",{sessionId:c})),m?.();};let g=s.handleRequest;if(typeof g!="function")throw new Error("StreamableHTTPServerTransport.handleRequest not found - SDK may have changed");return {transport:s,handleRequest:g.bind(s)}};this.httpServer=http.createServer(async(f,s)=>{let p=f.url?.split("?")[0]??"";if(p!=="/mcp"&&p!=="/mcp/"){s.writeHead(404,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:"Not Found",path:p}));return}let l;if(this.options.auth){let c=await this.validateAuth(f);if(!c){s.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":'Bearer realm="mcp"'}),s.end(JSON.stringify({error:"Unauthorized"}));return}l=c;}let m=f.headers["mcp-session-id"],g=c=>he.run(l,c);try{if(m&&this.httpSessions.has(m)){let c=this.httpSessions.get(m),h=c.transport.handleRequest;await g(()=>h.call(c.transport,f,s));}else if(!m||f.method==="POST"){let{handleRequest:c}=await a();await g(()=>c(f,s));}else s.writeHead(404,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:"Session not found"}));}catch(c){let h=routecraft.isRoutecraftError(c)?c.meta.message:c instanceof Error?c.message:"MCP HTTP request error";this.context.logger.error({err:c},h),s.headersSent||(s.writeHead(500,{"Content-Type":"application/json"}),s.end(JSON.stringify({error:"Internal Server Error"})));}}),await new Promise((f,s)=>{this.httpServer.listen(o,i,()=>f()),this.httpServer.on("error",p=>{let l=routecraft.isRoutecraftError(p)?p.meta.message:p instanceof Error?p.message:"MCP HTTP server listen failed";this.context.logger.error({err:p},l),s(p);});});let u=this.getHttpPort()??o,d={host:i,port:u,path:"/mcp"};this.context.logger.info(d,"MCP HTTP server listening"),this.context.emit("plugin:mcp:server:listening",d);}getHttpPort(){let e=this.httpServer?.address();if(e&&typeof e=="object"&&"port"in e)return e.port}async validateAuth(e){let n=this.options.auth;if(!n)return null;let r=e.headers.authorization;if(!r||Array.isArray(r)){let d={reason:"missing_header",scheme:"bearer",source:"mcp"};return this.context.logger.warn(d,"Auth rejected: missing or malformed Authorization header"),this.context.emit("auth:rejected",d),null}let o=/^bearer\s+(.+)$/i.exec(r);if(!o){let d={reason:"unsupported_scheme",scheme:"bearer",source:"mcp"};return this.context.logger.warn(d,"Auth rejected: unsupported authorization scheme"),this.context.emit("auth:rejected",d),null}let i=o[1],a=await n.validator(i);if(!a){let d={reason:"invalid_token",scheme:"bearer",source:"mcp"};return this.context.logger.warn(d,"Auth rejected: token validation failed"),this.context.emit("auth:rejected",d),null}let u={subject:a.subject,scheme:a.scheme,source:"mcp"};return this.context.logger.info(u,"Auth succeeded"),this.context.emit("auth:success",u),a}async setupRequestHandlers(){await this.setupRequestHandlersOn(this.server);}async setupRequestHandlersOn(e){let n;try{n=await import('@modelcontextprotocol/sdk/types.js');}catch{throw new Error(Z)}let r=n,o=r.ListToolsRequestSchema,i=r.CallToolRequestSchema;if(!o||!i)throw new Error("MCP SDK types missing ListToolsRequestSchema or CallToolRequestSchema - ensure @modelcontextprotocol/sdk is installed");let a=e;a.setRequestHandler(o,async()=>{let u=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:u}}),a.setRequestHandler(i,async u=>{let f=u.params;return await this.handleToolCall(f.name||"",f.arguments||{})});}async stop(){if(this.running)try{if(this.httpServer){for(let[,e]of this.httpSessions){let n=e.transport;typeof n.close=="function"&&await n.close();}this.httpSessions.clear(),await new Promise(e=>{this.httpServer.close(()=>e());}),this.httpServer=null;}if(this.transport){let e=this.transport;typeof e.close=="function"&&await e.close();}this.running=!1,this.context.logger.info({},"MCP server stopped");}catch(e){let n=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Error stopping MCP server";this.context.logger.error({err:e},n);}}logExposedToolsOnce(){if(this.toolsListLogged)return;let e=this.getAvailableTools();if(e.length===0)return;let n=e.map(o=>o.name??"?"),r={tools:n,count:n.length};this.context.logger.info(r,"Exposing MCP tools"),this.context.emit("plugin:mcp:server:tools:exposed",r),this.toolsListLogged=true;}getAvailableTools(){let e=this.context.getStore(routecraft.ADAPTER_DIRECT_REGISTRY);if(!e)return [];let n=Array.from(e.values()).filter(o=>o.description!==void 0),r=this.options.tools;if(r)if(Array.isArray(r)){let o=new Set(r);n=n.filter(i=>o.has(i.endpoint));}else typeof r=="function"&&(n=n.filter(r));return n.map(o=>this.metadataToMcpTool(o))}metadataToMcpTool(e){return {name:e.endpoint,description:e.description||"",inputSchema:this.schemaToJsonSchema(e.schema)}}schemaToJsonSchema(e){if(!e||typeof e!="object")return {type:"object"};let n=e["~standard"];if(n?.jsonSchema?.input)try{let r=n.jsonSchema.input({target:"draft-2020-12"});return typeof r=="object"&&r!==null?r:{type:"object"}}catch(r){return this.context.logger.debug(r,"Standard JSON Schema conversion failed"),{type:"object"}}return "~standard"in e?{type:"object",additionalProperties:true}:{type:"object"}}async handleToolCall(e,n){try{let r=this.context.getStore(routecraft.ADAPTER_DIRECT_STORE);if(!r){let l=new Error("No direct channels available");return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:l.message}),{isError:!0,content:[{type:"text",text:"Error: No direct channels available"}]}}let o=r.get(e);if(!o){let l=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:l.message}),{isError:!0,content:[{type:"text",text:`Error: Tool not found: ${e}`}]}}let i=typeof n=="string"?(()=>{try{return JSON.parse(n)||{}}catch{return {input:n}}})():n&&typeof n=="object"?n:{};this.context.logger.debug({bodyType:typeof i,body:i},"MCP tool call exchange body");let a=he.getStore(),u={"routecraft.mcp.tool":e,"routecraft.mcp.session":`mcp-${Date.now()}`};a&&(u["routecraft.auth.subject"]=a.subject,u["routecraft.auth.scheme"]=a.scheme,a.roles&&(u["routecraft.auth.roles"]=a.roles),a.scopes&&(u["routecraft.auth.scopes"]=a.scopes),a.email&&(u["routecraft.auth.email"]=a.email),a.name&&(u["routecraft.auth.name"]=a.name),a.issuer&&(u["routecraft.auth.issuer"]=a.issuer),a.audience&&(u["routecraft.auth.audience"]=a.audience));let d=new routecraft.DefaultExchange(this.context,{body:i,headers:u});this.context.emit("plugin:mcp:tool:called",{tool:e,args:n});let s=await o.send(e,d),p=typeof s.body=="string"?s.body:JSON.stringify(s.body);return this.context.emit("plugin:mcp:tool:completed",{tool:e}),{content:[{type:"text",text:p}]}}catch(r){let o=routecraft.isRoutecraftError(r)?r.meta.message:r instanceof Error?r.message:String(r);this.context.logger.error({tool:e,err:r},o),this.context.emit("plugin:mcp:tool:failed",{tool:e,error:o});let i=o;if(routecraft.isRoutecraftError(r)){let a=r.cause;a?.message&&(i=`${o}: ${a.message}`);}return {content:[{type:"text",text:`Error: ${i}`}],isError:true}}}};function ye(t){if(t.transport==="http"){if(t.port!==void 0){if(typeof t.port!="number")throw new TypeError("mcpPlugin: when transport is 'http', port must be a number");if(t.port<0||t.port>65535)throw new RangeError("mcpPlugin: port must be between 0 and 65535 when transport is 'http'")}if(t.host!==void 0&&typeof t.host!="string")throw new TypeError("mcpPlugin: when provided, host must be a string")}if(t.auth!==void 0&&typeof t.auth.validator!="function")throw new TypeError("mcpPlugin: auth.validator must be a function that returns an AuthPrincipal or null");if(t.clients){for(let[e,n]of Object.entries(t.clients))if(typeof n=="object"&&n!==null&&"transport"in n&&n.transport==="stdio"&&(!n.command||typeof n.command!="string"))throw new TypeError(`mcpPlugin: stdio client "${e}" must have a non-empty command string`)}if(t.maxRestarts!==void 0&&(typeof t.maxRestarts!="number"||!Number.isInteger(t.maxRestarts)||t.maxRestarts<0))throw new TypeError("mcpPlugin: maxRestarts must be a non-negative integer");if(t.restartDelayMs!==void 0&&(typeof t.restartDelayMs!="number"||t.restartDelayMs<=0))throw new TypeError("mcpPlugin: restartDelayMs must be a positive number");if(t.restartBackoffMultiplier!==void 0&&(typeof t.restartBackoffMultiplier!="number"||t.restartBackoffMultiplier<1))throw new TypeError("mcpPlugin: restartBackoffMultiplier must be >= 1");if(t.toolRefreshIntervalMs!==void 0&&(typeof t.toolRefreshIntervalMs!="number"||!Number.isInteger(t.toolRefreshIntervalMs)||t.toolRefreshIntervalMs<0))throw new TypeError("mcpPlugin: toolRefreshIntervalMs must be a non-negative integer")}async function we(t,e){let n=e["~standard"];if(!n?.validate)throw new Error("mcpPlugin: schema must be a StandardSchemaV1 with ~standard.validate");let r=n.validate(t);if(r instanceof Promise&&(r=await r),r.issues)throw new Error(`mcpPlugin options validation failed: ${routecraft.formatSchemaIssues(r.issues)}`);if(r.value===void 0)throw new Error("mcpPlugin options validation failed: no value returned");return r.value}var ut='MCP stdio client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',F=class{constructor(e,n,r,o){this.options=e;this.logger=n;this.onEvent=r;this.onToolsUpdated=o;}client=null;transport=null;running=false;stopping=false;restartCount=0;restartTimer=null;stabilityTimer=null;tools=[];async start(){if(this.running)return;this.stopping=false,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let e,n;try{e=await import('@modelcontextprotocol/sdk/client/index.js'),n=await import('@modelcontextprotocol/sdk/client/stdio.js');}catch{throw new Error(ut)}let{serverId:r,command:o,args:i,env:a,cwd:u}=this.options;this.transport=new n.StdioClientTransport({command:o,args:i??[],...a?{env:a}:{},...u?{cwd:u}:{},stderr:"pipe"});let d=this.transport;d.onerror=f=>{this.logger.error({err:f,serverId:r},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${r}:error`,{serverId:r,error:f});},d.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},d.stderr?.on&&d.stderr.on("data",f=>{this.logger.debug({serverId:r,stderr:String(f).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{},listChanged:{tools:{onChanged:(f,s)=>{s&&Array.isArray(s.tools)?(this.tools=s.tools,this.onToolsUpdated(r,this.tools),this.onEvent(`plugin:mcp:client:${r}:tools:listed`,{serverId:r,toolCount:this.tools.length})):this.refreshTools();}}}}),await this.client.connect(this.transport),this.running=true,await this.refreshTools(),this.logger.info({serverId:r,toolCount:this.tools.length},"Stdio client started"),this.onEvent(`plugin:mcp:client:${r}:started`,{serverId:r,toolCount:this.tools.length});}async stop(){this.stopping=true,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.stabilityTimer&&(clearTimeout(this.stabilityTimer),this.stabilityTimer=null);let{serverId:e}=this.options;if(this.client){try{await this.client.close();}catch{}this.client=null;}if(this.transport){let n=this.transport;if(typeof n.close=="function")try{await Promise.resolve(n.close());}catch{}this.transport=null;}this.running=false,this.logger.info({serverId:e},"Stdio client stopped"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"graceful"});}async callTool(e,n){if(!this.running||!this.client)throw new Error(`Stdio client "${this.options.serverId}" is not running. Cannot call tool "${e}".`);let r=await this.client.callTool({name:e,arguments:n});return G(r)}getTools(){return [...this.tools]}isRunning(){return this.running}async refreshTools(){if(!this.client)return;let{serverId:e}=this.options;try{let n=await this.client.listTools();this.tools=n.tools??[],this.onToolsUpdated(e,this.tools),this.onEvent(`plugin:mcp:client:${e}:tools:listed`,{serverId:e,toolCount:this.tools.length});}catch(n){this.logger.warn({err:n,serverId:e},"Failed to list tools for stdio client");}}handleDisconnect(){let{serverId:e,maxRestarts:n,restartDelayMs:r,restartBackoffMultiplier:o}=this.options;if(this.tools.length>0&&(this.tools=[],this.onToolsUpdated(e,[])),this.logger.warn({serverId:e},"Stdio client disconnected unexpectedly"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"unexpected"}),this.restartCount>=n){this.logger.error({serverId:e,restartCount:this.restartCount,maxRestarts:n},"Stdio client exceeded max restarts, giving up"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:new Error(`Max restarts (${n}) exceeded for stdio client "${e}"`)});return}let i=r*Math.pow(o,this.restartCount);this.logger.info({serverId:e,restartCount:this.restartCount,delayMs:i},"Scheduling stdio client restart"),this.restartTimer=setTimeout(()=>{this.restartTimer=null,this.restart();},i);}async restart(){let{serverId:e}=this.options;this.restartCount++,this.client=null,this.transport=null;try{await this.start(),this.logger.info({serverId:e,restartCount:this.restartCount},"Stdio client restarted successfully"),this.onEvent(`plugin:mcp:client:${e}:restarted`,{serverId:e,restartCount:this.restartCount});let n=this.options.restartDelayMs*2;this.stabilityTimer=setTimeout(()=>{this.stabilityTimer=null,this.running&&(this.restartCount=0);},n);}catch(n){this.logger.error({err:n,serverId:e,restartCount:this.restartCount},"Stdio client restart failed"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:n}),this.handleDisconnect();}}};var k=class{tools=new Map;setToolsForSource(e,n,r){let o=new Map;for(let i of r){let a={name:i.name,inputSchema:i.inputSchema,source:e,transport:n};i.description!==void 0&&(a.description=i.description),o.set(i.name,a);}this.tools.set(e,o);}removeSource(e){this.tools.delete(e);}getTools(){let e=[];for(let n of this.tools.values())for(let r of n.values())e.push(r);return e}getToolsByServer(e){let n=this.tools.get(e);return n?Array.from(n.values()):[]}getTool(e){for(let n of this.tools.values()){let r=n.get(e);if(r)return r}}getToolBySource(e,n){return this.tools.get(e)?.get(n)}};function ve(t){return "transport"in t&&t.transport==="stdio"}function Pe(t={}){ye(t);let e=null,n=new Map,r=new Map,o=[],i=null;return {async apply(s){if(s.setStore(b,true),i=new k,s.setStore(U,i),s.setStore(T,n),t.clients&&Object.keys(t.clients).length>0){let p=Object.entries(t.clients),l=new Map;for(let[m,g]of p)l.set(m,g);s.setStore(v,l);for(let[m,g]of p){if(ve(g))await a(s,m,g,i);else {let h=g;await d(s,m,h.url,i,h.auth),f(s,m,h.url,i,h.auth);}let c=ve(g)?"stdio":"http";s.emit(`plugin:mcp:client:${m}:registered`,{serverId:m,transport:c});}}e=new x(s,t),await e.start();},async teardown(s){for(let p of o)clearInterval(p);o.length=0;for(let[p,l]of r)try{await l.close();}catch(m){s.logger.error({err:m,serverId:p,operation:"close"},"Failed to close HTTP client");}r.clear();for(let[p,l]of n)try{await l.stop();}catch(m){s.logger.error({err:m,serverId:p,operation:"stop"},"Failed to stop stdio client");}if(n.clear(),e){try{await e.stop();}catch(p){s.logger.error({err:p,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}i=null;}};async function a(s,p,l,m){let g={serverId:p,command:l.command,args:l.args??[],maxRestarts:t.maxRestarts??5,restartDelayMs:t.restartDelayMs??1e3,restartBackoffMultiplier:t.restartBackoffMultiplier??2};l.env!==void 0&&(g.env=l.env),l.cwd!==void 0&&(g.cwd=l.cwd);let c=new F(g,s.logger,(h,y)=>{s.emit(h,y);},(h,y)=>{m.setToolsForSource(h,"stdio",y.map(w=>{let P={name:w.name,inputSchema:w.inputSchema};return w.description!==void 0&&(P.description=w.description),P}));});n.set(p,c);try{await c.start();}catch(h){s.logger.error({err:h,serverId:p,operation:"start"},"Failed to start stdio client"),s.emit(`plugin:mcp:client:${p}:error`,{serverId:p,error:h});}}async function u(s,p,l){let m=r.get(s);if(m)return m;let{Client:g}=await import('@modelcontextprotocol/sdk/client/index.js'),{StreamableHTTPClientTransport:c}=await import('@modelcontextprotocol/sdk/client/streamableHttp.js'),h=await B(l),y=h?{requestInit:{headers:h}}:void 0,w=new c(new URL(p),y),P=new g({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}});await P.connect(w);let ee=P;return r.set(s,ee),ee}async function d(s,p,l,m,g){try{let y=(await(await u(p,l,g)).listTools()).tools??[];m.setToolsForSource(p,"http",y.map(w=>{let P={name:w.name,inputSchema:w.inputSchema};return w.description!==void 0&&(P.description=w.description),P})),s.emit(`plugin:mcp:client:${p}:tools:listed`,{serverId:p,toolCount:y.length});}catch(c){r.delete(p),s.logger.warn({err:c,serverId:p,url:l,operation:"listTools"},"Failed to list tools from HTTP client");}}function f(s,p,l,m,g){let c=t.toolRefreshIntervalMs??6e4;if(c<=0)return;let h=setInterval(()=>{d(s,p,l,m,g);},c);o.push(h);}}var J=class{constructor(e){this._options=e;}async run(e){return this._options,e.logger&&e.logger.debug({adapter:"agent"},"Agent pass-through \u2014 implementation pending"),{output:e.body,steps:0}}};function dt(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`Agent adapter: modelId must be "providerId:modelName" (e.g. ollama:llama3). Got: "${t}"`)}var O=class{adapterId="routecraft.adapter.agent";runner;constructor(e){dt(e.modelId),this.runner=new J(e);}async send(e){return this.runner.run(e)}};function Me(t){return new O(t)}var K=new Map;async function W(){let t=[...K.entries()];K.clear(),t.length!==0&&await Promise.all(t.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function mt(t){return t.includes("/")?t:`Xenova/${t}`}var gt='The Hugging Face embedding provider requires "@huggingface/transformers". Install it with: pnpm add @huggingface/transformers';function ft(t,e){if(!(t instanceof Error))return false;let n=t.message??"";return (n.includes("ERR_MODULE_NOT_FOUND")||n.includes("Cannot find module")||n.includes("Cannot find package"))&&n.includes(e)}async function ht(t){let e=mt(t),n=K.get(e);if(n)return n.run;let r;try{r=(await import('@huggingface/transformers')).pipeline;}catch(u){throw ft(u,"@huggingface/transformers")?new Error(gt):u}let o=await r("feature-extraction",e,{dtype:"fp32"}),i=(u,d)=>o(u,{pooling:d?.pooling??"mean",normalize:d?.normalize??true}),a={run:i,dispose:typeof o.dispose=="function"?()=>Promise.resolve(o.dispose()):void 0};return K.set(e,a),i}function Re(t){if(t===null)return "null";if(typeof t!="object")return String(t);if(Array.isArray(t))return `array(${t.length})`;try{let e=JSON.stringify(t);return e.length>100?e.slice(0,100)+"...":e}catch{return "object"}}function yt(t){if(Array.isArray(t))return t;if(t instanceof Float32Array)return Array.from(t);if(t&&typeof t=="object"&&"data"in t){let e=t.data;if(Array.isArray(e))return e;if(e instanceof Float32Array)return Array.from(e);throw new Error(`Embedding output .data must be an Array or Float32Array; got ${typeof e}: ${Re(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof t}: ${Re(t)}`)}async function Se(t){let{config:e,modelName:n,text:r}=t;if(e.provider==="mock"){let i=[];for(let a=0;a<8;a++)i.push((r.length+a)%100/100);return i}if(e.provider==="huggingface"){let i=await(await ht(n))(r,{pooling:"mean",normalize:true}),a=i&&typeof i=="object"&&"data"in i?i.data:i;return yt(a)}throw e.provider==="ollama"||e.provider==="openai"?new Error(`Embedding provider "${e.provider}" is not yet implemented. Use huggingface for now.`):new Error(`Unknown embedding provider: ${e.provider}`)}var z=Symbol.for("routecraft.adapter.embedding.providers"),Y=Symbol.for("routecraft.adapter.embedding.options");function vt(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`Embedding adapter: model id must be "providerId:modelName" (e.g. huggingface:all-MiniLM-L6-v2). Got: "${t}"`);return {providerId:t.slice(0,e),modelName:t.slice(e+1)}}function Pt(t,e){if(!e)throw new Error(`Embedding adapter: model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so embedding providers can be read.`);let n=e.getStore(z);if(!n)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:r,modelName:o}=vt(t),i=n.get(r);if(!i)throw new Error(`Embedding provider "${r}" not found. Register it with embeddingPlugin({ providers: { "${r}": {} } }).`);return {config:i,modelName:o}}function Mt(t){return e=>{let n=t(e);return Array.isArray(n)?n.filter(Boolean).join(" | "):n}}var A=class{constructor(e,n={}){this.modelId=e;this.options=n;}adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(Y),...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=Pt(this.modelId,n),i=this.mergedOptions(n);if(!i.using)throw new Error("Embedding adapter: options.using(exchange) is required to build the string to embed.");let u=Mt(i.using)(e);return {embedding:await Se({config:r,modelName:o,text:u})}}};function Ee(t,e){return new A(t,e)}function Rt(t,e){return {...e,provider:t}}function be(t={providers:{}}){return {apply(e){let n=new Map;for(let[r,o]of Object.entries(t.providers))o!==void 0&&n.set(r,Rt(r,o));e.setStore(z,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(Y,t.defaultOptions);},async teardown(){await W();}}}
2
- exports.ADAPTER_LLM_OPTIONS=S;exports.ADAPTER_LLM_PROVIDERS=M;exports.ADAPTER_MCP_CLIENT_SERVERS=v;exports.AgentDestinationAdapter=O;exports.BRAND=te;exports.BRAND_MCP_ADAPTER=R;exports.EmbeddingDestinationAdapter=A;exports.LlmDestinationAdapter=E;exports.MCP_PLUGIN_REGISTERED=b;exports.MCP_STDIO_MANAGERS=T;exports.MCP_TOOL_REGISTRY=U;exports.McpHeadersKeys=N;exports.McpServer=x;exports.McpToolRegistry=k;exports.agent=Me;exports.defaultArgs=V;exports.disposeEmbeddingPipelineCache=W;exports.embedding=Ee;exports.embeddingPlugin=be;exports.isMcpAdapter=Ce;exports.jwt=fe;exports.llm=ae;exports.llmPlugin=pe;exports.mcp=ue;exports.mcpPlugin=Pe;exports.validateLlmPluginOptions=j;exports.validateWithSchema=we;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var routecraft=require('@routecraft/routecraft'),ai=require('ai'),async_hooks=require('async_hooks'),http=require('http');var ie={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function Ce(n,e){return typeof n=="object"&&n!==null&&n[e]===true}function xe(n){return Ce(n,ie.McpAdapter)}function D(n,e){throw new Error(`The ${e} LLM provider requires the "${n}" package. Install it with: pnpm add ${n}`)}function _(n,e){if(!(n instanceof Error))return false;let t=n.message??"";return (t.includes("ERR_MODULE_NOT_FOUND")||t.includes("Cannot find module")||t.includes("Cannot find package"))&&t.includes(e)}var Ae={ollama:{baseURL:"http://localhost:11434/api"}};function U(n){return {...n.inputTokens!==void 0&&{inputTokens:n.inputTokens},...n.outputTokens!==void 0&&{outputTokens:n.outputTokens},...n.totalTokens!==void 0&&{totalTokens:n.totalTokens}}}function j(n){try{if("output"in n&&n.output!==void 0)return n.output}catch{}}function se(n,e,t){if(n===null||typeof n!="object")throw new Error(`[${e}] Invalid model: expected an object, got ${typeof n}. Model id: ${t}`);let r=n;if(typeof r.doGenerate!="function")throw new Error(`[${e}] Invalid model: missing or invalid doGenerate method. Model id: ${t}. Ensure the provider returns an AI SDK-compatible language model.`);if(typeof r.doStream!="function")throw new Error(`[${e}] Invalid model: missing or invalid doStream method. Model id: ${t}. Ensure the provider returns an AI SDK-compatible language model.`)}async function ae(n){let{config:e,modelId:t,options:r,systemPrompt:o,userPrompt:i,output:s}=n;switch(e.provider){case "openai":return ke(e,t,r,o,i,s);case "anthropic":return Oe(e,t,r,o,i,s);case "gemini":return Le(e,t,r,o,i,s);case "openrouter":return Ie(e,t,r,o,i,s);case "ollama":return De(e,t,r,o,i,s);default:{let a=e;throw new Error(`LLM provider not implemented: ${a.provider}`)}}}async function ke(n,e,t,r,o,i){let s;try{s=(await import('@ai-sdk/openai')).createOpenAI;}catch(g){throw _(g,"@ai-sdk/openai")&&D("@ai-sdk/openai","OpenAI"),g}let{generateText:a}=await import('ai'),c={apiKey:n.apiKey};n.baseURL!==void 0&&(c.baseURL=n.baseURL);let d={model:s(c)(e),prompt:o,...t.maxTokens!==void 0&&{maxOutputTokens:t.maxTokens},temperature:t.temperature};r&&(d.system=r),t.topP!==void 0&&(d.topP=t.topP),t.frequencyPenalty!==void 0&&(d.frequencyPenalty=t.frequencyPenalty),t.presencePenalty!==void 0&&(d.presencePenalty=t.presencePenalty);let l=i!==void 0?{...d,output:i}:d,u=await a(l),m={text:u.text??"",raw:u};u.usage&&(m.usage=U(u.usage));let h=j(u);return h!==void 0&&(m.output=h),m}async function Oe(n,e,t,r,o,i){let s;try{s=(await import('@ai-sdk/anthropic')).createAnthropic;}catch(h){throw _(h,"@ai-sdk/anthropic")&&D("@ai-sdk/anthropic","Anthropic"),h}let{generateText:a}=await import('ai'),p={model:s({apiKey:n.apiKey})(e),prompt:o,...t.maxTokens!==void 0&&{maxOutputTokens:t.maxTokens},temperature:t.temperature};r&&(p.system=r),t.topP!==void 0&&(p.topP=t.topP),t.frequencyPenalty!==void 0&&(p.frequencyPenalty=t.frequencyPenalty),t.presencePenalty!==void 0&&(p.presencePenalty=t.presencePenalty);let d=i!==void 0?{...p,output:i}:p,l=await a(d),u={text:l.text??"",raw:l};l.usage&&(u.usage=U(l.usage));let m=j(l);return m!==void 0&&(u.output=m),u}async function Le(n,e,t,r,o,i){let s;try{s=(await import('@ai-sdk/google')).createGoogleGenerativeAI;}catch(h){throw _(h,"@ai-sdk/google")&&D("@ai-sdk/google","Gemini"),h}let{generateText:a}=await import('ai'),p={model:s({apiKey:n.apiKey})(e),prompt:o,...t.maxTokens!==void 0&&{maxOutputTokens:t.maxTokens},temperature:t.temperature};r&&(p.system=r),t.topP!==void 0&&(p.topP=t.topP),t.frequencyPenalty!==void 0&&(p.frequencyPenalty=t.frequencyPenalty),t.presencePenalty!==void 0&&(p.presencePenalty=t.presencePenalty);let d=i!==void 0?{...p,output:i}:p,l=await a(d),u={text:l.text??"",raw:l};l.usage&&(u.usage=U(l.usage));let m=j(l);return m!==void 0&&(u.output=m),u}async function Ie(n,e,t,r,o,i){let s;try{s=(await import('@openrouter/ai-sdk-provider')).createOpenRouter;}catch(y){throw _(y,"@openrouter/ai-sdk-provider")&&D("@openrouter/ai-sdk-provider","OpenRouter"),y}let{generateText:a}=await import('ai'),c=s({apiKey:n.apiKey}),f=n.modelId??e,p=c.chat(f);se(p,"OpenRouter",f);let l={model:p,prompt:o,...t.maxTokens!==void 0&&{maxOutputTokens:t.maxTokens},temperature:t.temperature};r&&(l.system=r),t.topP!==void 0&&(l.topP=t.topP),t.frequencyPenalty!==void 0&&(l.frequencyPenalty=t.frequencyPenalty),t.presencePenalty!==void 0&&(l.presencePenalty=t.presencePenalty);let u=i!==void 0?{...l,output:i}:l,m=await a(u),h={text:m.text??"",raw:m};m.usage&&(h.usage=U(m.usage));let g=j(m);return g!==void 0&&(h.output=g),h}async function De(n,e,t,r,o,i){let s;try{s=(await import('ollama-ai-provider-v2')).createOllama;}catch(y){throw _(y,"ollama-ai-provider-v2")&&D("ollama-ai-provider-v2","Ollama"),y}let{generateText:a}=await import('ai'),c=s({baseURL:n.baseURL??Ae.ollama.baseURL}),f=n.modelId??e,p=c(f);se(p,"Ollama",f);let l={model:p,prompt:o,...t.maxTokens!==void 0&&{maxOutputTokens:t.maxTokens},temperature:t.temperature};r&&(l.system=r),t.topP!==void 0&&(l.topP=t.topP),t.frequencyPenalty!==void 0&&(l.frequencyPenalty=t.frequencyPenalty),t.presencePenalty!==void 0&&(l.presencePenalty=t.presencePenalty);let u=i!==void 0?{...l,output:i}:l,m=await a(u),h={text:m.text??"",raw:m};m.usage&&(h.usage=U(m.usage));let g=j(m);return g!==void 0&&(h.output=g),h}function le(n){let e=n["~standard"];if(!e?.validate)throw new Error("LLM outputSchema must be a StandardSchemaV1 with ~standard.validate");let t=e.jsonSchema?.output?.({target:"draft-2020-12"})??e.jsonSchema?.input?.({target:"draft-2020-12"});if(!t||typeof t!="object")throw new Error("LLM outputSchema must expose ~standard.jsonSchema.output or .input for provider structured output");function r(i){let s;try{s=e.validate(i);}catch(c){return {success:false,error:c instanceof Error?c:new Error(String(c))}}return s instanceof Promise?{success:false,error:new Error("Async output schema is not supported for LLM structured output")}:s.issues!=null&&(Array.isArray(s.issues)?s.issues.length>0:typeof s.issues=="object"&&s.issues!==null?Object.keys(s.issues).length>0:!!s.issues)?{success:false,error:new Error(routecraft.formatSchemaIssues(s.issues))}:{success:true,value:s.value}}let o=ai.jsonSchema(t,{validate:r});return ai.Output.object({schema:o})}var S=Symbol.for("routecraft.adapter.llm.providers"),T=Symbol.for("routecraft.adapter.llm.options");async function He(n,e){let t;try{t=JSON.parse(n);}catch{return}let r=e["~standard"];if(!r?.validate)return;let o=r.validate(t);if(o instanceof Promise&&(o=await o),!(o&&typeof o=="object"&&"issues"in o&&o.issues))return o&&typeof o=="object"&&"value"in o?o.value:void 0}var qe=0,$e=1024;function pe(n,e){return n===void 0||n===""?"":typeof n=="function"?n(e):n}function Ve(n){let e=n.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}function ce(n){let e=n.indexOf(":");if(e<1||e===n.length-1)throw new Error(`LLM adapter: model id must be "providerId:modelName" (e.g. ollama:lfm2.5-thinking). Got: "${n}"`);return {providerId:n.slice(0,e),modelName:n.slice(e+1)}}function Ge(n,e){if(!e)throw new Error(`LLM adapter: model id "${n}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${S.description}" can be read.`);let t=e.getStore(S);if(!t)throw new Error('LLM provider not found: no providers registered. Add llmPlugin({ providers: { ollama: { provider: "ollama" }, ... } }) to your config.');let{providerId:r,modelName:o}=ce(n),i=t.get(r);if(!i)throw new Error(`LLM provider "${r}" not found. Register it with llmPlugin({ providers: { "${r}": { provider, apiKey?, baseURL? } } }).`);return {config:i,modelName:o}}var E=class{constructor(e,t={}){this.modelId=e;this.options=t;}modelId;adapterId="routecraft.adapter.llm";options;mergedOptions(e){let t=e.getStore(T);return {temperature:qe,maxTokens:$e,...t,...this.options}}async send(e){let t=routecraft.getExchangeContext(e),{config:r,modelName:o}=Ge(this.modelId,t),i=this.mergedOptions(t),s=pe(i.systemPrompt,e),a=pe(i.userPrompt,e)||Ve(e),c={temperature:i.temperature,maxTokens:i.maxTokens};i.topP!==void 0&&(c.topP=i.topP),i.frequencyPenalty!==void 0&&(c.frequencyPenalty=i.frequencyPenalty),i.presencePenalty!==void 0&&(c.presencePenalty=i.presencePenalty);let f=i.outputSchema!==void 0?le(i.outputSchema):void 0,p=await ae({config:r,modelId:o,options:c,systemPrompt:s,userPrompt:a,output:f});if(p.output===void 0&&p.text&&i.outputSchema!==void 0){let d=await He(p.text,i.outputSchema);d!==void 0&&(p.output=d);}return p}getMetadata(e){let t=e,{providerId:r}=ce(this.modelId),o={model:this.modelId,provider:r};return t.usage&&(t.usage.inputTokens!==void 0&&(o.inputTokens=t.usage.inputTokens),t.usage.outputTokens!==void 0&&(o.outputTokens=t.usage.outputTokens)),o}};function ue(n,e){return new E(n,e)}var de=["openai","anthropic","openrouter","ollama","gemini"];function Fe(n){return de.includes(n)}function q(n){if(!n||typeof n!="object")throw new TypeError("llmPlugin: options must be an object");if(!n.providers||typeof n.providers!="object")throw new TypeError("llmPlugin: options.providers must be an object (record of provider id \u2192 options)");for(let[e,t]of Object.entries(n.providers))if(t!==void 0){if(!t||typeof t!="object")throw new TypeError(`llmPlugin: providers["${e}"] must be an object`);if(!Fe(e))throw new TypeError(`llmPlugin: providers["${e}"] is not a supported provider. Supported: ${de.join(", ")}`);switch(e){case "openai":case "anthropic":case "openrouter":case "gemini":if(typeof t.apiKey!="string"||!t.apiKey.trim())throw new TypeError(`llmPlugin: providers["${e}"].apiKey is required`);break;case "ollama":if(t.baseURL!==void 0&&typeof t.baseURL!="string")throw new TypeError(`llmPlugin: providers["${e}"].baseURL must be a string when provided`);if(t.modelId!==void 0&&(typeof t.modelId!="string"||!t.modelId.trim()))throw new TypeError(`llmPlugin: providers["${e}"].modelId must be a non-empty string when provided`);break}}if(n.defaultOptions!==void 0&&(typeof n.defaultOptions!="object"||n.defaultOptions===null))throw new TypeError("llmPlugin: defaultOptions must be an object when provided")}var Be=["openai","anthropic","openrouter","ollama","gemini"];function Ke(n,e){return {provider:n,...e}}function me(n={providers:{}}){return q(n),{apply(e){let t=new Map;for(let r of Be){let o=n.providers[r];o!==void 0&&t.set(r,Ke(r,o));}e.setStore(S,t),n.defaultOptions&&Object.keys(n.defaultOptions).length>0&&e.setStore(T,n.defaultOptions);}}}var b=Symbol.for("routecraft.mcp.plugin.registered"),v=Symbol.for("routecraft.mcp.client.servers"),$=Symbol.for("routecraft.mcp.tool.registry"),C=Symbol.for("routecraft.mcp.stdio.managers"),V=(l=>(l.TOOL="routecraft.mcp.tool",l.SESSION="routecraft.mcp.session",l.AUTH_SUBJECT="routecraft.auth.subject",l.AUTH_SCHEME="routecraft.auth.scheme",l.AUTH_KIND="routecraft.auth.kind",l.AUTH_ROLES="routecraft.auth.roles",l.AUTH_SCOPES="routecraft.auth.scopes",l.AUTH_EMAIL="routecraft.auth.email",l.AUTH_NAME="routecraft.auth.name",l.AUTH_ISSUER="routecraft.auth.issuer",l.AUTH_AUDIENCE="routecraft.auth.audience",l.AUTH_CLIENT_ID="routecraft.auth.client_id",l))(V||{});function G(n){return "provider"in n&&n.provider==="oauth"}var R=Symbol.for("routecraft.mcp.adapter");var B=class{adapterId="routecraft.adapter.mcp";endpoint;options;constructor(e,t){if(this[R]=true,typeof e!="string")throw routecraft.rcError("RC5003",void 0,{message:"Dynamic endpoints cannot be used as source",suggestion:"Use a static string endpoint for source: .from(mcp('endpoint', options))."});if("url"in t||"serverId"in t)throw routecraft.rcError("RC5003",void 0,{message:"mcp() with url or serverId must be used as destination: .to(mcp({ url, tool }))",suggestion:"Use .to(mcp({ url: '...', tool: '...' })) to call a remote MCP server."});if("args"in t&&t.args!==void 0&&!("description"in t))throw routecraft.rcError("RC5003",void 0,{message:"mcp(endpoint, { args }) is for client usage with a 'server:tool' target, not for defining a source",suggestion:"Use .to(mcp('server:tool', { args })) to call a remote tool, or .from(mcp('endpoint', { description: '...' })) to define a source."});if(!("description"in t)||typeof t.description!="string")throw routecraft.rcError("RC5003",void 0,{message:"mcp(endpoint, options) as source requires options.description",suggestion:"Use .from(mcp('endpoint', { description: '...' })) to define a source."});this.endpoint=e,this.options=t;}async subscribe(e,t,r,o){if(e.getStore(b)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");return routecraft.direct(this.endpoint,this.options).subscribe(e,t,r,o)}};function K(n){let e=n?.content;if(!Array.isArray(e)||e.length===0)return n;if(e.length===1){let t=e[0];if(t.type==="text"&&typeof t.text=="string")return t.text;if(typeof t.data=="string")return t.data}return e}var ge=new WeakMap;async function ze(n){if(typeof n=="function")return n();if(Array.isArray(n)){if(n.length===0)throw new Error("McpClientAuthOptions.token array must not be empty");let e=(ge.get(n)??0)%n.length;return ge.set(n,e+1),n[e]}return n}async function W(n){if(!n)return;let e={},t=n.headers??{},r=Object.entries(t).find(([o])=>o.toLowerCase()==="authorization")?.[1];if(r)e.Authorization=r;else if(n.token!==void 0){let o=await ze(n.token);if(o.length===0)throw new Error("McpClientAuthOptions.token must be a non-empty string when provided");e.Authorization=`Bearer ${o}`;}for(let[o,i]of Object.entries(t))o.toLowerCase()!=="authorization"&&(e[o]=i);return Object.keys(e).length>0?e:void 0}function Ye(n){let e=n.trim().toLowerCase();if(!e.startsWith("http://")&&!e.startsWith("https://"))throw new Error(`MCP client: url must be HTTP or HTTPS. Stdio is not supported in routes; register stdio clients via mcpPlugin({ clients: { name: { command, args } } }). Got: "${n.slice(0,50)}${n.length>50?"...":""}"`)}function Xe(n,e){return !n.serverId||!e?void 0:e.getStore(v)?.get(n.serverId)}function Qe(n,e){if(n.url)return Ye(n.url),{url:n.url,auth:n.auth};if(n.serverId&&!e)throw new Error(`MCP client: serverId "${n.serverId}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${String(v)}" can be read.`);if(n.serverId&&e){let t=Xe(n,e);if(!t)throw new Error(`MCP client: serverId "${n.serverId}" not found in context store. Register it with context store key "${String(v)}".`);let r=typeof t=="string"?t:t.url,o=n.auth??(typeof t=="object"&&"auth"in t?t.auth:void 0);return {url:r,auth:o}}throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.")}var z=n=>typeof n.body=="object"&&n.body!==null?n.body:{input:n.body},N=class{constructor(e){this.options=e;if(this[R]=true,!e.url&&!e.serverId)throw new Error("MCP client: either url or serverId must be provided in McpClientOptions.");if(e.url&&e.serverId)throw new Error("MCP client: cannot provide both url and serverId. Use either url for direct HTTP or serverId for registered servers.")}options;adapterId="routecraft.adapter.mcp";async send(e){let t=routecraft.getExchangeContext(e),r=this.options.tool??(typeof e.body=="object"&&e.body!==null&&"tool"in e.body&&typeof e.body.tool=="string"?e.body.tool:void 0);if(!r)throw new Error("MCP client: tool name required. Set options.tool or exchange.body.tool.");let i=(this.options.args??z)(e);if(this.options.serverId&&t){let p=t.getStore(C)?.get(this.options.serverId);if(p){let u=await p.callTool(r,i);return u&&typeof u=="object"&&(u.metadata={toolName:r,transport:"stdio",serverId:this.options.serverId}),u}let l=t.getStore(v)?.get(this.options.serverId);if(l&&typeof l=="object"&&"transport"in l&&l.transport==="stdio")throw new Error(`MCP client: stdio server "${this.options.serverId}" is not running. Ensure mcpPlugin is applied and the stdio client started successfully.`)}let{url:s,auth:a}=Qe(this.options,t),c=await this.callRemoteTool(s,r,i,a);return c&&typeof c=="object"&&(c.metadata={toolName:r,url:s,transport:"http",...this.options.serverId?{serverId:this.options.serverId}:{}}),c}getMetadata(e){return e&&typeof e=="object"&&"metadata"in e?e.metadata:{toolName:"unknown",transport:"unknown"}}async callRemoteTool(e,t,r,o){let i,s;try{i=await import('@modelcontextprotocol/sdk/client/index.js'),s=await import('@modelcontextprotocol/sdk/client/streamableHttp.js');}catch{throw new Error('MCP client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk')}let a=i.Client,c=s.StreamableHTTPClientTransport,f=new URL(e),p=await W(o),d=p?{requestInit:{headers:p}}:void 0,l=new c(f,d),u={name:"routecraft-mcp-client",version:"1.0.0"},m=new a(u,{capabilities:{}});try{await m.connect.call(m,l);let y=await m.callTool.call(m,{name:t,arguments:r});return K(y)}finally{let h=m,g=h.close??h.disconnect;if(typeof g=="function")try{await Promise.resolve(g.call(m));}catch{}let y=l,P=y.close??y.destroy;if(typeof P=="function")try{await Promise.resolve(P.call(l));}catch{}}}};function H(n,e){if(typeof n=="object"&&n!==null&&("url"in n||"serverId"in n)){let o=n;if(typeof o.auth?.token=="string"&&o.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(o.auth?.token)){if(o.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let i=0;i<o.auth.token.length;i++){let s=o.auth.token[i];if(typeof s!="string"||s.trim().length===0)throw new TypeError(`mcp(): auth.token[${i}] must be a non-empty string`)}}return routecraft.tagAdapter(new N(o),H,routecraft.factoryArgs(n,e))}let t=e===void 0||typeof e=="object"&&e!==null&&!("description"in e);if(typeof n=="string"&&n.includes(":")&&t){let o=n.indexOf(":"),i=n.slice(0,o),s=n.slice(o+1),a={serverId:i,tool:s};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(a.args=e.args),routecraft.tagAdapter(new N(a),H,routecraft.factoryArgs(n,e))}let r=n;if(e!==void 0)return routecraft.tagAdapter(new B(r,e),H,routecraft.factoryArgs(n,e));throw routecraft.rcError("RC5003",void 0,{message:"mcp() with only an endpoint is not supported. Use direct('endpoint') for in-process. For MCP server use .from(mcp('endpoint', { description: '...' })); for client use .to(mcp({ url, tool })) or .to(mcp('server:tool', { args })).",suggestion:"Use .from(mcp('endpoint', { description: '...' })) or .to(mcp({ url, tool })) or direct('endpoint')."})}function et(n){if(typeof n=="function")return async t=>n(t);let e=n;return async t=>t===e.client_id?e:void 0}function tt(n){if(!n)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");return typeof n=="function"?async e=>n(e):async e=>n.validator(e)}function fe(n){if(new URL(n.resourceIssuerUrl.toString()).protocol!=="https:"&&process.env.NODE_ENV==="production")throw new TypeError("oauth: resourceIssuerUrl must use HTTPS in production");let t=tt(n.verify),r=et(n.client);return {provider:"oauth",resourceIssuerUrl:n.resourceIssuerUrl,endpoints:n.endpoints,verifyAccessToken:t,getClient:r,...n.baseUrl!==void 0&&{baseUrl:n.baseUrl},...n.scopesSupported!==void 0&&{scopesSupported:n.scopesSupported},...n.requiredScopes!==void 0&&{requiredScopes:n.requiredScopes},...n.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:n.serviceDocumentationUrl},...n.resourceName!==void 0&&{resourceName:n.resourceName}}}var ye=new async_hooks.AsyncLocalStorage,re='MCP server requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',A=class{context;options;server=null;transport=null;httpServer=null;httpSessions=new Map;running=false;toolsListLogged=false;constructor(e,t={}){this.context=e,this.options={name:"routecraft",version:"1.0.0",transport:"stdio",port:3001,host:"localhost",...t};}async start(){if(this.running){this.context.logger.warn({},"MCP server already running");return}try{let e=this.options.transport;e==="http"?await this.startHttp():await this.startStdio(),this.running=!0,this.context.logger.info({name:this.options.name,version:this.options.version,transport:e},"MCP server started"),this.logExposedToolsOnce();}catch(e){let t=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Failed to start MCP server";throw this.context.logger.error({err:e},t),e}}async startStdio(){let e,t;try{e=(await import('@modelcontextprotocol/sdk/server/index.js')).Server,t=(await import('@modelcontextprotocol/sdk/server/stdio.js')).StdioServerTransport;}catch{throw new Error(re)}this.server=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}}),await this.setupRequestHandlers(),this.transport=new t,await this.server.connect(this.transport);}async startHttp(){this.options.auth&&G(this.options.auth)?await this.startHttpWithOAuth(this.options.auth):await this.startHttpWithValidator();}async importSdkHttp(){let e;try{e=(await import('@modelcontextprotocol/sdk/server/index.js')).Server;}catch{throw new Error(re)}let r=(await import('@modelcontextprotocol/sdk/server/streamableHttp.js').catch(()=>null))?.StreamableHTTPServerTransport;if(!r)throw new Error("StreamableHTTPServerTransport not found in MCP SDK - ensure @modelcontextprotocol/sdk v1.26.0+ is installed");return {ServerCtor:e,TransportClass:r}}async createSession(e,t){let r=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}});await this.setupRequestHandlersOn(r);let o=new t({sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:f=>{this.httpSessions.set(f,{server:r,transport:o}),this.context.logger.debug({sessionId:f},"MCP session created"),this.context.emit("plugin:mcp:session:created",{sessionId:f});},enableJsonResponse:true});await r.connect(o);let s=o,a=s.onclose;s.onclose=()=>{let f=o.sessionId;f&&(this.httpSessions.delete(f),this.context.logger.debug({sessionId:f},"MCP session closed"),this.context.emit("plugin:mcp:session:closed",{sessionId:f})),a?.();};let c=o.handleRequest;if(typeof c!="function")throw new Error("StreamableHTTPServerTransport.handleRequest not found - SDK may have changed");return {transport:o,handleRequest:c.bind(o)}}async handleMcpRequest(e,t,r,o){let i=e.headers["mcp-session-id"],s=a=>ye.run(r,a);try{if(i&&this.httpSessions.has(i)){let a=this.httpSessions.get(i),c=a.transport.handleRequest;await s(()=>c.call(a.transport,e,t));}else if(!i||e.method==="POST"){let{handleRequest:a}=await o();await s(()=>a(e,t));}else t.writeHead(404,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Session not found"}));}catch(a){let c=routecraft.isRoutecraftError(a)?a.meta.message:a instanceof Error?a.message:"MCP HTTP request error";this.context.logger.error({err:a},c),t.headersSent||(t.writeHead(500,{"Content-Type":"application/json"}),t.end(JSON.stringify({error:"Internal Server Error"})));}}async startHttpWithValidator(){let{ServerCtor:e,TransportClass:t}=await this.importSdkHttp(),r=this.options.port,o=this.options.host,i=()=>this.createSession(e,t);this.httpServer=http.createServer(async(s,a)=>{let c=s.url?.split("?")[0]??"";if(c!=="/mcp"&&c!=="/mcp/"){a.writeHead(404,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Not Found",path:c}));return}let f;if(this.options.auth){let p=await this.validateAuth(s);if(!p){a.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":'Bearer realm="mcp"'}),a.end(JSON.stringify({error:"Unauthorized"}));return}f=p;}await this.handleMcpRequest(s,a,f,i);}),await this.listenHttp(r,o);}async startHttpWithOAuth(e){let{ServerCtor:t,TransportClass:r}=await this.importSdkHttp(),o,i,s,a;try{let g=await import('express');o=g.default??g;}catch{throw new Error('OAuth auth requires "express" (optional peer dependency of @routecraft/ai). Install it with: pnpm add express')}try{i=(await import('@modelcontextprotocol/sdk/server/auth/router.js')).mcpAuthRouter,s=(await import('@modelcontextprotocol/sdk/server/auth/middleware/bearerAuth.js')).requireBearerAuth,a=(await import('@modelcontextprotocol/sdk/server/auth/providers/proxyProvider.js')).ProxyOAuthServerProvider;}catch{throw new Error("OAuth auth requires @modelcontextprotocol/sdk v1.27.0+ with OAuth support. Install it with: pnpm add @modelcontextprotocol/sdk")}let c=async g=>{let y;try{y=await e.verifyAccessToken(g);}catch(w){let M={reason:w instanceof Error?w.message:"invalid_token",scheme:"bearer",source:"mcp",path:"oauth"};throw this.context.logger.warn({err:w,...M},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",M),w}if(y.expiresAt===void 0){let w={reason:"missing_expires_at",scheme:"bearer",source:"mcp",path:"oauth"};throw this.context.logger.warn(w,"Auth rejected: OAuth principal is missing expiresAt"),this.context.emit("auth:rejected",w),new Error("oauth: verifyAccessToken must return a principal with expiresAt (required by MCP SDK bearer middleware)")}return y.clientId||this.context.logger.debug({subject:y.subject},"oauth: principal missing clientId; using subject as fallback for AuthInfo.clientId"),{token:g,clientId:y.clientId??y.subject,scopes:y.scopes??[],expiresAt:y.expiresAt,extra:{principal:y}}},f=new a({endpoints:{authorizationUrl:e.endpoints.authorizationUrl,tokenUrl:e.endpoints.tokenUrl,revocationUrl:e.endpoints.revocationUrl,registrationUrl:e.endpoints.registrationUrl},verifyAccessToken:c,getClient:e.getClient}),p=this.options.port,d=this.options.host,l=o(),u={provider:f,issuerUrl:new URL(e.resourceIssuerUrl.toString())};e.baseUrl&&(u.baseUrl=new URL(e.baseUrl.toString())),e.scopesSupported&&(u.scopesSupported=e.scopesSupported),e.serviceDocumentationUrl&&(u.serviceDocumentationUrl=new URL(e.serviceDocumentationUrl.toString())),e.resourceName&&(u.resourceName=e.resourceName),l.use(i(u));let m={verifier:f};e.requiredScopes&&(m.requiredScopes=e.requiredScopes),l.use("/mcp",s(m));let h=()=>this.createSession(t,r);l.all("/mcp",async(g,y)=>{let P=g,w=y,I=g.auth,M=this.authInfoToPrincipal(I);if(M){let oe={subject:M.subject,scheme:M.scheme,source:"mcp"};this.context.logger.info(oe,"Auth succeeded"),this.context.emit("auth:success",oe);}await this.handleMcpRequest(P,w,M,h);}),this.httpServer=http.createServer(l),await this.listenHttp(p,d);}async listenHttp(e,t){await new Promise((i,s)=>{this.httpServer.listen(e,t,()=>i()),this.httpServer.on("error",a=>{let c=routecraft.isRoutecraftError(a)?a.meta.message:a instanceof Error?a.message:"MCP HTTP server listen failed";this.context.logger.error({err:a},c),s(a);});});let r=this.getHttpPort()??e,o={host:t,port:r,path:"/mcp"};this.context.logger.info(o,"MCP HTTP server listening"),this.context.emit("plugin:mcp:server:listening",o);}authInfoToPrincipal(e){if(!e)return;let t=e.extra?.principal;if(t)return t;let r={kind:"oauth",scheme:"bearer",subject:e.clientId,clientId:e.clientId,scopes:e.scopes};return e.expiresAt!==void 0&&(r.expiresAt=e.expiresAt),r}getHttpPort(){let e=this.httpServer?.address();if(e&&typeof e=="object"&&"port"in e)return e.port}async validateAuth(e){let t=this.options.auth;if(!t||!("validator"in t))return null;let r=e.headers.authorization;if(!r||Array.isArray(r)){let s={reason:"missing_header",scheme:"bearer",source:"mcp"};return this.context.logger.warn(s,"Auth rejected: missing or malformed Authorization header"),this.context.emit("auth:rejected",s),null}let o=/^bearer\s+(.+)$/i.exec(r);if(!o){let s={reason:"unsupported_scheme",scheme:"bearer",source:"mcp"};return this.context.logger.warn(s,"Auth rejected: unsupported authorization scheme"),this.context.emit("auth:rejected",s),null}let i=o[1];try{let s=await t.validator(i),a={subject:s.subject,scheme:s.scheme,source:"mcp"};return this.context.logger.info(a,"Auth succeeded"),this.context.emit("auth:success",a),s}catch(s){let c={reason:s instanceof Error?s.message:"invalid_token",scheme:"bearer",source:"mcp"};return this.context.logger.warn({err:s,...c},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",c),null}}async setupRequestHandlers(){await this.setupRequestHandlersOn(this.server);}async setupRequestHandlersOn(e){let t;try{t=await import('@modelcontextprotocol/sdk/types.js');}catch{throw new Error(re)}let r=t,o=r.ListToolsRequestSchema,i=r.CallToolRequestSchema;if(!o||!i)throw new Error("MCP SDK types missing ListToolsRequestSchema or CallToolRequestSchema - ensure @modelcontextprotocol/sdk is installed");let s=e;s.setRequestHandler(o,async()=>{let a=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:a}}),s.setRequestHandler(i,async a=>{let f=a.params;return await this.handleToolCall(f.name||"",f.arguments||{})});}async stop(){if(this.running)try{if(this.httpServer){for(let[,e]of this.httpSessions){let t=e.transport;typeof t.close=="function"&&await t.close();}this.httpSessions.clear(),await new Promise(e=>{this.httpServer.close(()=>e());}),this.httpServer=null;}if(this.transport){let e=this.transport;typeof e.close=="function"&&await e.close();}this.running=!1,this.context.logger.info({},"MCP server stopped");}catch(e){let t=routecraft.isRoutecraftError(e)?e.meta.message:e instanceof Error?e.message:"Error stopping MCP server";this.context.logger.error({err:e},t);}}logExposedToolsOnce(){if(this.toolsListLogged)return;let e=this.getAvailableTools();if(e.length===0)return;let t=e.map(o=>o.name),r={tools:t,count:t.length};this.context.logger.info(r,"Exposing MCP tools"),this.context.emit("plugin:mcp:server:tools:exposed",r),this.toolsListLogged=true;}getAvailableTools(){let e=this.context.getStore(routecraft.ADAPTER_DIRECT_REGISTRY);if(!e)return [];let t=Array.from(e.values()).filter(o=>o.description!==void 0),r=this.options.tools;if(r)if(Array.isArray(r)){let o=new Set(r);t=t.filter(i=>o.has(i.endpoint));}else typeof r=="function"&&(t=t.filter(r));return t.map(o=>this.metadataToMcpTool(o))}metadataToMcpTool(e){let t={name:e.endpoint,description:e.description||"",inputSchema:this.schemaToJsonSchema(e.schema)};return e.annotations!==void 0&&(t.annotations=e.annotations),t}schemaToJsonSchema(e){if(!e||typeof e!="object")return {type:"object"};let t=e["~standard"];if(t?.jsonSchema?.input)try{let r=t.jsonSchema.input({target:"draft-2020-12"});return typeof r=="object"&&r!==null?r:{type:"object"}}catch(r){return this.context.logger.debug(r,"Standard JSON Schema conversion failed"),{type:"object"}}return "~standard"in e?{type:"object",additionalProperties:true}:{type:"object"}}async handleToolCall(e,t){try{let r=this.context.getStore(routecraft.ADAPTER_DIRECT_STORE);if(!r){let l=new Error("No direct channels available");return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:l.message}),{isError:!0,content:[{type:"text",text:"Error: No direct channels available"}]}}let o=r.get(e);if(!o){let l=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:l.message}),{isError:!0,content:[{type:"text",text:`Error: Tool not found: ${e}`}]}}let i=typeof t=="string"?(()=>{try{return JSON.parse(t)||{}}catch{return {input:t}}})():t&&typeof t=="object"?t:{};this.context.logger.debug({bodyType:typeof i,body:i},"MCP tool call exchange body");let s=ye.getStore(),a={"routecraft.mcp.tool":e,"routecraft.mcp.session":`mcp-${Date.now()}`};s&&(a["routecraft.auth.subject"]=s.subject,a["routecraft.auth.scheme"]=s.scheme,a["routecraft.auth.kind"]=s.kind,s.name&&(a["routecraft.auth.name"]=s.name),s.email&&(a["routecraft.auth.email"]=s.email),s.roles&&(a["routecraft.auth.roles"]=s.roles),s.scopes&&(a["routecraft.auth.scopes"]=s.scopes),s.issuer&&(a["routecraft.auth.issuer"]=s.issuer),s.audience&&(a["routecraft.auth.audience"]=s.audience),s.clientId&&(a["routecraft.auth.client_id"]=s.clientId));let c=new routecraft.DefaultExchange(this.context,{body:i,headers:a});this.context.emit("plugin:mcp:tool:called",{tool:e,args:t});let p=await o.send(e,c),d=typeof p.body=="string"?p.body:JSON.stringify(p.body);return this.context.emit("plugin:mcp:tool:completed",{tool:e}),{content:[{type:"text",text:d}]}}catch(r){let o=routecraft.isRoutecraftError(r)?r.meta.message:r instanceof Error?r.message:String(r);this.context.logger.error({tool:e,err:r},o),this.context.emit("plugin:mcp:tool:failed",{tool:e,error:o});let i=o;if(routecraft.isRoutecraftError(r)){let s=r.cause;s?.message&&(i=`${o}: ${s.message}`);}return {content:[{type:"text",text:`Error: ${i}`}],isError:true}}}};function we(n){if(n.transport==="http"){if(n.port!==void 0){if(typeof n.port!="number")throw new TypeError("mcpPlugin: when transport is 'http', port must be a number");if(n.port<0||n.port>65535)throw new RangeError("mcpPlugin: port must be between 0 and 65535 when transport is 'http'")}if(n.host!==void 0&&typeof n.host!="string")throw new TypeError("mcpPlugin: when provided, host must be a string")}if(n.auth!==void 0)if("provider"in n.auth){if(n.auth.provider!=="oauth")throw new TypeError('mcpPlugin: auth.provider must be "oauth". Use the oauth() helper.')}else if("validator"in n.auth){if(typeof n.auth.validator!="function")throw new TypeError("mcpPlugin: auth.validator must be a function that returns a Principal (throw to reject)")}else throw new TypeError("mcpPlugin: auth must have either a 'validator' function or 'provider' set to 'oauth'. Use jwt(), jwks(), oauth(), or a custom { validator } object.");if(n.clients){for(let[e,t]of Object.entries(n.clients))if(typeof t=="object"&&t!==null&&"transport"in t&&t.transport==="stdio"&&(!t.command||typeof t.command!="string"))throw new TypeError(`mcpPlugin: stdio client "${e}" must have a non-empty command string`)}if(n.maxRestarts!==void 0&&(typeof n.maxRestarts!="number"||!Number.isInteger(n.maxRestarts)||n.maxRestarts<0))throw new TypeError("mcpPlugin: maxRestarts must be a non-negative integer");if(n.restartDelayMs!==void 0&&(typeof n.restartDelayMs!="number"||n.restartDelayMs<=0))throw new TypeError("mcpPlugin: restartDelayMs must be a positive number");if(n.restartBackoffMultiplier!==void 0&&(typeof n.restartBackoffMultiplier!="number"||n.restartBackoffMultiplier<1))throw new TypeError("mcpPlugin: restartBackoffMultiplier must be >= 1");if(n.toolRefreshIntervalMs!==void 0&&(typeof n.toolRefreshIntervalMs!="number"||!Number.isInteger(n.toolRefreshIntervalMs)||n.toolRefreshIntervalMs<0))throw new TypeError("mcpPlugin: toolRefreshIntervalMs must be a non-negative integer")}async function ve(n,e){let t=e["~standard"];if(!t?.validate)throw new Error("mcpPlugin: schema must be a StandardSchemaV1 with ~standard.validate");let r=t.validate(n);if(r instanceof Promise&&(r=await r),r.issues)throw new Error(`mcpPlugin options validation failed: ${routecraft.formatSchemaIssues(r.issues)}`);if(r.value===void 0)throw new Error("mcpPlugin options validation failed: no value returned");return r.value}var at='MCP stdio client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',J=class{constructor(e,t,r,o){this.options=e;this.logger=t;this.onEvent=r;this.onToolsUpdated=o;}options;logger;onEvent;onToolsUpdated;client=null;transport=null;running=false;stopping=false;restartCount=0;restartTimer=null;stabilityTimer=null;tools=[];async start(){if(this.running)return;this.stopping=false,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null);let e,t;try{e=await import('@modelcontextprotocol/sdk/client/index.js'),t=await import('@modelcontextprotocol/sdk/client/stdio.js');}catch{throw new Error(at)}let{serverId:r,command:o,args:i,env:s,cwd:a}=this.options;this.transport=new t.StdioClientTransport({command:o,args:i??[],...s?{env:s}:{},...a?{cwd:a}:{},stderr:"pipe"});let c=this.transport;c.onerror=f=>{this.logger.error({err:f,serverId:r},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${r}:error`,{serverId:r,error:f});},c.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},c.stderr?.on&&c.stderr.on("data",f=>{this.logger.debug({serverId:r,stderr:String(f).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{},listChanged:{tools:{onChanged:(f,p)=>{p&&Array.isArray(p.tools)?(this.tools=p.tools,this.onToolsUpdated(r,this.tools),this.onEvent(`plugin:mcp:client:${r}:tools:listed`,{serverId:r,toolCount:this.tools.length})):this.refreshTools();}}}}),await this.client.connect(this.transport),this.running=true,await this.refreshTools(),this.logger.info({serverId:r,toolCount:this.tools.length},"Stdio client started"),this.onEvent(`plugin:mcp:client:${r}:started`,{serverId:r,toolCount:this.tools.length});}async stop(){this.stopping=true,this.restartTimer&&(clearTimeout(this.restartTimer),this.restartTimer=null),this.stabilityTimer&&(clearTimeout(this.stabilityTimer),this.stabilityTimer=null);let{serverId:e}=this.options;if(this.client){try{await this.client.close();}catch{}this.client=null;}if(this.transport){let t=this.transport;if(typeof t.close=="function")try{await Promise.resolve(t.close());}catch{}this.transport=null;}this.running=false,this.logger.info({serverId:e},"Stdio client stopped"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"graceful"});}async callTool(e,t){if(!this.running||!this.client)throw new Error(`Stdio client "${this.options.serverId}" is not running. Cannot call tool "${e}".`);let r=await this.client.callTool({name:e,arguments:t});return K(r)}getTools(){return [...this.tools]}isRunning(){return this.running}async refreshTools(){if(!this.client)return;let{serverId:e}=this.options;try{let t=await this.client.listTools();this.tools=t.tools??[],this.onToolsUpdated(e,this.tools),this.onEvent(`plugin:mcp:client:${e}:tools:listed`,{serverId:e,toolCount:this.tools.length});}catch(t){this.logger.warn({err:t,serverId:e},"Failed to list tools for stdio client");}}handleDisconnect(){let{serverId:e,maxRestarts:t,restartDelayMs:r,restartBackoffMultiplier:o}=this.options;if(this.tools.length>0&&(this.tools=[],this.onToolsUpdated(e,[])),this.logger.warn({serverId:e},"Stdio client disconnected unexpectedly"),this.onEvent(`plugin:mcp:client:${e}:stopped`,{serverId:e,reason:"unexpected"}),this.restartCount>=t){this.logger.error({serverId:e,restartCount:this.restartCount,maxRestarts:t},"Stdio client exceeded max restarts, giving up"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:new Error(`Max restarts (${t}) exceeded for stdio client "${e}"`)});return}let i=r*Math.pow(o,this.restartCount);this.logger.info({serverId:e,restartCount:this.restartCount,delayMs:i},"Scheduling stdio client restart"),this.restartTimer=setTimeout(()=>{this.restartTimer=null,this.restart();},i);}async restart(){let{serverId:e}=this.options;this.restartCount++,this.client=null,this.transport=null;try{await this.start(),this.logger.info({serverId:e,restartCount:this.restartCount},"Stdio client restarted successfully"),this.onEvent(`plugin:mcp:client:${e}:restarted`,{serverId:e,restartCount:this.restartCount});let t=this.options.restartDelayMs*2;this.stabilityTimer=setTimeout(()=>{this.stabilityTimer=null,this.running&&(this.restartCount=0);},t);}catch(t){this.logger.error({err:t,serverId:e,restartCount:this.restartCount},"Stdio client restart failed"),this.onEvent(`plugin:mcp:client:${e}:error`,{serverId:e,error:t}),this.handleDisconnect();}}};var k=class{tools=new Map;setToolsForSource(e,t,r){let o=new Map;for(let i of r){let s={name:i.name,inputSchema:i.inputSchema,source:e,transport:t};i.description!==void 0&&(s.description=i.description),i.annotations!==void 0&&(s.annotations=i.annotations),o.set(i.name,s);}this.tools.set(e,o);}removeSource(e){this.tools.delete(e);}getTools(){let e=[];for(let t of this.tools.values())for(let r of t.values())e.push(r);return e}getToolsByServer(e){let t=this.tools.get(e);return t?Array.from(t.values()):[]}getTool(e){for(let t of this.tools.values()){let r=t.get(e);if(r)return r}}getToolBySource(e,t){return this.tools.get(e)?.get(t)}};function Pe(n){return "transport"in n&&n.transport==="stdio"}function Me(n={}){we(n);let e=null,t=new Map,r=new Map,o=[],i=null;return {async apply(p){if(p.setStore(b,true),i=new k,p.setStore($,i),p.setStore(C,t),n.clients&&Object.keys(n.clients).length>0){let d=Object.entries(n.clients),l=new Map;for(let[u,m]of d)l.set(u,m);p.setStore(v,l);for(let[u,m]of d){if(Pe(m))await s(p,u,m,i);else {let g=m;await c(p,u,g.url,i,g.auth),f(p,u,g.url,i,g.auth);}let h=Pe(m)?"stdio":"http";p.emit(`plugin:mcp:client:${u}:registered`,{serverId:u,transport:h});}}e=new A(p,n),await e.start();},async teardown(p){for(let d of o)clearInterval(d);o.length=0;for(let[d,l]of r)try{await l.close();}catch(u){p.logger.error({err:u,serverId:d,operation:"close"},"Failed to close HTTP client");}r.clear();for(let[d,l]of t)try{await l.stop();}catch(u){p.logger.error({err:u,serverId:d,operation:"stop"},"Failed to stop stdio client");}if(t.clear(),e){try{await e.stop();}catch(d){p.logger.error({err:d,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}i=null;}};async function s(p,d,l,u){let m={serverId:d,command:l.command,args:l.args??[],maxRestarts:n.maxRestarts??5,restartDelayMs:n.restartDelayMs??1e3,restartBackoffMultiplier:n.restartBackoffMultiplier??2};l.env!==void 0&&(m.env=l.env),l.cwd!==void 0&&(m.cwd=l.cwd);let h=new J(m,p.logger,(g,y)=>{p.emit(g,y);},(g,y)=>{u.setToolsForSource(g,"stdio",y);});t.set(d,h);try{await h.start();}catch(g){p.logger.error({err:g,serverId:d,operation:"start"},"Failed to start stdio client"),p.emit(`plugin:mcp:client:${d}:error`,{serverId:d,error:g});}}async function a(p,d,l){let u=r.get(p);if(u)return u;let{Client:m}=await import('@modelcontextprotocol/sdk/client/index.js'),{StreamableHTTPClientTransport:h}=await import('@modelcontextprotocol/sdk/client/streamableHttp.js'),g=await W(l),y=g?{requestInit:{headers:g}}:void 0,P=new h(new URL(d),y),w=new m({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}});await w.connect(P);let I=w;return r.set(p,I),I}async function c(p,d,l,u,m){try{let y=(await(await a(d,l,m)).listTools()).tools??[];u.setToolsForSource(d,"http",y),p.emit(`plugin:mcp:client:${d}:tools:listed`,{serverId:d,toolCount:y.length});}catch(h){r.delete(d),p.logger.warn({err:h,serverId:d,url:l,operation:"listTools"},"Failed to list tools from HTTP client");}}function f(p,d,l,u,m){let h=n.toolRefreshIntervalMs??6e4;if(h<=0)return;let g=setInterval(()=>{c(p,d,l,u,m);},h);o.push(g);}}var Y=class{constructor(e){this._options=e;}_options;async run(e){return this._options,e.logger&&e.logger.debug({adapter:"agent"},"Agent pass-through \u2014 implementation pending"),{output:e.body,steps:0}}};function lt(n){let e=n.indexOf(":");if(e<1||e===n.length-1)throw new Error(`Agent adapter: modelId must be "providerId:modelName" (e.g. ollama:llama3). Got: "${n}"`)}var O=class{adapterId="routecraft.adapter.agent";runner;constructor(e){lt(e.modelId),this.runner=new Y(e);}async send(e){return this.runner.run(e)}};function Se(n){return new O(n)}var X=new Map;async function Q(){let n=[...X.entries()];X.clear(),n.length!==0&&await Promise.all(n.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function pt(n){return n.includes("/")?n:`Xenova/${n}`}var ct='The Hugging Face embedding provider requires "@huggingface/transformers". Install it with: pnpm add @huggingface/transformers';function ut(n,e){if(!(n instanceof Error))return false;let t=n.message??"";return (t.includes("ERR_MODULE_NOT_FOUND")||t.includes("Cannot find module")||t.includes("Cannot find package"))&&t.includes(e)}async function dt(n){let e=pt(n),t=X.get(e);if(t)return t.run;let r;try{r=(await import('@huggingface/transformers')).pipeline;}catch(a){throw ut(a,"@huggingface/transformers")?new Error(ct):a}let o=await r("feature-extraction",e,{dtype:"fp32"}),i=(a,c)=>o(a,{pooling:c?.pooling??"mean",normalize:c?.normalize??true}),s={run:i,dispose:typeof o.dispose=="function"?()=>Promise.resolve(o.dispose()):void 0};return X.set(e,s),i}function Re(n){if(n===null)return "null";if(typeof n!="object")return String(n);if(Array.isArray(n))return `array(${n.length})`;try{let e=JSON.stringify(n);return e.length>100?e.slice(0,100)+"...":e}catch{return "object"}}function mt(n){if(Array.isArray(n))return n;if(n instanceof Float32Array)return Array.from(n);if(n&&typeof n=="object"&&"data"in n){let e=n.data;if(Array.isArray(e))return e;if(e instanceof Float32Array)return Array.from(e);throw new Error(`Embedding output .data must be an Array or Float32Array; got ${typeof e}: ${Re(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof n}: ${Re(n)}`)}async function Te(n){let{config:e,modelName:t,text:r}=n;if(e.provider==="mock"){let i=[];for(let s=0;s<8;s++)i.push((r.length+s)%100/100);return i}if(e.provider==="huggingface"){let i=await(await dt(t))(r,{pooling:"mean",normalize:true}),s=i&&typeof i=="object"&&"data"in i?i.data:i;return mt(s)}throw e.provider==="ollama"||e.provider==="openai"?new Error(`Embedding provider "${e.provider}" is not yet implemented. Use huggingface for now.`):new Error(`Unknown embedding provider: ${e.provider}`)}var Z=Symbol.for("routecraft.adapter.embedding.providers"),ee=Symbol.for("routecraft.adapter.embedding.options");function ft(n){let e=n.indexOf(":");if(e<1||e===n.length-1)throw new Error(`Embedding adapter: model id must be "providerId:modelName" (e.g. huggingface:all-MiniLM-L6-v2). Got: "${n}"`);return {providerId:n.slice(0,e),modelName:n.slice(e+1)}}function ht(n,e){if(!e)throw new Error(`Embedding adapter: model id "${n}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so embedding providers can be read.`);let t=e.getStore(Z);if(!t)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:r,modelName:o}=ft(n),i=t.get(r);if(!i)throw new Error(`Embedding provider "${r}" not found. Register it with embeddingPlugin({ providers: { "${r}": {} } }).`);return {config:i,modelName:o}}function yt(n){return e=>{let t=n(e);return Array.isArray(t)?t.filter(Boolean).join(" | "):t}}var L=class{constructor(e,t={}){this.modelId=e;this.options=t;}modelId;adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(ee),...this.options}}async send(e){let t=routecraft.getExchangeContext(e),{config:r,modelName:o}=ht(this.modelId,t),i=this.mergedOptions(t);if(!i.using)throw new Error("Embedding adapter: options.using(exchange) is required to build the string to embed.");let a=yt(i.using)(e);return {embedding:await Te({config:r,modelName:o,text:a})}}};function Ee(n,e){return new L(n,e)}function wt(n,e){return {...e,provider:n}}function be(n={providers:{}}){return {apply(e){let t=new Map;for(let[r,o]of Object.entries(n.providers))o!==void 0&&t.set(r,wt(r,o));e.setStore(Z,t),n.defaultOptions&&Object.keys(n.defaultOptions).length>0&&e.setStore(ee,n.defaultOptions);},async teardown(){await Q();}}}
2
+ Object.defineProperty(exports,"jwks",{enumerable:true,get:function(){return routecraft.jwks}});Object.defineProperty(exports,"jwt",{enumerable:true,get:function(){return routecraft.jwt}});exports.ADAPTER_LLM_OPTIONS=T;exports.ADAPTER_LLM_PROVIDERS=S;exports.ADAPTER_MCP_CLIENT_SERVERS=v;exports.AgentDestinationAdapter=O;exports.BRAND=ie;exports.BRAND_MCP_ADAPTER=R;exports.EmbeddingDestinationAdapter=L;exports.LlmDestinationAdapter=E;exports.MCP_PLUGIN_REGISTERED=b;exports.MCP_STDIO_MANAGERS=C;exports.MCP_TOOL_REGISTRY=$;exports.McpHeadersKeys=V;exports.McpServer=A;exports.McpToolRegistry=k;exports.agent=Se;exports.defaultArgs=z;exports.disposeEmbeddingPipelineCache=Q;exports.embedding=Ee;exports.embeddingPlugin=be;exports.isMcpAdapter=xe;exports.isOAuthAuth=G;exports.llm=ue;exports.llmPlugin=me;exports.mcp=H;exports.mcpPlugin=Me;exports.oauth=fe;exports.validateLlmPluginOptions=q;exports.validateWithSchema=ve;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map