@routecraft/ai 0.4.0 → 0.5.0-canary.2

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