@routecraft/ai 0.5.0-canary.21 → 0.5.0-canary.22

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'),async_hooks=require('async_hooks'),http=require('http');var ve={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function qe(t,e){return typeof t=="object"&&t!==null&&t[e]===true}function $e(t){return qe(t,ve.McpAdapter)}function N(t,e){throw new Error(`The ${e} LLM provider requires the "${t}" package. Install it with: pnpm add ${t}`)}function j(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 Ge={ollama:{baseURL:"http://localhost:11434/api"}};function H(t){return {...t.inputTokens!==void 0&&{inputTokens:t.inputTokens},...t.outputTokens!==void 0&&{outputTokens:t.outputTokens},...t.totalTokens!==void 0&&{totalTokens:t.totalTokens}}}function q(t){try{if("output"in t&&t.output!==void 0)return t.output}catch{}}function Pe(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 W(t){let{config:e,modelId:n,options:r,systemPrompt:o,userPrompt:i,output:s}=t;switch(e.provider){case "openai":return Fe(e,n,r,o,i,s);case "anthropic":return Ve(e,n,r,o,i,s);case "gemini":return Be(e,n,r,o,i,s);case "openrouter":return Ke(e,n,r,o,i,s);case "ollama":return We(e,n,r,o,i,s);default:{let a=e;throw new Error(`LLM provider not implemented: ${a.provider}`)}}}async function Fe(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/openai')).createOpenAI;}catch(f){throw j(f,"@ai-sdk/openai")&&N("@ai-sdk/openai","OpenAI"),f}let{generateText:a}=await import('ai'),l={apiKey:t.apiKey};t.baseURL!==void 0&&(l.baseURL=t.baseURL);let m={model:s(l)(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(m.system=r),n.topP!==void 0&&(m.topP=n.topP),n.frequencyPenalty!==void 0&&(m.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(m.presencePenalty=n.presencePenalty);let p=i!==void 0?{...m,output:i}:m,d=await a(p),g={text:d.text??"",raw:d};d.usage&&(g.usage=H(d.usage));let h=q(d);return h!==void 0&&(g.output=h),g}async function Ve(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/anthropic')).createAnthropic;}catch(h){throw j(h,"@ai-sdk/anthropic")&&N("@ai-sdk/anthropic","Anthropic"),h}let{generateText:a}=await import('ai'),c={model:s({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(c.system=r),n.topP!==void 0&&(c.topP=n.topP),n.frequencyPenalty!==void 0&&(c.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(c.presencePenalty=n.presencePenalty);let m=i!==void 0?{...c,output:i}:c,p=await a(m),d={text:p.text??"",raw:p};p.usage&&(d.usage=H(p.usage));let g=q(p);return g!==void 0&&(d.output=g),d}async function Be(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/google')).createGoogleGenerativeAI;}catch(h){throw j(h,"@ai-sdk/google")&&N("@ai-sdk/google","Gemini"),h}let{generateText:a}=await import('ai'),c={model:s({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(c.system=r),n.topP!==void 0&&(c.topP=n.topP),n.frequencyPenalty!==void 0&&(c.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(c.presencePenalty=n.presencePenalty);let m=i!==void 0?{...c,output:i}:c,p=await a(m),d={text:p.text??"",raw:p};p.usage&&(d.usage=H(p.usage));let g=q(p);return g!==void 0&&(d.output=g),d}async function Ke(t,e,n,r,o,i){let s;try{s=(await import('@openrouter/ai-sdk-provider')).createOpenRouter;}catch(y){throw j(y,"@openrouter/ai-sdk-provider")&&N("@openrouter/ai-sdk-provider","OpenRouter"),y}let{generateText:a}=await import('ai'),l=s({apiKey:t.apiKey}),u=t.modelId??e,c=l.chat(u);Pe(c,"OpenRouter",u);let p={model:c,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 d=i!==void 0?{...p,output:i}:p,g=await a(d),h={text:g.text??"",raw:g};g.usage&&(h.usage=H(g.usage));let f=q(g);return f!==void 0&&(h.output=f),h}async function We(t,e,n,r,o,i){let s;try{s=(await import('ollama-ai-provider-v2')).createOllama;}catch(y){throw j(y,"ollama-ai-provider-v2")&&N("ollama-ai-provider-v2","Ollama"),y}let{generateText:a}=await import('ai'),l=s({baseURL:t.baseURL??Ge.ollama.baseURL}),u=t.modelId??e,c=l(u);Pe(c,"Ollama",u);let p={model:c,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 d=i!==void 0?{...p,output:i}:p,g=await a(d),h={text:g.text??"",raw:g};g.usage&&(h.usage=H(g.usage));let f=q(g);return f!==void 0&&(h.output=f),h}var E=Symbol.for("routecraft.adapter.llm.providers"),C=Symbol.for("routecraft.adapter.llm.options");function $(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`LLM 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 z(t,e){if(typeof t!="string"){let s=t.modelId??"";if(s.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`LLM model: inline LlmModelConfig for provider "${t.provider}" did not resolve to a model name. Either pass the model as a "providerId:modelName" string (e.g. "${t.provider}:<model>") or set "modelId" on the config. Providers "openai", "anthropic", and "gemini" do not carry a modelId field, so those must use the string form.`});return {config:t,modelName:s}}if(!e)throw new Error(`LLM model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${E.description}" can be read.`);let n=e.getStore(E);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}=$(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}}function G(t,e){return t===void 0||t===""?"":typeof t=="function"?t(e):t}function J(t){let e=t.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}function Me(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 s;try{s=e.validate(i);}catch(l){return {success:false,error:l instanceof Error?l:new Error(String(l))}}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(n,{validate:r});return ai.Output.object({schema:o})}async function Qe(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 et=0,tt=1024,S=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.llm";options;mergedOptions(e){let n=e.getStore(C);return {temperature:et,maxTokens:tt,...n,...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=z(this.modelId,n),i=this.mergedOptions(n),s=G(i.systemPrompt,e),a=G(i.userPrompt,e)||J(e),l={temperature:i.temperature,maxTokens:i.maxTokens};i.topP!==void 0&&(l.topP=i.topP),i.frequencyPenalty!==void 0&&(l.frequencyPenalty=i.frequencyPenalty),i.presencePenalty!==void 0&&(l.presencePenalty=i.presencePenalty);let u=i.outputSchema!==void 0?Me(i.outputSchema):void 0,c=await W({config:r,modelId:o,options:l,systemPrompt:s,userPrompt:a,output:u});if(c.output===void 0&&c.text&&i.outputSchema!==void 0){let m=await Qe(c.text,i.outputSchema);m!==void 0&&(c.output=m);}return c}getMetadata(e){let n=e,{providerId:r}=$(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 Re(t,e){return new S(t,e)}var Te=["openai","anthropic","openrouter","ollama","gemini"];function nt(t){return Te.includes(t)}function Y(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(!nt(e))throw new TypeError(`llmPlugin: providers["${e}"] is not a supported provider. Supported: ${Te.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 rt=["openai","anthropic","openrouter","ollama","gemini"];function ot(t,e){return {provider:t,...e}}function Ee(t={providers:{}}){return Y(t),{apply(e){let n=new Map;for(let r of rt){let o=t.providers[r];o!==void 0&&n.set(r,ot(r,o));}e.setStore(E,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(C,t.defaultOptions);}}}var x=Symbol.for("routecraft.mcp.plugin.registered"),v=Symbol.for("routecraft.mcp.client.servers"),X=Symbol.for("routecraft.mcp.tool.registry"),k=Symbol.for("routecraft.mcp.stdio.managers"),P=Symbol.for("routecraft.mcp.local-tool-registry"),Z=(p=>(p.TOOL="routecraft.mcp.tool",p.SESSION="routecraft.mcp.session",p.AUTH_SUBJECT="routecraft.auth.subject",p.AUTH_SCHEME="routecraft.auth.scheme",p.AUTH_KIND="routecraft.auth.kind",p.AUTH_ROLES="routecraft.auth.roles",p.AUTH_SCOPES="routecraft.auth.scopes",p.AUTH_EMAIL="routecraft.auth.email",p.AUTH_NAME="routecraft.auth.name",p.AUTH_ISSUER="routecraft.auth.issuer",p.AUTH_AUDIENCE="routecraft.auth.audience",p.AUTH_CLIENT_ID="routecraft.auth.client_id",p))(Z||{});function Q(t){return "provider"in t&&t.provider==="oauth"}var A=Symbol.for("routecraft.mcp.adapter");var it=/^[A-Za-z0-9_-]{1,64}$/;function st(t){if(!it.test(t))throw routecraft.rcError("RC5003",void 0,{message:`Invalid MCP tool name "${t}"`,suggestion:"MCP tool names must match /^[A-Za-z0-9_-]{1,64}$/ for client interoperability (OpenAI, Anthropic, etc.). Use alphanumerics, underscore, or hyphen in the route's .id()."})}var te=class{adapterId="routecraft.adapter.mcp";options;constructor(e={}){this[A]=true,this.options=e;}async subscribe(e,n,r,o,i){if(!i?.routeId)throw routecraft.rcError("RC5003",void 0,{message:"McpSourceAdapter requires a route id from the engine (missing SourceMeta.routeId)",suggestion:"MCP source adapters take their tool name from the route id. Call .id('tool-name') on the route before .from(mcp(...))."});let s=i.routeId;st(s);let a=i.discovery,l=a?.description;if(typeof l!="string"||l.length===0)throw routecraft.rcError("RC5003",void 0,{message:`MCP route "${s}" requires a description`,suggestion:"Set .description('...') on the route builder before .from(mcp()); the MCP protocol requires a non-empty description for each tool."});if(e.getStore(x)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");let c=e.getStore(P);if(c||(c=new Map,e.setStore(P,c)),c.has(s))throw routecraft.rcError("RC5003",void 0,{message:`Duplicate MCP tool endpoint "${s}": another .from(mcp(...)) route already registered this endpoint in the same context`,suggestion:"Each MCP tool endpoint must be unique within a context. Rename one of the mcp() routes to a different route id."});let p={endpoint:s,description:l,handler:async d=>n(d.body,d.headers)};a?.title!==void 0&&(p.title=a.title),a?.input!==void 0&&(p.input=a.input),a?.output!==void 0&&(p.output=a.output),this.options.annotations!==void 0&&(p.annotations=this.options.annotations),this.options.icons!==void 0&&(p.icons=this.options.icons),r.signal.addEventListener("abort",()=>{e.getStore(P)?.delete(s);},{once:true}),!r.signal.aborted&&(c.set(s,p),o?.(),await new Promise(d=>{if(r.signal.aborted){d();return}r.signal.addEventListener("abort",()=>d(),{once:true});}));}};function ne(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 Ae=new WeakMap;async function at(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=(Ae.get(t)??0)%t.length;return Ae.set(t,e+1),t[e]}return t}async function re(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 at(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 lt(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 ct(t,e){return !t.serverId||!e?void 0:e.getStore(v)?.get(t.serverId)}function dt(t,e){if(t.url)return lt(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=ct(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 oe=t=>typeof t.body=="object"&&t.body!==null?t.body:{input:t.body},F=class{constructor(e){this.options=e;if(this[A]=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 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??oe)(e);if(this.options.serverId&&n){let c=n.getStore(k)?.get(this.options.serverId);if(c){let d=await c.callTool(r,i);return d&&typeof d=="object"&&(d.metadata={toolName:r,transport:"stdio",serverId:this.options.serverId}),d}let p=n.getStore(v)?.get(this.options.serverId);if(p&&typeof p=="object"&&"transport"in p&&p.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}=dt(this.options,n),l=await this.callRemoteTool(s,r,i,a);return l&&typeof l=="object"&&(l.metadata={toolName:r,url:s,transport:"http",...this.options.serverId?{serverId:this.options.serverId}:{}}),l}getMetadata(e){return e&&typeof e=="object"&&"metadata"in e?e.metadata:{toolName:"unknown",transport:"unknown"}}async callRemoteTool(e,n,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,l=s.StreamableHTTPClientTransport,u=new URL(e),c=await re(o),m=c?{requestInit:{headers:c}}:void 0,p=new l(u,m),d={name:"routecraft-mcp-client",version:"1.0.0"},g=new a(d,{capabilities:{}});try{await g.connect.call(g,p);let y=await g.callTool.call(g,{name:n,arguments:r});return ne(y)}finally{let h=g,f=h.close??h.disconnect;if(typeof f=="function")try{await Promise.resolve(f.call(g));}catch{}let y=p,M=y.close??y.destroy;if(typeof M=="function")try{await Promise.resolve(M.call(p));}catch{}}}};function V(t,e){if(typeof t=="object"&&t!==null&&("url"in t||"serverId"in t)){let n=t;if(typeof n.auth?.token=="string"&&n.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(n.auth?.token)){if(n.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let r=0;r<n.auth.token.length;r++){let o=n.auth.token[r];if(typeof o!="string"||o.trim().length===0)throw new TypeError(`mcp(): auth.token[${r}] must be a non-empty string`)}}return routecraft.tagAdapter(new F(n),V,routecraft.factoryArgs(t,e))}if(typeof t=="string"&&t.includes(":")){let n=t.indexOf(":"),r=t.slice(0,n),o=t.slice(n+1),i={serverId:r,tool:o};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(i.args=e.args),routecraft.tagAdapter(new F(i),V,routecraft.factoryArgs(t,e))}if(typeof t=="string")throw routecraft.rcError("RC5003",void 0,{message:`mcp(${JSON.stringify(t)}) is not a valid call: a bare string without ":" is neither a client shorthand nor source options`,suggestion:"Use .from(mcp()) for a source (tool name comes from .id()), .to(mcp({ url, tool })) for a remote server, .to(mcp('server:tool')) for a registered shorthand, or direct('name') for in-process dispatch."});return routecraft.tagAdapter(new te(t??{}),V,routecraft.factoryArgs(t,e))}function mt(t){if(typeof t=="function")return async n=>t(n);let e=t;return async n=>n===e.client_id?e:void 0}function gt(t){if(!t)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");return typeof t=="function"?async e=>t(e):async e=>t.validator(e)}function Oe(t){if(new URL(t.resourceIssuerUrl.toString()).protocol!=="https:"&&process.env.NODE_ENV==="production")throw new TypeError("oauth: resourceIssuerUrl must use HTTPS in production");let n=gt(t.verify),r=mt(t.client);return {provider:"oauth",resourceIssuerUrl:t.resourceIssuerUrl,endpoints:t.endpoints,verifyAccessToken:n,getClient:r,...t.baseUrl!==void 0&&{baseUrl:t.baseUrl},...t.scopesSupported!==void 0&&{scopesSupported:t.scopesSupported},...t.requiredScopes!==void 0&&{requiredScopes:t.requiredScopes},...t.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:t.serviceDocumentationUrl},...t.resourceName!==void 0&&{resourceName:t.resourceName}}}var Ce=new async_hooks.AsyncLocalStorage,ge='MCP server requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',I=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(ge)}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(){this.options.auth&&Q(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(ge)}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,n){let r=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}});await this.setupRequestHandlersOn(r);let o=new n({sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:u=>{this.httpSessions.set(u,{server:r,transport:o}),this.context.logger.debug({sessionId:u},"MCP session created"),this.context.emit("plugin:mcp:session:created",{sessionId:u});},enableJsonResponse:true});await r.connect(o);let s=o,a=s.onclose;s.onclose=()=>{let u=o.sessionId;u&&(this.httpSessions.delete(u),this.context.logger.debug({sessionId:u},"MCP session closed"),this.context.emit("plugin:mcp:session:closed",{sessionId:u})),a?.();};let l=o.handleRequest;if(typeof l!="function")throw new Error("StreamableHTTPServerTransport.handleRequest not found - SDK may have changed");return {transport:o,handleRequest:l.bind(o)}}async handleMcpRequest(e,n,r,o){let i=e.headers["mcp-session-id"],s=a=>Ce.run(r,a);try{if(i&&this.httpSessions.has(i)){let a=this.httpSessions.get(i),l=a.transport.handleRequest;await s(()=>l.call(a.transport,e,n));}else if(!i||e.method==="POST"){let{handleRequest:a}=await o();await s(()=>a(e,n));}else n.writeHead(404,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Session not found"}));}catch(a){let l=routecraft.isRoutecraftError(a)?a.meta.message:a instanceof Error?a.message:"MCP HTTP request error";this.context.logger.error({err:a},l),n.headersSent||(n.writeHead(500,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Internal Server Error"})));}}async startHttpWithValidator(){let{ServerCtor:e,TransportClass:n}=await this.importSdkHttp(),r=this.options.port,o=this.options.host,i=()=>this.createSession(e,n);this.httpServer=http.createServer(async(s,a)=>{let l=s.url?.split("?")[0]??"";if(l!=="/mcp"&&l!=="/mcp/"){a.writeHead(404,{"Content-Type":"application/json"}),a.end(JSON.stringify({error:"Not Found",path:l}));return}let u;if(this.options.auth){let c=await this.validateAuth(s);if(!c){a.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":'Bearer realm="mcp"'}),a.end(JSON.stringify({error:"Unauthorized"}));return}u=c;}await this.handleMcpRequest(s,a,u,i);}),await this.listenHttp(r,o);}async startHttpWithOAuth(e){let{ServerCtor:n,TransportClass:r}=await this.importSdkHttp(),o,i,s,a;try{let f=await import('express');o=f.default??f;}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 l=async f=>{let y;try{y=await e.verifyAccessToken(f);}catch(w){let T={reason:w instanceof Error?w.message:"invalid_token",scheme:"bearer",source:"mcp",path:"oauth"};throw this.context.logger.warn({err:w,...T},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",T),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:f,clientId:y.clientId??y.subject,scopes:y.scopes??[],expiresAt:y.expiresAt,extra:{principal:y}}},u=new a({endpoints:{authorizationUrl:e.endpoints.authorizationUrl,tokenUrl:e.endpoints.tokenUrl,revocationUrl:e.endpoints.revocationUrl,registrationUrl:e.endpoints.registrationUrl},verifyAccessToken:l,getClient:e.getClient}),c=this.options.port,m=this.options.host,p=o(),d={provider:u,issuerUrl:new URL(e.resourceIssuerUrl.toString())};e.baseUrl&&(d.baseUrl=new URL(e.baseUrl.toString())),e.scopesSupported&&(d.scopesSupported=e.scopesSupported),e.serviceDocumentationUrl&&(d.serviceDocumentationUrl=new URL(e.serviceDocumentationUrl.toString())),e.resourceName&&(d.resourceName=e.resourceName),p.use(i(d));let g={verifier:u};e.requiredScopes&&(g.requiredScopes=e.requiredScopes),p.use("/mcp",s(g));let h=()=>this.createSession(n,r);p.all("/mcp",async(f,y)=>{let M=f,w=y,U=f.auth,T=this.authInfoToPrincipal(U);if(T){let we={subject:T.subject,scheme:T.scheme,source:"mcp"};this.context.logger.info(we,"Auth succeeded"),this.context.emit("auth:success",we);}await this.handleMcpRequest(M,w,T,h);}),this.httpServer=http.createServer(p),await this.listenHttp(c,m);}async listenHttp(e,n){await new Promise((i,s)=>{this.httpServer.listen(e,n,()=>i()),this.httpServer.on("error",a=>{let l=routecraft.isRoutecraftError(a)?a.meta.message:a instanceof Error?a.message:"MCP HTTP server listen failed";this.context.logger.error({err:a},l),s(a);});});let r=this.getHttpPort()??e,o={host:n,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 n=e.extra?.principal;if(n)return n;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 n=this.options.auth;if(!n||!("validator"in n))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 n.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 l={reason:s instanceof Error?s.message:"invalid_token",scheme:"bearer",source:"mcp"};return this.context.logger.warn({err:s,...l},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",l),null}}async setupRequestHandlers(){await this.setupRequestHandlersOn(this.server);}async setupRequestHandlersOn(e){let n;try{n=await import('@modelcontextprotocol/sdk/types.js');}catch{throw new Error(ge)}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 s=e;s.setRequestHandler(o,async()=>{let a=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:a}}),s.setRequestHandler(i,async a=>{let u=a.params;return await this.handleToolCall(u.name||"",u.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(P);if(!e)return [];let n=Array.from(e.values()),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.entryToMcpTool(o))}entryToMcpTool(e){let n={name:e.endpoint,description:e.description,inputSchema:this.schemaToJsonSchema(e.input?.body)};return e.title!==void 0&&(n.title=e.title),e.output?.body!==void 0&&(n.outputSchema=this.schemaToJsonSchema(e.output.body)),e.annotations!==void 0&&(n.annotations=e.annotations),e.icons!==void 0&&(n.icons=e.icons),n}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 o=this.context.getStore(P)?.get(e);if(!o){let m=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:m.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 s=Ce.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 l=new routecraft.DefaultExchange(this.context,{body:i,headers:a});this.context.emit("plugin:mcp:tool:called",{tool:e,args:n});let u=await o.handler(l),c=typeof u.body=="string"?u.body:JSON.stringify(u.body);return this.context.emit("plugin:mcp:tool:completed",{tool:e}),{content:[{type:"text",text:c}]}}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 Se(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)if("provider"in t.auth){if(t.auth.provider!=="oauth")throw new TypeError('mcpPlugin: auth.provider must be "oauth". Use the oauth() helper.')}else if("validator"in t.auth){if(typeof t.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(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 xe(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 wt='MCP stdio client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',ie=class{constructor(e,n,r,o){this.options=e;this.logger=n;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,n;try{e=await import('@modelcontextprotocol/sdk/client/index.js'),n=await import('@modelcontextprotocol/sdk/client/stdio.js');}catch{throw new Error(wt)}let{serverId:r,command:o,args:i,env:s,cwd:a}=this.options;this.transport=new n.StdioClientTransport({command:o,args:i??[],...s?{env:s}:{},...a?{cwd:a}:{},stderr:"pipe"});let l=this.transport;l.onerror=u=>{this.logger.error({err:u,serverId:r},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${r}:error`,{serverId:r,error:u});},l.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},l.stderr?.on&&l.stderr.on("data",u=>{this.logger.debug({serverId:r,stderr:String(u).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{},listChanged:{tools:{onChanged:(u,c)=>{c&&Array.isArray(c.tools)?(this.tools=c.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 ne(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 _=class{tools=new Map;setToolsForSource(e,n,r){let o=new Map;for(let i of r){let s={name:i.name,inputSchema:i.inputSchema,source:e,transport:n};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 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 ke(t){return "transport"in t&&t.transport==="stdio"}function Le(t={}){Se(t);let e=null,n=new Map,r=new Map,o=[],i=null;return {async apply(c){if(c.setStore(x,true),i=new _,c.setStore(X,i),c.setStore(k,n),t.clients&&Object.keys(t.clients).length>0){let m=Object.entries(t.clients),p=new Map;for(let[d,g]of m)p.set(d,g);c.setStore(v,p);for(let[d,g]of m){if(ke(g))await s(c,d,g,i);else {let f=g;await l(c,d,f.url,i,f.auth),u(c,d,f.url,i,f.auth);}let h=ke(g)?"stdio":"http";c.emit(`plugin:mcp:client:${d}:registered`,{serverId:d,transport:h});}}e=new I(c,t),await e.start();},async teardown(c){for(let m of o)clearInterval(m);o.length=0;for(let[m,p]of r)try{await p.close();}catch(d){c.logger.error({err:d,serverId:m,operation:"close"},"Failed to close HTTP client");}r.clear();for(let[m,p]of n)try{await p.stop();}catch(d){c.logger.error({err:d,serverId:m,operation:"stop"},"Failed to stop stdio client");}if(n.clear(),e){try{await e.stop();}catch(m){c.logger.error({err:m,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}i=null;}};async function s(c,m,p,d){let g={serverId:m,command:p.command,args:p.args??[],maxRestarts:t.maxRestarts??5,restartDelayMs:t.restartDelayMs??1e3,restartBackoffMultiplier:t.restartBackoffMultiplier??2};p.env!==void 0&&(g.env=p.env),p.cwd!==void 0&&(g.cwd=p.cwd);let h=new ie(g,c.logger,(f,y)=>{c.emit(f,y);},(f,y)=>{d.setToolsForSource(f,"stdio",y);});n.set(m,h);try{await h.start();}catch(f){c.logger.error({err:f,serverId:m,operation:"start"},"Failed to start stdio client"),c.emit(`plugin:mcp:client:${m}:error`,{serverId:m,error:f});}}async function a(c,m,p){let d=r.get(c);if(d)return d;let{Client:g}=await import('@modelcontextprotocol/sdk/client/index.js'),{StreamableHTTPClientTransport:h}=await import('@modelcontextprotocol/sdk/client/streamableHttp.js'),f=await re(p),y=f?{requestInit:{headers:f}}:void 0,M=new h(new URL(m),y),w=new g({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}});await w.connect(M);let U=w;return r.set(c,U),U}async function l(c,m,p,d,g){try{let y=(await(await a(m,p,g)).listTools()).tools??[];d.setToolsForSource(m,"http",y),c.emit(`plugin:mcp:client:${m}:tools:listed`,{serverId:m,toolCount:y.length});}catch(h){r.delete(m),c.logger.warn({err:h,serverId:m,url:p,operation:"listTools"},"Failed to list tools from HTTP client");}}function u(c,m,p,d,g){let h=t.toolRefreshIntervalMs??6e4;if(h<=0)return;let f=setInterval(()=>{l(c,m,p,d,g);},h);o.push(f);}}var R=Symbol.for("routecraft.adapter.agent.registry");var Pt=0,Mt=1024,Rt=R.description??"routecraft.adapter.agent.registry",O=class{constructor(e){this.binding=e;}binding;adapterId="routecraft.adapter.agent";async send(e){let n=routecraft.getExchangeContext(e),r=this.resolveOptions(n),{config:o,modelName:i}=z(r.model,n),s=r.system,a=r.user!==void 0?G(r.user,e):J(e),l=await W({config:o,modelId:i,options:{temperature:Pt,maxTokens:Mt},systemPrompt:s,userPrompt:a}),u={text:l.text};return l.usage&&(u.usage=l.usage),u}resolveOptions(e){if(this.binding.kind==="inline")return this.binding.options;if(!e)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so the "${Rt}" store can be read.`});let n=e.getStore(R);if(!n)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found: no agents registered. Add agentPlugin({ agents: [defineAgent({ id: "${this.binding.name}", ... })] }) to your config.`});let r=n.get(this.binding.name);if(!r){let o=Array.from(n.keys()).join(", ")||"<none>";throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found in registry. Known agents: ${o}.`})}return r}getMetadata(e){let n=e,r={};if(this.binding.kind==="by-name"&&(r.agent=this.binding.name),this.binding.kind==="inline"){let o=this.binding.options.model;if(typeof o=="string")r.model=o;else {let i=o.modelId;r.model=i?`${o.provider}:${i}`:o.provider;}}return n.usage?.inputTokens!==void 0&&(r.inputTokens=n.usage.inputTokens),n.usage?.outputTokens!==void 0&&(r.outputTokens=n.usage.outputTokens),r}};function he(t){if(typeof t.system!="string"||t.system.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" is required and must be a non-empty string.'});if(typeof t.model=="string")try{$(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`Agent: "model" string must be in "providerId:modelName" form (e.g. ollama:llama3). Got: "${t.model}"`})}else if(t.model===null||typeof t.model!="object"||typeof t.model.provider!="string")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "model" must be either a "providerId:modelName" string or an LlmModelConfig object with a "provider" field.'})}function ae(t){if(typeof t=="string"){if(t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"Agent: name must be a non-empty string."});return routecraft.tagAdapter(new O({kind:"by-name",name:t}),ae,routecraft.factoryArgs(t))}return he(t),routecraft.tagAdapter(new O({kind:"inline",options:t}),ae,routecraft.factoryArgs(t))}function ye(t,e){if(e===null||typeof e!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" entry must be an object with description, schema, and handler.`});if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" is missing a non-empty "description".`});if(e.schema===null||typeof e.schema!="object"||typeof e.schema["~standard"]!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "schema" is required and must be a Standard Schema value (Zod/Valibot/ArkType/etc.).`});if(typeof e.schema["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "schema" must be a Standard Schema with a callable validate.`});if(typeof e.handler!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "handler" is required and must be a function.`})}var K=Symbol.for("routecraft.adapter.fn.registry");function Tt(t,e){if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${t}" is missing a non-empty "description". Registered agents carry their own description because they are not backed by a route.`});he(e);}function De(t={}){let e=t.agents??{},n=t.functions??{};return {apply(r){let o=r.getStore(R),i=o??new Map;for(let[l,u]of Object.entries(e)){if(l.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: agent id must be a non-empty string."});if(u===null||typeof u!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${l}" entry must be an object with description, model, and system.`});if(Tt(l,u),i.has(l))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate agent id "${l}". Each agent id must be unique within a context.`});i.set(l,u);}o||r.setStore(R,i);let s=r.getStore(K),a=s??new Map;for(let[l,u]of Object.entries(n)){if(l.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: fn id must be a non-empty string."});if(u===null||typeof u!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${l}" entry must be an object with description, schema, and handler.`});if(ye(l,u),a.has(l))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate fn id "${l}". Each fn id must be unique within a context.`});a.set(l,u);}s||r.setStore(K,a);}}}var pe=new Map;async function le(){let t=[...pe.entries()];pe.clear(),t.length!==0&&await Promise.all(t.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function Et(t){return t.includes("/")?t:`Xenova/${t}`}var At='The Hugging Face embedding provider requires "@huggingface/transformers". Install it with: pnpm add @huggingface/transformers';function Ot(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 bt(t){let e=Et(t),n=pe.get(e);if(n)return n.run;let r;try{r=(await import('@huggingface/transformers')).pipeline;}catch(a){throw Ot(a,"@huggingface/transformers")?new Error(At):a}let o=await r("feature-extraction",e,{dtype:"fp32"}),i=(a,l)=>o(a,{pooling:l?.pooling??"mean",normalize:l?.normalize??true}),s={run:i,dispose:typeof o.dispose=="function"?()=>Promise.resolve(o.dispose()):void 0};return pe.set(e,s),i}function Ue(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 Ct(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}: ${Ue(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof t}: ${Ue(t)}`)}async function Ne(t){let{config:e,modelName:n,text:r}=t;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 bt(n))(r,{pooling:"mean",normalize:true}),s=i&&typeof i=="object"&&"data"in i?i.data:i;return Ct(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 ce=Symbol.for("routecraft.adapter.embedding.providers"),de=Symbol.for("routecraft.adapter.embedding.options");function xt(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 kt(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(ce);if(!n)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:r,modelName:o}=xt(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 Lt(t){return e=>{let n=t(e);return Array.isArray(n)?n.filter(Boolean).join(" | "):n}}var D=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(de),...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=kt(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 a=Lt(i.using)(e);return {embedding:await Ne({config:r,modelName:o,text:a})}}};function je(t,e){return new D(t,e)}function It(t,e){return {...e,provider:t}}function He(t={providers:{}}){return {apply(e){let n=new Map;for(let[r,o]of Object.entries(t.providers))o!==void 0&&n.set(r,It(r,o));e.setStore(ce,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(de,t.defaultOptions);},async teardown(){await le();}}}
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_AGENT_REGISTRY=R;exports.ADAPTER_FN_REGISTRY=K;exports.ADAPTER_LLM_OPTIONS=C;exports.ADAPTER_LLM_PROVIDERS=E;exports.ADAPTER_MCP_CLIENT_SERVERS=v;exports.AgentDestinationAdapter=O;exports.BRAND=ve;exports.BRAND_MCP_ADAPTER=A;exports.EmbeddingDestinationAdapter=D;exports.LlmDestinationAdapter=S;exports.MCP_LOCAL_TOOL_REGISTRY=P;exports.MCP_PLUGIN_REGISTERED=x;exports.MCP_STDIO_MANAGERS=k;exports.MCP_TOOL_REGISTRY=X;exports.McpHeadersKeys=Z;exports.McpServer=I;exports.McpToolRegistry=_;exports.agent=ae;exports.agentPlugin=De;exports.defaultArgs=oe;exports.disposeEmbeddingPipelineCache=le;exports.embedding=je;exports.embeddingPlugin=He;exports.isMcpAdapter=$e;exports.isOAuthAuth=Q;exports.llm=Re;exports.llmPlugin=Ee;exports.mcp=V;exports.mcpPlugin=Le;exports.oauth=Oe;exports.validateLlmPluginOptions=Y;exports.validateWithSchema=xe;//# sourceMappingURL=index.cjs.map
1
+ 'use strict';var routecraft=require('@routecraft/routecraft'),ai=require('ai'),async_hooks=require('async_hooks'),http=require('http'),crypto$1=require('crypto');var Oe={McpAdapter:Symbol.for("routecraft.ai.McpAdapter")};function rt(t,e){return typeof t=="object"&&t!==null&&t[e]===true}function ot(t){return rt(t,Oe.McpAdapter)}function B(t,e){throw new Error(`The ${e} LLM provider requires the "${t}" package. Install it with: pnpm add ${t}`)}function K(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 it={ollama:{baseURL:"http://localhost:11434/api"}};function W(t){return {...t.inputTokens!==void 0&&{inputTokens:t.inputTokens},...t.outputTokens!==void 0&&{outputTokens:t.outputTokens},...t.totalTokens!==void 0&&{totalTokens:t.totalTokens}}}function z(t){try{if("output"in t&&t.output!==void 0)return t.output}catch{}}function be(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 ne(t){let{config:e,modelId:n,options:r,systemPrompt:o,userPrompt:i,output:s}=t;switch(e.provider){case "openai":return st(e,n,r,o,i,s);case "anthropic":return at(e,n,r,o,i,s);case "gemini":return pt(e,n,r,o,i,s);case "openrouter":return lt(e,n,r,o,i,s);case "ollama":return dt(e,n,r,o,i,s);default:{let p=e;throw new Error(`LLM provider not implemented: ${p.provider}`)}}}async function st(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/openai')).createOpenAI;}catch(f){throw K(f,"@ai-sdk/openai")&&B("@ai-sdk/openai","OpenAI"),f}let{generateText:p}=await import('ai'),d={apiKey:t.apiKey};t.baseURL!==void 0&&(d.baseURL=t.baseURL);let m={model:s(d)(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(m.system=r),n.topP!==void 0&&(m.topP=n.topP),n.frequencyPenalty!==void 0&&(m.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(m.presencePenalty=n.presencePenalty);let l=i!==void 0?{...m,output:i}:m,u=await p(l),g={text:u.text??"",raw:u};u.usage&&(g.usage=W(u.usage));let h=z(u);return h!==void 0&&(g.output=h),g}async function at(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/anthropic')).createAnthropic;}catch(h){throw K(h,"@ai-sdk/anthropic")&&B("@ai-sdk/anthropic","Anthropic"),h}let{generateText:p}=await import('ai'),a={model:s({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(a.system=r),n.topP!==void 0&&(a.topP=n.topP),n.frequencyPenalty!==void 0&&(a.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(a.presencePenalty=n.presencePenalty);let m=i!==void 0?{...a,output:i}:a,l=await p(m),u={text:l.text??"",raw:l};l.usage&&(u.usage=W(l.usage));let g=z(l);return g!==void 0&&(u.output=g),u}async function pt(t,e,n,r,o,i){let s;try{s=(await import('@ai-sdk/google')).createGoogleGenerativeAI;}catch(h){throw K(h,"@ai-sdk/google")&&B("@ai-sdk/google","Gemini"),h}let{generateText:p}=await import('ai'),a={model:s({apiKey:t.apiKey})(e),prompt:o,...n.maxTokens!==void 0&&{maxOutputTokens:n.maxTokens},temperature:n.temperature};r&&(a.system=r),n.topP!==void 0&&(a.topP=n.topP),n.frequencyPenalty!==void 0&&(a.frequencyPenalty=n.frequencyPenalty),n.presencePenalty!==void 0&&(a.presencePenalty=n.presencePenalty);let m=i!==void 0?{...a,output:i}:a,l=await p(m),u={text:l.text??"",raw:l};l.usage&&(u.usage=W(l.usage));let g=z(l);return g!==void 0&&(u.output=g),u}async function lt(t,e,n,r,o,i){let s;try{s=(await import('@openrouter/ai-sdk-provider')).createOpenRouter;}catch(y){throw K(y,"@openrouter/ai-sdk-provider")&&B("@openrouter/ai-sdk-provider","OpenRouter"),y}let{generateText:p}=await import('ai'),d=s({apiKey:t.apiKey}),c=t.modelId??e,a=d.chat(c);be(a,"OpenRouter",c);let l={model:a,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 u=i!==void 0?{...l,output:i}:l,g=await p(u),h={text:g.text??"",raw:g};g.usage&&(h.usage=W(g.usage));let f=z(g);return f!==void 0&&(h.output=f),h}async function dt(t,e,n,r,o,i){let s;try{s=(await import('ollama-ai-provider-v2')).createOllama;}catch(y){throw K(y,"ollama-ai-provider-v2")&&B("ollama-ai-provider-v2","Ollama"),y}let{generateText:p}=await import('ai'),d=s({baseURL:t.baseURL??it.ollama.baseURL}),c=t.modelId??e,a=d(c);be(a,"Ollama",c);let l={model:a,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 u=i!==void 0?{...l,output:i}:l,g=await p(u),h={text:g.text??"",raw:g};g.usage&&(h.usage=W(g.usage));let f=z(g);return f!==void 0&&(h.output=f),h}var O=Symbol.for("routecraft.adapter.llm.providers"),D=Symbol.for("routecraft.adapter.llm.options");function Y(t){let e=t.indexOf(":");if(e<1||e===t.length-1)throw new Error(`LLM 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 re(t,e){if(typeof t!="string"){let s=t.modelId??"";if(s.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`LLM model: inline LlmModelConfig for provider "${t.provider}" did not resolve to a model name. Either pass the model as a "providerId:modelName" string (e.g. "${t.provider}:<model>") or set "modelId" on the config. Providers "openai", "anthropic", and "gemini" do not carry a modelId field, so those must use the string form.`});return {config:t,modelName:s}}if(!e)throw new Error(`LLM model id "${t}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so store "${O.description}" can be read.`);let n=e.getStore(O);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}=Y(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}}function J(t,e){return t===void 0||t===""?"":typeof t=="function"?t(e):t}function oe(t){let e=t.body;return typeof e=="string"?e:e==null?"":typeof e=="object"?JSON.stringify(e):String(e)}function xe(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 s;try{s=e.validate(i);}catch(d){return {success:false,error:d instanceof Error?d:new Error(String(d))}}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(n,{validate:r});return ai.Output.object({schema:o})}async function ht(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 yt=0,wt=1024,U=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.llm";options;mergedOptions(e){let n=e.getStore(D);return {temperature:yt,maxTokens:wt,...n,...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=re(this.modelId,n),i=this.mergedOptions(n),s=J(i.systemPrompt,e),p=J(i.userPrompt,e)||oe(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 c=i.outputSchema!==void 0?xe(i.outputSchema):void 0,a=await ne({config:r,modelId:o,options:d,systemPrompt:s,userPrompt:p,output:c});if(a.output===void 0&&a.text&&i.outputSchema!==void 0){let m=await ht(a.text,i.outputSchema);m!==void 0&&(a.output=m);}return a}getMetadata(e){let n=e,{providerId:r}=Y(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 ke(t,e){return new U(t,e)}var Le=["openai","anthropic","openrouter","ollama","gemini"];function vt(t){return Le.includes(t)}function ie(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(!vt(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 Tt=["openai","anthropic","openrouter","ollama","gemini"];function Pt(t,e){return {provider:t,...e}}function Ie(t={providers:{}}){return ie(t),{apply(e){let n=new Map;for(let r of Tt){let o=t.providers[r];o!==void 0&&n.set(r,Pt(r,o));}e.setStore(O,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(D,t.defaultOptions);}}}var N=Symbol.for("routecraft.mcp.plugin.registered"),P=Symbol.for("routecraft.mcp.client.servers"),se=Symbol.for("routecraft.mcp.tool.registry"),F=Symbol.for("routecraft.mcp.stdio.managers"),R=Symbol.for("routecraft.mcp.local-tool-registry"),ae=(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))(ae||{});function pe(t){return "provider"in t&&t.provider==="oauth"}var b=Symbol.for("routecraft.mcp.adapter");var Rt=/^[A-Za-z0-9_-]{1,64}$/;function Mt(t){if(!Rt.test(t))throw routecraft.rcError("RC5003",void 0,{message:`Invalid MCP tool name "${t}"`,suggestion:"MCP tool names must match /^[A-Za-z0-9_-]{1,64}$/ for client interoperability (OpenAI, Anthropic, etc.). Use alphanumerics, underscore, or hyphen in the route's .id()."})}var de=class{adapterId="routecraft.adapter.mcp";options;constructor(e={}){this[b]=true,this.options=e;}async subscribe(e,n,r,o,i){if(!i?.routeId)throw routecraft.rcError("RC5003",void 0,{message:"McpSourceAdapter requires a route id from the engine (missing SourceMeta.routeId)",suggestion:"MCP source adapters take their tool name from the route id. Call .id('tool-name') on the route before .from(mcp(...))."});let s=i.routeId;Mt(s);let p=i.discovery,d=p?.description;if(typeof d!="string"||d.length===0)throw routecraft.rcError("RC5003",void 0,{message:`MCP route "${s}" requires a description`,suggestion:"Set .description('...') on the route builder before .from(mcp()); the MCP protocol requires a non-empty description for each tool."});if(e.getStore(N)!==true)throw new Error("MCP plugin required: routes using .from(mcp(...)) require the MCP plugin. Add mcpPlugin() to your config: plugins: [mcpPlugin()].");let a=e.getStore(R);if(a||(a=new Map,e.setStore(R,a)),a.has(s))throw routecraft.rcError("RC5003",void 0,{message:`Duplicate MCP tool endpoint "${s}": another .from(mcp(...)) route already registered this endpoint in the same context`,suggestion:"Each MCP tool endpoint must be unique within a context. Rename one of the mcp() routes to a different route id."});let l={endpoint:s,description:d,handler:async u=>n(u.body,u.headers)};p?.title!==void 0&&(l.title=p.title),p?.input!==void 0&&(l.input=p.input),p?.output!==void 0&&(l.output=p.output),this.options.annotations!==void 0&&(l.annotations=this.options.annotations),this.options.icons!==void 0&&(l.icons=this.options.icons),r.signal.addEventListener("abort",()=>{e.getStore(R)?.delete(s);},{once:true}),!r.signal.aborted&&(a.set(s,l),o?.(),await new Promise(u=>{if(r.signal.aborted){u();return}r.signal.addEventListener("abort",()=>u(),{once:true});}));}};function ce(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 _e=new WeakMap;async function Et(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=(_e.get(t)??0)%t.length;return _e.set(t,e+1),t[e]}return t}async function ue(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 Et(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 St(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 At(t,e){return !t.serverId||!e?void 0:e.getStore(P)?.get(t.serverId)}function Ot(t,e){if(t.url)return St(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(P)}" can be read.`);if(t.serverId&&e){let n=At(t,e);if(!n)throw new Error(`MCP client: serverId "${t.serverId}" not found in context store. Register it with context store key "${String(P)}".`);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 me=t=>typeof t.body=="object"&&t.body!==null?t.body:{input:t.body},X=class{constructor(e){this.options=e;if(this[b]=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 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??me)(e);if(this.options.serverId&&n){let a=n.getStore(F)?.get(this.options.serverId);if(a){let u=await a.callTool(r,i);return u&&typeof u=="object"&&(u.metadata={toolName:r,transport:"stdio",serverId:this.options.serverId}),u}let l=n.getStore(P)?.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:p}=Ot(this.options,n),d=await this.callRemoteTool(s,r,i,p);return d&&typeof d=="object"&&(d.metadata={toolName:r,url:s,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,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 p=i.Client,d=s.StreamableHTTPClientTransport,c=new URL(e),a=await ue(o),m=a?{requestInit:{headers:a}}:void 0,l=new d(c,m),u={name:"routecraft-mcp-client",version:"1.0.0"},g=new p(u,{capabilities:{}});try{await g.connect.call(g,l);let y=await g.callTool.call(g,{name:n,arguments:r});return ce(y)}finally{let h=g,f=h.close??h.disconnect;if(typeof f=="function")try{await Promise.resolve(f.call(g));}catch{}let y=l,C=y.close??y.destroy;if(typeof C=="function")try{await Promise.resolve(C.call(l));}catch{}}}};function Z(t,e){if(typeof t=="object"&&t!==null&&("url"in t||"serverId"in t)){let n=t;if(typeof n.auth?.token=="string"&&n.auth.token.trim().length===0)throw new TypeError("mcp(): auth.token must be a non-empty string when provided");if(Array.isArray(n.auth?.token)){if(n.auth.token.length===0)throw new TypeError("mcp(): auth.token array must not be empty");for(let r=0;r<n.auth.token.length;r++){let o=n.auth.token[r];if(typeof o!="string"||o.trim().length===0)throw new TypeError(`mcp(): auth.token[${r}] must be a non-empty string`)}}return routecraft.tagAdapter(new X(n),Z,routecraft.factoryArgs(t,e))}if(typeof t=="string"&&t.includes(":")){let n=t.indexOf(":"),r=t.slice(0,n),o=t.slice(n+1),i={serverId:r,tool:o};return e!==void 0&&typeof e=="object"&&"args"in e&&e.args!==void 0&&(i.args=e.args),routecraft.tagAdapter(new X(i),Z,routecraft.factoryArgs(t,e))}if(typeof t=="string")throw routecraft.rcError("RC5003",void 0,{message:`mcp(${JSON.stringify(t)}) is not a valid call: a bare string without ":" is neither a client shorthand nor source options`,suggestion:"Use .from(mcp()) for a source (tool name comes from .id()), .to(mcp({ url, tool })) for a remote server, .to(mcp('server:tool')) for a registered shorthand, or direct('name') for in-process dispatch."});return routecraft.tagAdapter(new de(t??{}),Z,routecraft.factoryArgs(t,e))}function xt(t){if(typeof t=="function")return async n=>t(n);let e=t;return async n=>n===e.client_id?e:void 0}function kt(t){if(!t)throw new TypeError("oauth: `verify` is required. Pass jwks(...), jwt(...), or a custom (token) => OAuthPrincipal function.");return typeof t=="function"?async e=>t(e):async e=>t.validator(e)}function De(t){if(new URL(t.resourceIssuerUrl.toString()).protocol!=="https:"&&process.env.NODE_ENV==="production")throw new TypeError("oauth: resourceIssuerUrl must use HTTPS in production");let n=kt(t.verify),r=xt(t.client);return {provider:"oauth",resourceIssuerUrl:t.resourceIssuerUrl,endpoints:t.endpoints,verifyAccessToken:n,getClient:r,...t.baseUrl!==void 0&&{baseUrl:t.baseUrl},...t.scopesSupported!==void 0&&{scopesSupported:t.scopesSupported},...t.requiredScopes!==void 0&&{requiredScopes:t.requiredScopes},...t.serviceDocumentationUrl!==void 0&&{serviceDocumentationUrl:t.serviceDocumentationUrl},...t.resourceName!==void 0&&{resourceName:t.resourceName}}}var Ne=new async_hooks.AsyncLocalStorage,Me='MCP server requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',$=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(Me)}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(){this.options.auth&&pe(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(Me)}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,n){let r=new e({name:this.options.name,version:this.options.version},{capabilities:{tools:{}}});await this.setupRequestHandlersOn(r);let o=new n({sessionIdGenerator:()=>crypto.randomUUID(),onsessioninitialized:c=>{this.httpSessions.set(c,{server:r,transport:o}),this.context.logger.debug({sessionId:c},"MCP session created"),this.context.emit("plugin:mcp:session:created",{sessionId:c});},enableJsonResponse:true});await r.connect(o);let s=o,p=s.onclose;s.onclose=()=>{let c=o.sessionId;c&&(this.httpSessions.delete(c),this.context.logger.debug({sessionId:c},"MCP session closed"),this.context.emit("plugin:mcp:session:closed",{sessionId:c})),p?.();};let d=o.handleRequest;if(typeof d!="function")throw new Error("StreamableHTTPServerTransport.handleRequest not found - SDK may have changed");return {transport:o,handleRequest:d.bind(o)}}async handleMcpRequest(e,n,r,o){let i=e.headers["mcp-session-id"],s=p=>Ne.run(r,p);try{if(i&&this.httpSessions.has(i)){let p=this.httpSessions.get(i),d=p.transport.handleRequest;await s(()=>d.call(p.transport,e,n));}else if(!i||e.method==="POST"){let{handleRequest:p}=await o();await s(()=>p(e,n));}else n.writeHead(404,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Session not found"}));}catch(p){let d=routecraft.isRoutecraftError(p)?p.meta.message:p instanceof Error?p.message:"MCP HTTP request error";this.context.logger.error({err:p},d),n.headersSent||(n.writeHead(500,{"Content-Type":"application/json"}),n.end(JSON.stringify({error:"Internal Server Error"})));}}async startHttpWithValidator(){let{ServerCtor:e,TransportClass:n}=await this.importSdkHttp(),r=this.options.port,o=this.options.host,i=()=>this.createSession(e,n);this.httpServer=http.createServer(async(s,p)=>{let d=s.url?.split("?")[0]??"";if(d!=="/mcp"&&d!=="/mcp/"){p.writeHead(404,{"Content-Type":"application/json"}),p.end(JSON.stringify({error:"Not Found",path:d}));return}let c;if(this.options.auth){let a=await this.validateAuth(s);if(!a){p.writeHead(401,{"Content-Type":"application/json","WWW-Authenticate":'Bearer realm="mcp"'}),p.end(JSON.stringify({error:"Unauthorized"}));return}c=a;}await this.handleMcpRequest(s,p,c,i);}),await this.listenHttp(r,o);}async startHttpWithOAuth(e){let{ServerCtor:n,TransportClass:r}=await this.importSdkHttp(),o,i,s,p;try{let f=await import('express');o=f.default??f;}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,p=(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 d=async f=>{let y;try{y=await e.verifyAccessToken(f);}catch(w){let A={reason:w instanceof Error?w.message:"invalid_token",scheme:"bearer",source:"mcp",path:"oauth"};throw this.context.logger.warn({err:w,...A},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",A),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:f,clientId:y.clientId??y.subject,scopes:y.scopes??[],expiresAt:y.expiresAt,extra:{principal:y}}},c=new p({endpoints:{authorizationUrl:e.endpoints.authorizationUrl,tokenUrl:e.endpoints.tokenUrl,revocationUrl:e.endpoints.revocationUrl,registrationUrl:e.endpoints.registrationUrl},verifyAccessToken:d,getClient:e.getClient}),a=this.options.port,m=this.options.host,l=o(),u={provider:c,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 g={verifier:c};e.requiredScopes&&(g.requiredScopes=e.requiredScopes),l.use("/mcp",s(g));let h=()=>this.createSession(n,r);l.all("/mcp",async(f,y)=>{let C=f,w=y,V=f.auth,A=this.authInfoToPrincipal(V);if(A){let Ae={subject:A.subject,scheme:A.scheme,source:"mcp"};this.context.logger.info(Ae,"Auth succeeded"),this.context.emit("auth:success",Ae);}await this.handleMcpRequest(C,w,A,h);}),this.httpServer=http.createServer(l),await this.listenHttp(a,m);}async listenHttp(e,n){await new Promise((i,s)=>{this.httpServer.listen(e,n,()=>i()),this.httpServer.on("error",p=>{let d=routecraft.isRoutecraftError(p)?p.meta.message:p instanceof Error?p.message:"MCP HTTP server listen failed";this.context.logger.error({err:p},d),s(p);});});let r=this.getHttpPort()??e,o={host:n,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 n=e.extra?.principal;if(n)return n;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 n=this.options.auth;if(!n||!("validator"in n))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 n.validator(i),p={subject:s.subject,scheme:s.scheme,source:"mcp"};return this.context.logger.info(p,"Auth succeeded"),this.context.emit("auth:success",p),s}catch(s){let d={reason:s instanceof Error?s.message:"invalid_token",scheme:"bearer",source:"mcp"};return this.context.logger.warn({err:s,...d},"Auth rejected: token validation failed"),this.context.emit("auth:rejected",d),null}}async setupRequestHandlers(){await this.setupRequestHandlersOn(this.server);}async setupRequestHandlersOn(e){let n;try{n=await import('@modelcontextprotocol/sdk/types.js');}catch{throw new Error(Me)}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 s=e;s.setRequestHandler(o,async()=>{let p=this.getAvailableTools();return this.logExposedToolsOnce(),{tools:p}}),s.setRequestHandler(i,async p=>{let c=p.params;return await this.handleToolCall(c.name||"",c.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(R);if(!e)return [];let n=Array.from(e.values()),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.entryToMcpTool(o))}entryToMcpTool(e){let n={name:e.endpoint,description:e.description,inputSchema:this.schemaToJsonSchema(e.input?.body)};return e.title!==void 0&&(n.title=e.title),e.output?.body!==void 0&&(n.outputSchema=this.schemaToJsonSchema(e.output.body)),e.annotations!==void 0&&(n.annotations=e.annotations),e.icons!==void 0&&(n.icons=e.icons),n}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 o=this.context.getStore(R)?.get(e);if(!o){let m=new Error(`Tool not found: ${e}`);return this.context.emit("plugin:mcp:tool:failed",{tool:e,error:m.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 s=Ne.getStore(),p={"routecraft.mcp.tool":e,"routecraft.mcp.session":`mcp-${Date.now()}`};s&&(p["routecraft.auth.subject"]=s.subject,p["routecraft.auth.scheme"]=s.scheme,p["routecraft.auth.kind"]=s.kind,s.name&&(p["routecraft.auth.name"]=s.name),s.email&&(p["routecraft.auth.email"]=s.email),s.roles&&(p["routecraft.auth.roles"]=s.roles),s.scopes&&(p["routecraft.auth.scopes"]=s.scopes),s.issuer&&(p["routecraft.auth.issuer"]=s.issuer),s.audience&&(p["routecraft.auth.audience"]=s.audience),s.clientId&&(p["routecraft.auth.client_id"]=s.clientId));let d=new routecraft.DefaultExchange(this.context,{body:i,headers:p});this.context.emit("plugin:mcp:tool:called",{tool:e,args:n});let c=await o.handler(d),a=typeof c.body=="string"?c.body:JSON.stringify(c.body);return this.context.emit("plugin:mcp:tool:completed",{tool:e}),{content:[{type:"text",text:a}]}}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 Fe(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)if("provider"in t.auth){if(t.auth.provider!=="oauth")throw new TypeError('mcpPlugin: auth.provider must be "oauth". Use the oauth() helper.')}else if("validator"in t.auth){if(typeof t.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(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 je(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 Dt='MCP stdio client requires "@modelcontextprotocol/sdk". Install it with: pnpm add @modelcontextprotocol/sdk',ge=class{constructor(e,n,r,o){this.options=e;this.logger=n;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,n;try{e=await import('@modelcontextprotocol/sdk/client/index.js'),n=await import('@modelcontextprotocol/sdk/client/stdio.js');}catch{throw new Error(Dt)}let{serverId:r,command:o,args:i,env:s,cwd:p}=this.options;this.transport=new n.StdioClientTransport({command:o,args:i??[],...s?{env:s}:{},...p?{cwd:p}:{},stderr:"pipe"});let d=this.transport;d.onerror=c=>{this.logger.error({err:c,serverId:r},"Stdio client transport error"),this.onEvent(`plugin:mcp:client:${r}:error`,{serverId:r,error:c});},d.onclose=()=>{this.stopping||(this.running=false,this.handleDisconnect());},d.stderr?.on&&d.stderr.on("data",c=>{this.logger.debug({serverId:r,stderr:String(c).trimEnd()},"Stdio client stderr output");}),this.client=new e.Client({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{},listChanged:{tools:{onChanged:(c,a)=>{a&&Array.isArray(a.tools)?(this.tools=a.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 ce(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 H=class{tools=new Map;setToolsForSource(e,n,r){let o=new Map;for(let i of r){let s={name:i.name,inputSchema:i.inputSchema,source:e,transport:n};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 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 $e(t){return "transport"in t&&t.transport==="stdio"}function He(t={}){Fe(t);let e=null,n=new Map,r=new Map,o=[],i=null;return {async apply(a){if(a.setStore(N,true),i=new H,a.setStore(se,i),a.setStore(F,n),t.clients&&Object.keys(t.clients).length>0){let m=Object.entries(t.clients),l=new Map;for(let[u,g]of m)l.set(u,g);a.setStore(P,l);for(let[u,g]of m){if($e(g))await s(a,u,g,i);else {let f=g;await d(a,u,f.url,i,f.auth),c(a,u,f.url,i,f.auth);}let h=$e(g)?"stdio":"http";a.emit(`plugin:mcp:client:${u}:registered`,{serverId:u,transport:h});}}e=new $(a,t),await e.start();},async teardown(a){for(let m of o)clearInterval(m);o.length=0;for(let[m,l]of r)try{await l.close();}catch(u){a.logger.error({err:u,serverId:m,operation:"close"},"Failed to close HTTP client");}r.clear();for(let[m,l]of n)try{await l.stop();}catch(u){a.logger.error({err:u,serverId:m,operation:"stop"},"Failed to stop stdio client");}if(n.clear(),e){try{await e.stop();}catch(m){a.logger.error({err:m,operation:"stop"},"Failed to stop MCP server plugin");}e=null;}i=null;}};async function s(a,m,l,u){let g={serverId:m,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 h=new ge(g,a.logger,(f,y)=>{a.emit(f,y);},(f,y)=>{u.setToolsForSource(f,"stdio",y);});n.set(m,h);try{await h.start();}catch(f){a.logger.error({err:f,serverId:m,operation:"start"},"Failed to start stdio client"),a.emit(`plugin:mcp:client:${m}:error`,{serverId:m,error:f});}}async function p(a,m,l){let u=r.get(a);if(u)return u;let{Client:g}=await import('@modelcontextprotocol/sdk/client/index.js'),{StreamableHTTPClientTransport:h}=await import('@modelcontextprotocol/sdk/client/streamableHttp.js'),f=await ue(l),y=f?{requestInit:{headers:f}}:void 0,C=new h(new URL(m),y),w=new g({name:"routecraft-mcp-client",version:"1.0.0"},{capabilities:{}});await w.connect(C);let V=w;return r.set(a,V),V}async function d(a,m,l,u,g){try{let y=(await(await p(m,l,g)).listTools()).tools??[];u.setToolsForSource(m,"http",y),a.emit(`plugin:mcp:client:${m}:tools:listed`,{serverId:m,toolCount:y.length});}catch(h){r.delete(m),a.logger.warn({err:h,serverId:m,url:l,operation:"listTools"},"Failed to list tools from HTTP client");}}function c(a,m,l,u,g){let h=t.toolRefreshIntervalMs??6e4;if(h<=0)return;let f=setInterval(()=>{d(a,m,l,u,g);},h);o.push(f);}}var S=Symbol.for("routecraft.adapter.agent.registry"),Q=Symbol.for("routecraft.adapter.tools.default");var Nt=0,Ft=1024,jt=S.description??"routecraft.adapter.agent.registry",x=class{constructor(e){this.binding=e;}binding;adapterId="routecraft.adapter.agent";async send(e){let n=routecraft.getExchangeContext(e),r=this.resolveOptions(n),{config:o,modelName:i}=re(r.model,n),s=r.system,p=r.user!==void 0?J(r.user,e):oe(e),d=await ne({config:o,modelId:i,options:{temperature:Nt,maxTokens:Ft},systemPrompt:s,userPrompt:p}),c={text:d.text};return d.usage&&(c.usage=d.usage),c}resolveOptions(e){if(this.binding.kind==="inline")return this.binding.options;if(!e)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" requires a context to resolve. Ensure the exchange has context (e.g. from a route) so the "${jt}" store can be read.`});let n=e.getStore(S);if(!n)throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found: no agents registered. Add agentPlugin({ agents: [defineAgent({ id: "${this.binding.name}", ... })] }) to your config.`});let r=n.get(this.binding.name);if(!r){let o=Array.from(n.keys()).join(", ")||"<none>";throw routecraft.rcError("RC5004",void 0,{message:`Agent "${this.binding.name}" not found in registry. Known agents: ${o}.`})}return r}getMetadata(e){let n=e,r={};if(this.binding.kind==="by-name"&&(r.agent=this.binding.name),this.binding.kind==="inline"){let o=this.binding.options.model;if(typeof o=="string")r.model=o;else {let i=o.modelId;r.model=i?`${o.provider}:${i}`:o.provider;}}return n.usage?.inputTokens!==void 0&&(r.inputTokens=n.usage.inputTokens),n.usage?.outputTokens!==void 0&&(r.outputTokens=n.usage.outputTokens),r}};var M=Symbol.for("routecraft.adapter.fn.registry");var k=Symbol.for("routecraft.ai.fn.deferred");function L(t){return typeof t=="object"&&t!==null&&k in t&&t[k]===true}var qe={"~standard":{version:1,vendor:"routecraft",validate(t){return t===null||typeof t!="object"||Array.isArray(t)||Object.keys(t).length>0?{issues:[{message:"Expected an empty object {}."}]}:{value:{}}}}};function ee(t,e){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"directTool: routeId must be a non-empty string."});let n=Bt(e?.tags,t);return {[k]:true,kind:"direct",targetId:t,...n!==void 0?{overrideTags:n}:{},resolve(r,o){let i=Kt(r,t,o),s=e?.description??i.description;if(typeof s!="string"||s.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .description() and no override was provided (referenced as fn "${o}").`});let p=e?.schema??i.input?.body;if(!p)throw routecraft.rcError("RC5003",void 0,{message:`directTool: route "${t}" has no .input(...) schema and no override was provided (referenced as fn "${o}").`});let d=n??i.tags,c=((a,m)=>Wt(m,t,a));return {description:s,schema:p,...d&&d.length>0?{tags:[...d]}:{},handler:c}}}}function Bt(t,e){if(t===void 0)return;if(!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:`directTool("${e}"): override "tags" must be an array of non-empty strings.`});let n=[];for(let r of t){if(typeof r!="string"||r.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`directTool("${e}"): override "tags" must contain only non-empty strings.`});let o=r.trim();n.includes(o)||n.push(o);}return n}function Kt(t,e,n){let r=t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY),o=routecraft.sanitizeEndpoint(e),i=r?.get(o);if(!i){let s=r?[...r.keys()].sort():[];throw routecraft.rcError("RC5003",void 0,{message:`directTool: unknown direct route id "${e}" (referenced as fn "${n}"). `+(s.length>0?`Known route ids: ${s.join(", ")}.`:"No direct routes are registered in this context.")})}return i}async function Wt(t,e,n){if(!t.context)throw routecraft.rcError("RC5003",void 0,{message:`directTool: no CraftContext available on the handler context (cannot dispatch to direct route "${e}").`});let r=routecraft.sanitizeEndpoint(e),o=t.correlationId?{[routecraft.HeadersKeys.CORRELATION_ID]:t.correlationId}:void 0,i=new routecraft.DefaultExchange(t.context,{body:n,...o?{headers:o}:{}});return (await routecraft.getDirectChannel(t.context,r,{}).send(r,i)).body}function Ve(t,e){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentTool: agentId must be a non-empty string."});return {[k]:true,kind:"agent",targetId:t,resolve(n,r){throw routecraft.rcError("RC5003",void 0,{message:`agentTool("${t}") (referenced as fn "${r}") is not yet supported. Sub-agent tools land in a follow-up story.`})}}}function Be(t,e,n){if(typeof t!="string"||t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"mcpTool: serverId must be a non-empty string."});if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"mcpTool: toolName must be a non-empty string."});return {[k]:true,kind:"mcp",targetId:`${t}:${e}`,resolve(r,o){throw routecraft.rcError("RC5003",void 0,{message:`mcpTool("${t}", "${e}") (referenced as fn "${o}") is not yet supported. MCP tools land in a follow-up story.`})}}}var Ke={currentTime:{description:"Returns the current UTC timestamp in ISO 8601 format.",schema:qe,handler:()=>new Date().toISOString(),tags:["read-only","idempotent"]},randomUuid:{description:"Generates a fresh random UUID v4.",schema:qe,handler:()=>crypto$1.randomUUID(),tags:["read-only"]}};var fe=Symbol.for("routecraft.ai.tools.selection");function I(t){return typeof t=="object"&&t!==null&&fe in t&&t[fe]===true}function ze(t){if(!Array.isArray(t))throw routecraft.rcError("RC5003",void 0,{message:"tools(items): items must be an array."});return {[fe]:true,resolve(e){let n=new Map;for(let o of t){if(typeof o=="string"){let i=We(e,o,void 0);n.set(i.name,i);continue}if(o===null||typeof o!="object")throw routecraft.rcError("RC5003",void 0,{message:"tools(): each item must be a string, { name, guard? }, or { tagged, guard? }."});if("name"in o){if(typeof o.name!="string"||o.name.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): { name } must be a non-empty string."});let i=We(e,o.name,o.guard);n.set(i.name,i);}else if(!("tagged"in o))throw routecraft.rcError("RC5003",void 0,{message:'tools(): each object item must include "name" or "tagged".'})}let r=new Map(n);for(let o of t)if(typeof o=="object"&&o!==null&&"tagged"in o){let i=Zt(o.tagged);if(i.length===0)continue;for(let s of Jt(e,i,o.guard))r.has(s.name)||r.set(s.name,s);}return [...r.values()]}}}function We(t,e,n){if(typeof e!="string"||e.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"tools(): tool name must be a non-empty string."});let o=t.getStore(M)?.get(e);if(o)return Yt(t,e,o,n);if(e.startsWith("agent_"))throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${e}" looks like an agent reference. Sub-agent tools land in a follow-up story.`});if(e.startsWith("mcp_"))throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${e}" looks like an MCP reference. MCP tools land in a follow-up story.`});if(e.startsWith("direct_")){let s=e.slice(7);if(s==="")throw routecraft.rcError("RC5003",void 0,{message:`tools(): "${e}" has an empty direct route id.`});let d=ee(s).resolve(t,e);return q(e,d,n)}let i=Qt(t);throw routecraft.rcError("RC5003",void 0,{message:`tools(): unknown tool "${e}". `+(i.length>0?`Available: ${i.join(", ")}.`:"No fns or direct routes are registered in this context.")})}function Yt(t,e,n,r){if(L(n)){let o=n.resolve(t,e);return q(e,o,r)}return q(e,n,r)}function q(t,e,n){return {name:t,description:e.description,schema:e.schema,...e.tags&&e.tags.length>0?{tags:e.tags}:{},...n?{guard:n}:{},handler:e.handler}}function Jt(t,e,n){let r=new Set(e),o=[],i=new Set,s=new Set,p=t.getStore(M);if(p)for(let[c,a]of p){if(L(a)){if(a.kind!=="direct"||!(a.overrideTags??Xt(t,a.targetId)).some(g=>r.has(g)))continue;let u=a.resolve(t,c);o.push(q(c,u,n)),i.add(c),s.add(a.targetId);continue}(a.tags??[]).some(l=>r.has(l))&&(o.push(q(c,a,n)),i.add(c));}let d=t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY);if(d)for(let[c,a]of d){if(s.has(c)||!(a.tags??[]).some(h=>r.has(h)))continue;let l=`direct_${c}`;if(i.has(l)||typeof a.description!="string"||a.description.trim()===""||!a.input?.body)continue;let g=ee(c).resolve(t,l);o.push(q(l,g,n)),i.add(l);}return o}function Xt(t,e){return t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY)?.get(routecraft.sanitizeEndpoint(e))?.tags??[]}function Zt(t){return (Array.isArray(t)?t:[t]).filter(e=>typeof e=="string"&&e.trim()!=="")}function Qt(t){let e=[...(t.getStore(M)??new Map).keys()],n=[...(t.getStore(routecraft.ADAPTER_DIRECT_REGISTRY)??new Map).keys()].map(r=>`direct_${r}`);return [...e,...n].sort()}function Se(t){if(typeof t.system!="string"||t.system.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "system" is required and must be a non-empty string.'});if(typeof t.model=="string")try{Y(t.model);}catch{throw routecraft.rcError("RC5003",void 0,{message:`Agent: "model" string must be in "providerId:modelName" form (e.g. ollama:llama3). Got: "${t.model}"`})}else if(t.model===null||typeof t.model!="object"||typeof t.model.provider!="string")throw routecraft.rcError("RC5003",void 0,{message:'Agent: "model" must be either a "providerId:modelName" string or an LlmModelConfig object with a "provider" field.'});if(t.tools!==void 0&&!I(t.tools))throw routecraft.rcError("RC5003",void 0,{message:'Agent: "tools" must be the result of tools([...]).'})}function he(t){if(typeof t=="string"){if(t.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"Agent: name must be a non-empty string."});return routecraft.tagAdapter(new x({kind:"by-name",name:t}),he,routecraft.factoryArgs(t))}return Se(t),routecraft.tagAdapter(new x({kind:"inline",options:t}),he,routecraft.factoryArgs(t))}function Xe(t,e){if(e===null||typeof e!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" entry must be an object with description, schema, and handler.`});if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" is missing a non-empty "description".`});if(e.schema===null||typeof e.schema!="object"||typeof e.schema["~standard"]!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "schema" is required and must be a Standard Schema value (Zod/Valibot/ArkType/etc.).`});if(typeof e.schema["~standard"]?.validate!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "schema" must be a Standard Schema with a callable validate.`});if(typeof e.handler!="function")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "handler" is required and must be a function.`});if(e.tags!==void 0){if(!Array.isArray(e.tags))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must be an array of non-empty strings.`});for(let r=0;r<e.tags.length;r++){let o=e.tags[r];if(typeof o!="string"||o.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${t}" "tags" must contain only non-empty strings.`});e.tags[r]=o.trim();}}}function en(t,e){if(typeof e.description!="string"||e.description.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${t}" is missing a non-empty "description". Registered agents carry their own description because they are not backed by a route.`});Se(e);}function Ze(t={}){let e=t.agents??{},n=t.functions??{},r=t.tools;if(r!==void 0&&!I(r))throw routecraft.rcError("RC5003",void 0,{message:'agentPlugin: "tools" must be the result of tools([...]).'});return {apply(o){let i=o.getStore(S),s=i??new Map;for(let[c,a]of Object.entries(e)){if(c.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: agent id must be a non-empty string."});if(a===null||typeof a!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${c}" entry must be an object with description, model, and system.`});if(a.tools!==void 0&&!I(a.tools))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: agent "${c}" "tools" must be the result of tools([...]).`});if(en(c,a),s.has(c))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate agent id "${c}". Each agent id must be unique within a context.`});s.set(c,a);}i||o.setStore(S,s);let p=o.getStore(M),d=p??new Map;for(let[c,a]of Object.entries(n)){if(c.trim()==="")throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: fn id must be a non-empty string."});if(a===null||typeof a!="object")throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: fn "${c}" entry must be an object with description, schema, and handler.`});if(L(a)||Xe(c,a),d.has(c))throw routecraft.rcError("RC5003",void 0,{message:`agentPlugin: duplicate fn id "${c}". Each fn id must be unique within a context.`});d.set(c,a);}if(p||o.setStore(M,d),r!==void 0){if(o.getStore(Q)!==void 0)throw routecraft.rcError("RC5003",void 0,{message:"agentPlugin: a default tool list is already set on this context. Combine selectors into a single tools([...]) call."});o.setStore(Q,r);}}}}var ye=new Map;async function we(){let t=[...ye.entries()];ye.clear(),t.length!==0&&await Promise.all(t.map(async([,e])=>{try{typeof e.dispose=="function"&&await e.dispose();}catch{}}));}function tn(t){return t.includes("/")?t:`Xenova/${t}`}var nn='The Hugging Face embedding provider requires "@huggingface/transformers". Install it with: pnpm add @huggingface/transformers';function rn(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 on(t){let e=tn(t),n=ye.get(e);if(n)return n.run;let r;try{r=(await import('@huggingface/transformers')).pipeline;}catch(p){throw rn(p,"@huggingface/transformers")?new Error(nn):p}let o=await r("feature-extraction",e,{dtype:"fp32"}),i=(p,d)=>o(p,{pooling:d?.pooling??"mean",normalize:d?.normalize??true}),s={run:i,dispose:typeof o.dispose=="function"?()=>Promise.resolve(o.dispose()):void 0};return ye.set(e,s),i}function Qe(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 sn(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}: ${Qe(e)}`)}throw new Error(`Embedding output must be an Array, Float32Array, or object with .data; got ${typeof t}: ${Qe(t)}`)}async function et(t){let{config:e,modelName:n,text:r}=t;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 on(n))(r,{pooling:"mean",normalize:true}),s=i&&typeof i=="object"&&"data"in i?i.data:i;return sn(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 ve=Symbol.for("routecraft.adapter.embedding.providers"),Te=Symbol.for("routecraft.adapter.embedding.options");function pn(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 ln(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(ve);if(!n)throw new Error("Embedding provider not found: no providers registered. Add embeddingPlugin({ providers: { huggingface: {} } }) to your config.");let{providerId:r,modelName:o}=pn(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 dn(t){return e=>{let n=t(e);return Array.isArray(n)?n.filter(Boolean).join(" | "):n}}var G=class{constructor(e,n={}){this.modelId=e;this.options=n;}modelId;adapterId="routecraft.adapter.embedding";options;mergedOptions(e){return {...e.getStore(Te),...this.options}}async send(e){let n=routecraft.getExchangeContext(e),{config:r,modelName:o}=ln(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 p=dn(i.using)(e);return {embedding:await et({config:r,modelName:o,text:p})}}};function tt(t,e){return new G(t,e)}function cn(t,e){return {...e,provider:t}}function nt(t={providers:{}}){return {apply(e){let n=new Map;for(let[r,o]of Object.entries(t.providers))o!==void 0&&n.set(r,cn(r,o));e.setStore(ve,n),t.defaultOptions&&Object.keys(t.defaultOptions).length>0&&e.setStore(Te,t.defaultOptions);},async teardown(){await we();}}}
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_AGENT_REGISTRY=S;exports.ADAPTER_FN_REGISTRY=M;exports.ADAPTER_LLM_OPTIONS=D;exports.ADAPTER_LLM_PROVIDERS=O;exports.ADAPTER_MCP_CLIENT_SERVERS=P;exports.ADAPTER_TOOLS_DEFAULT=Q;exports.AgentDestinationAdapter=x;exports.BRAND=Oe;exports.BRAND_MCP_ADAPTER=b;exports.EmbeddingDestinationAdapter=G;exports.LlmDestinationAdapter=U;exports.MCP_LOCAL_TOOL_REGISTRY=R;exports.MCP_PLUGIN_REGISTERED=N;exports.MCP_STDIO_MANAGERS=F;exports.MCP_TOOL_REGISTRY=se;exports.McpHeadersKeys=ae;exports.McpServer=$;exports.McpToolRegistry=H;exports.agent=he;exports.agentPlugin=Ze;exports.agentTool=Ve;exports.defaultArgs=me;exports.defaultFns=Ke;exports.directTool=ee;exports.disposeEmbeddingPipelineCache=we;exports.embedding=tt;exports.embeddingPlugin=nt;exports.isDeferredFn=L;exports.isMcpAdapter=ot;exports.isOAuthAuth=pe;exports.isToolSelection=I;exports.llm=ke;exports.llmPlugin=Ie;exports.mcp=Z;exports.mcpPlugin=He;exports.mcpTool=Be;exports.oauth=De;exports.tools=ze;exports.validateLlmPluginOptions=ie;exports.validateWithSchema=je;//# sourceMappingURL=index.cjs.map
3
3
  //# sourceMappingURL=index.cjs.map