@lynq/lynq 0.8.2 → 0.8.3

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.
@@ -0,0 +1 @@
1
+ var r=new WeakMap;function n(s,e){r.set(s,e);}function t(s){let e=r.get(s);if(!e)throw new Error("No internals registered for this server instance");return e}export{n as a,t as b};
@@ -0,0 +1 @@
1
+ import {createHmac,timingSafeEqual}from'crypto';import {normalizeObjectSchema}from'@modelcontextprotocol/sdk/server/zod-compat.js';import {toJsonSchemaCompat}from'@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';function h(e){if(e==null)return {type:"object"};let t=normalizeObjectSchema(e);return t?toJsonSchemaCompat(t):e}function x(e,t){let o=t[t.length-1];if(typeof o!="function")throw new TypeError(`${e}: last argument must be a handler function`);let n=t[t.length-2];if(n==null||typeof n!="object"||Array.isArray(n))throw new TypeError(`${e}: second-to-last argument must be a config object`);let r=t.slice(0,-2);for(let s of r)if(!s||typeof s!="object"||typeof s.name!="string")throw new TypeError(`${e}: each middleware must have a "name" property`);return {middlewares:r,config:n,handler:o}}function T(e,t){let o=[];for(let n of t)n.onRegister?.(e)===false&&o.push(n.name);return o}function R(e){let o=e.split(/\{[^}]+\}/).map(n=>n.replace(/[.*+?^$|()[\]\\]/g,"\\$&"));return new RegExp(`^${o.join("([^/]+)")}$`)}function y(e,t,o,n){let r=o.get(t);if(r==="disabled")return false;if(r==="enabled")return true;for(let s of e)if(!n.has(s))return false;return true}function b(e,t){let o=e.get(t);if(o)return o;for(let n of e.values())if(n.isTemplate&&n.uriPattern?.test(t))return n}function $(e,t,o){let n=`${e}:${t}`,r=createHmac("sha256",o).update(n).digest("hex");return `${n}:${r}`}function C(e,t){if(e.length<66)return null;let o=e.slice(-64);if(e[e.length-65]!==":")return null;let n=e.slice(0,-65),r=n.indexOf(":");if(r<1)return null;let s=n.slice(0,r),i=n.slice(r+1);if(!i)return null;let l=createHmac("sha256",t).update(`${s}:${i}`).digest("hex");try{if(!timingSafeEqual(Buffer.from(o,"hex"),Buffer.from(l,"hex")))return null}catch{return null}return {sessionId:s,elicitationId:i}}function M(e,t){if(!e)return false;let o=e.replace(/:\d+$/,"");return t.includes(o)}var S=["localhost","127.0.0.1","::1"];function I(e,t,o){let n=e.filter(l=>l.onCall),r=e.filter(l=>l.onResult).reverse(),s=0,i=async()=>{if(s>=n.length){let a=await o();for(let c of r)a=await c.onResult(a,t);return a}return n[s++].onCall(t,i)};return i}export{h as a,x as b,T as c,R as d,y as e,b as f,$ as g,C as h,M as i,S as j,I as k};
@@ -0,0 +1 @@
1
+ function g(s){let r=s?.maxEntries??1e4,e=new Map;return {async get(n){let t=e.get(n);if(t){if(t.expiresAt!==void 0&&Date.now()>t.expiresAt){e.delete(n);return}return t.accessedAt=Date.now(),t.value}},async set(n,t,i){if(e.size>=r){let f=Date.now();for(let[o,u]of e)u.expiresAt!==void 0&&f>u.expiresAt&&e.delete(o);if(e.size>=r){let o,u=Number.POSITIVE_INFINITY;for(let[c,d]of e)d.accessedAt<u&&(u=d.accessedAt,o=c);o!==void 0&&e.delete(o);}}e.set(n,{value:t,expiresAt:i!==void 0?Date.now()+i*1e3:void 0,accessedAt:Date.now()});},async delete(n){e.delete(n);}}}function a(s){let r=s.get("user");if(r){if(typeof r=="string")return r;if(typeof r=="object"&&r!==null){let e=r;if(typeof e.id=="string")return e.id;if(typeof e.id=="number")return String(e.id);if(typeof e.sub=="string")return e.sub}}}function p(s,r){let e=()=>{let n=a(s);if(!n){let t=s.get("user");if(t){let i=typeof t=="object"?JSON.stringify(t):typeof t;throw new Error(`userStore: session has a "user" but could not resolve an ID. Expected: string | { id: string | number } | { sub: string }. Got: ${i}`)}throw new Error("userStore requires a user in session. Call session.set('user', ...) first.")}return n};return {async get(n){return r.get(`user:${e()}:${n}`)},async set(n,t,i){await r.set(`user:${e()}:${n}`,t,i);},async delete(n){await r.delete(`user:${e()}:${n}`);}}}export{g as a,a as b,p as c};
package/dist/helpers.mjs CHANGED
@@ -1 +1 @@
1
- export{j as LOCALHOST_HOSTS,g as signState,i as validateHost,h as verifyState}from'./chunk-3BJEUP3F.mjs';
1
+ export{j as LOCALHOST_HOSTS,g as signState,i as validateHost,h as verifyState}from'./chunk-OYEWQXJU.mjs';
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { S as ServerOptions, M as MCPServer } from './types-P-hHI9qc.js';
2
- export { E as Elicit, a as ElicitFormResult, b as ElicitUrlOptions, c as ElicitUrlResult, H as HttpAdapterOptions, R as ResourceConfig, d as ResourceContent, e as ResourceContext, f as ResourceHandler, g as RootInfo, h as Sample, i as SampleOptions, j as SampleRawParams, k as SampleRawResult, l as ServerInfo, m as Session, n as Store, T as TaskConfig, o as TaskContext, p as TaskControl, q as TaskHandler, r as ToolConfig, s as ToolContext, t as ToolHandler, u as ToolInfo, v as ToolMiddleware, w as ToolResponse, U as User, x as UserStore, y as error, z as image, A as json, B as text } from './types-P-hHI9qc.js';
3
- export { memoryStore } from './store.js';
1
+ import { S as ServerOptions, M as MCPServer } from './types-CB6NartK.js';
2
+ export { E as Elicit, a as ElicitFormResult, b as ElicitUrlOptions, c as ElicitUrlResult, H as HttpAdapterOptions, R as ResourceConfig, d as ResourceContent, e as ResourceContext, f as ResourceHandler, g as RootInfo, h as Sample, i as SampleOptions, j as SampleRawParams, k as SampleRawResult, l as ServerInfo, m as Session, n as Store, T as TaskConfig, o as TaskContext, p as TaskControl, q as TaskHandler, r as ToolConfig, s as ToolContext, t as ToolHandler, u as ToolInfo, v as ToolMiddleware, w as ToolResponse, U as User, x as UserStore, y as error, z as image, A as json, B as text } from './types-CB6NartK.js';
3
+ export { MemoryStoreOptions, memoryStore } from './store.js';
4
4
  import '@modelcontextprotocol/sdk/types.js';
5
5
  import 'zod';
6
6
 
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import {b as b$1,c,d,a as a$1,k,f,e}from'./chunk-3BJEUP3F.mjs';import {a,c as c$2}from'./chunk-63JN2KYH.mjs';export{a as memoryStore}from'./chunk-63JN2KYH.mjs';import {c as c$1,d as d$1,b as b$2,a as a$2}from'./chunk-VAAZWX4U.mjs';export{c as error,d as image,b as json,a as text}from'./chunk-VAAZWX4U.mjs';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {InMemoryTaskStore}from'@modelcontextprotocol/sdk/experimental/tasks';import {ListToolsRequestSchema,CallToolRequestSchema,ListResourcesRequestSchema,ListResourceTemplatesRequestSchema,ReadResourceRequestSchema}from'@modelcontextprotocol/sdk/types.js';function z(){let t=new Map;function e(){let r=Date.now();for(let[c,d]of t)r-d.createdAt>36e5&&t.delete(c);}function o(r,c,d){return e(),new Promise(m=>{let n;try{n=d.createElicitationCompletionNotifier(r);}catch{}t.set(r,{resolver:m,completionNotifier:n,createdAt:Date.now()});})}function s(r){e();let c=t.get(r);c&&(t.delete(r),c.completionNotifier&&c.completionNotifier().catch(()=>{}),c.resolver());}function i(r){let c=t.get(r);c&&(t.delete(r),c.resolver());}return {register:o,complete:s,cancel:i}}function K(t,e,o){return {async form(s,i){let r=a$1(i),c=await t.elicitInput({message:s,requestedSchema:r});return {action:c.action,content:c.content??{}}},async url(s,i,r){let c=r?.elicitationId??crypto.randomUUID(),d;r?.waitForCompletion&&e&&(d=e(c,t));let m=await t.elicitInput({mode:"url",message:s,url:i,elicitationId:c});if(m.action==="accept"&&d){let n=r?.timeout??3e5,g,y=new Promise((T,a)=>{g=setTimeout(()=>a(new Error("Elicitation timed out")),n);});try{await Promise.race([d,y]);}catch(T){throw o&&o(c),T}finally{clearTimeout(g);}}else d&&o&&o(c);return {action:m.action}}}}function D(t){return async()=>{try{return (await t.listRoots()).roots.map(o=>{let s={uri:o.uri};return o.name!==void 0&&(s.name=o.name),s})}catch{return []}}}function Q(t){async function e(s,i){let r={messages:[{role:"user",content:{type:"text",text:s}}],maxTokens:i?.maxTokens??1024};i?.model!==void 0&&(r.modelPreferences={hints:[{name:i.model}]}),i?.system!==void 0&&(r.systemPrompt=i.system),i?.temperature!==void 0&&(r.temperature=i.temperature),i?.stopSequences!==void 0&&(r.stopSequences=i.stopSequences);let d=(await t.createMessage(r)).content;return d.type==="text"?d.text:""}async function o(s){return t.createMessage(s)}return Object.assign(e,{raw:o})}function O(t,e,o,s,i,r,c,d,m){return {toolName:s,args:i,session:o,signal:r,sessionId:e,elicit:K(t,d,m),roots:D(t),sample:Q(t),text:a$2,json:b$2,error:c$1,image:d$1,store:c,userStore:c$2(o,c)}}function b(t,e){let o=t.sessions.get(e);if(!o&&(o={data:new Map,grants:new Set,toolOverrides:new Map,resourceOverrides:new Map},t.sessions.set(e,o),t.onSessionCreate))try{Promise.resolve(t.onSessionCreate(e)).catch(()=>{});}catch{}return o}function P(t,e$1,o){let s=b(t,o);return e(e$1.hiddenByMiddlewares,e$1.name,s.toolOverrides,s.grants)}function C(t,e$1,o){let s=b(t,o);return e(e$1.hiddenByMiddlewares,e$1.uri,s.resourceOverrides,s.grants)}function x(t,e$1,o){let s=b(t,o);return e(e$1.hiddenByMiddlewares,e$1.name,s.toolOverrides,s.grants)}function _(t,e,o){(o&&t.serverBySession.get(o)||e).sendToolListChanged().catch(()=>{});}function A(t,e,o){(o&&t.serverBySession.get(o)||e).sendResourceListChanged().catch(()=>{});}function w(t,e,o){let s=b(t,o);return {get(i){return s.data.get(i)},set(i,r){s.data.set(i,r);},authorize(i){s.grants.add(i),_(t,e,o),A(t,e,o);},revoke(i){s.grants.delete(i),_(t,e,o),A(t,e,o);},enableTools(...i){for(let r of i)s.toolOverrides.set(r,"enabled");_(t,e,o);},disableTools(...i){for(let r of i)s.toolOverrides.set(r,"disabled");_(t,e,o);},enableResources(...i){for(let r of i)s.resourceOverrides.set(r,"enabled");A(t,e,o);},disableResources(...i){for(let r of i)s.resourceOverrides.set(r,"disabled");A(t,e,o);}}}function F(){let t=new Set,e=new InMemoryTaskStore;return {taskStore:new Proxy(e,{get(s,i,r){return i==="updateTaskStatus"?async(c,d,...m)=>(d==="cancelled"&&t.add(c),s.updateTaskStatus.call(s,c,d,...m)):Reflect.get(s,i,r)}}),cancelledTaskIds:t}}function L(t,e,o,s,i){t.setRequestHandler(ListToolsRequestSchema,(r,c)=>{let d=c.sessionId??"default",m=[];for(let n of e.tools.values())P(e,n,d)&&m.push({name:n.name,description:n.description,inputSchema:a$1(n.input)});for(let n of e.tasks.values())x(e,n,d)&&m.push({name:n.name,description:n.description,inputSchema:a$1(n.input),execution:{taskSupport:"required"}});return {tools:m}}),t.setRequestHandler(CallToolRequestSchema,async(r,c)=>{let{name:d,arguments:m}=r.params,n=c.sessionId??"default",g=e.tools.get(d);if(g){if(!P(e,g,n))return c$1(`Tool not available: ${d}`);let T=m??{},a=O(t,n,w(e,o,n),d,T,c.signal,e.store,(f,S)=>s.register(f,n,S),s.cancel),u=()=>Promise.resolve(g.handler(T,a));return k(g.middlewares,a,u)()}let y=e.tasks.get(d);if(y){if(!x(e,y,n))return c$1(`Tool not available: ${d}`);let T=c.taskStore;if(!T)return c$1("Task store not available");let a=await T.createTask({pollInterval:1e3}),u=a.taskId,l={progress(p,h){if(i.has(u))return;let W=h?`${p}% ${h}`:`${p}%`;T.updateTaskStatus(u,"working",W).catch(()=>{});},get cancelled(){return i.has(u)}},f=m??{},S={...O(t,n,w(e,o,n),d,f,c.signal,e.store,(p,h)=>s.register(p,n,h),s.cancel),task:l},v=async()=>((async()=>{try{let p=await y.handler(f,S);i.has(u)||await T.storeTaskResult(u,"completed",p);}catch(p){if(!i.has(u)){let h=p instanceof Error?p.message:String(p);await T.storeTaskResult(u,"failed",c$1(h)).catch(()=>{});}}})(),{task:a});return k(y.middlewares,S,v)()}return c$1(`Unknown tool: ${d}`)}),t.setRequestHandler(ListResourcesRequestSchema,(r,c)=>{let d=c.sessionId??"default",m=[];for(let n of e.resources.values())!n.isTemplate&&C(e,n,d)&&m.push({uri:n.uri,name:n.name,description:n.description,mimeType:n.mimeType});return {resources:m}}),t.setRequestHandler(ListResourceTemplatesRequestSchema,(r,c)=>{let d=c.sessionId??"default",m=[];for(let n of e.resources.values())n.isTemplate&&C(e,n,d)&&m.push({uriTemplate:n.uri,name:n.name,description:n.description,mimeType:n.mimeType});return {resourceTemplates:m}}),t.setRequestHandler(ReadResourceRequestSchema,async(r,c)=>{let{uri:d}=r.params,m=f(e.resources,d);if(!m)throw new Error(`Unknown resource: ${d}`);let n=c.sessionId??"default";if(!C(e,m,n))throw new Error(`Resource not available: ${d}`);let g=w(e,o,n),y={uri:d,session:g,sessionId:n,roots:D(t),store:e.store,userStore:c$2(g,e.store)},T=O(t,n,g,m.uri,{},c.signal,e.store,(l,f)=>s.register(l,n,f),s.cancel),a=async()=>{let l=await m.handler(d,y);return {contents:[{uri:d,mimeType:l.mimeType??m.mimeType,...l.text!=null?{text:l.text}:{},...l.blob!=null?{blob:l.blob}:{}}]}};return k(m.middlewares,T,a)()});}function G(t,e,o,s,i,r,c){let d={tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}};function m(){let n=new Server(t,{capabilities:d,taskStore:o});return c(n,e,s,i,r),n}return function(g){let y=null;async function T(){return y||(y=(await import('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js')).WebStandardStreamableHTTPServerTransport),y}if(g?.sessionless)return async l=>{let f=await T(),S=m(),v=new f({sessionIdGenerator:void 0,enableJsonResponse:g?.enableJsonResponse});return await S.connect(v),v.handleRequest(l)};let a=new Map,u=false;return async l=>{!u&&e.onServerStart&&(u=true,Promise.resolve(e.onServerStart()).catch(()=>{}));let f=await T(),S=l.headers.get("mcp-session-id");if(S){let p=a.get(S);return p?(g?.onRequest&&await g.onRequest(l,S,w(e,s,S)),p.transport.handleRequest(l)):new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Session not found"}}),{status:404,headers:{"Content-Type":"application/json"}})}let v=m(),k=new f({sessionIdGenerator:g?.sessionIdGenerator??(()=>crypto.randomUUID()),enableJsonResponse:g?.enableJsonResponse,onsessioninitialized:p=>{a.set(p,{server:v,transport:k}),e.serverBySession.set(p,v),g?.onRequest&&g.onRequest(l,p,w(e,s,p));},onsessionclosed:p=>{a.delete(p),e.serverBySession.delete(p),e.sessions.delete(p),e.onSessionDestroy&&Promise.resolve(e.onSessionDestroy(p)).catch(()=>{});}});return await v.connect(k),v.onclose=()=>{for(let[p,h]of a)if(h.server===v){a.delete(p),e.serverBySession.delete(p),e.sessions.delete(p),e.onSessionDestroy&&Promise.resolve(e.onSessionDestroy(p)).catch(()=>{});break}},k.handleRequest(l)}}}function ne(t){let e={store:t.store??a(),globalMiddlewares:[],tools:new Map,resources:new Map,tasks:new Map,sessions:new Map,serverBySession:new Map,onServerStart:t.onServerStart,onSessionCreate:t.onSessionCreate,onSessionDestroy:t.onSessionDestroy},o=z(),{taskStore:s,cancelledTaskIds:i}=F(),r=new Server(t,{capabilities:{tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},taskStore:s});L(r,e,r,o,i),r.onclose=()=>{let a="default";if(e.sessions.delete(a),e.onSessionDestroy)try{Promise.resolve(e.onSessionDestroy(a)).catch(()=>{});}catch{}};function c$1(a){e.globalMiddlewares.push(a);}function d$1(...a){let u=a[0],l=b$1(`tool("${u}")`,a.slice(1));if(typeof l.config.name=="string")throw new TypeError(`tool("${u}"): second-to-last argument must be a config object`);let f=l.config,S=[...e.globalMiddlewares,...l.middlewares],v={name:u,description:f.description,middlewares:S};e.tools.set(u,{name:u,description:f.description,input:f.input,handler:l.handler,middlewares:S,hiddenByMiddlewares:c(v,S)});}function m(...a){let u=a[0],l=b$1(`resource("${u}")`,a.slice(1));if(typeof l.config.name!="string")throw new TypeError(`resource("${u}"): second-to-last argument must be a config object with a "name" property`);let f=l.config,S=[...e.globalMiddlewares,...l.middlewares],v={name:f.name,description:f.description,middlewares:S},k=u.includes("{");e.resources.set(u,{uri:u,isTemplate:k,uriPattern:k?d(u):null,name:f.name,description:f.description,mimeType:f.mimeType,handler:l.handler,middlewares:S,hiddenByMiddlewares:c(v,S)});}function n(...a){let u=a[0],l=b$1(`task("${u}")`,a.slice(1));if(typeof l.config.name=="string")throw new TypeError(`task("${u}"): second-to-last argument must be a config object`);let f=l.config,S=[...e.globalMiddlewares,...l.middlewares],v={name:u,description:f.description,middlewares:S};e.tasks.set(u,{name:u,description:f.description,input:f.input,handler:l.handler,middlewares:S,hiddenByMiddlewares:c(v,S)});}async function g(){let{StdioServerTransport:a}=await import('@modelcontextprotocol/sdk/server/stdio.js'),u=new a;await r.connect(u),e.onServerStart&&await Promise.resolve(e.onServerStart()).catch(()=>{});}async function y(a){await r.connect(a);}let T=G(t,e,s,r,o,i,L);return {use:c$1,tool:d$1,resource:m,task:n,stdio:g,http:T,session:a=>w(e,r,a),completeElicitation:o.complete,store:e.store,connect:y,_server:r,_getSession:a=>b(e,a),_isToolVisible(a,u){let l=e.tools.get(a);return l?P(e,l,u):false},_isResourceVisible(a,u){let l=e.resources.get(a);return l?C(e,l,u):false},_isTaskVisible(a,u){let l=e.tasks.get(a);return l?x(e,l,u):false},_createSessionAPI:a=>w(e,r,a)}}export{ne as createMCPServer};
1
+ import {a as a$1}from'./chunk-CI343GXC.mjs';import {b as b$1,c,d,a as a$2,k as k$1,f,e}from'./chunk-OYEWQXJU.mjs';import {a,c as c$1}from'./chunk-YIQZZYBJ.mjs';export{a as memoryStore}from'./chunk-YIQZZYBJ.mjs';import {d as d$1,c as c$2,b as b$2,a as a$3}from'./chunk-VAAZWX4U.mjs';export{c as error,d as image,b as json,a as text}from'./chunk-VAAZWX4U.mjs';import {Server}from'@modelcontextprotocol/sdk/server/index.js';import {InMemoryTaskStore}from'@modelcontextprotocol/sdk/experimental/tasks';import {ListToolsRequestSchema,CallToolRequestSchema,McpError,ErrorCode,ListResourcesRequestSchema,ListResourceTemplatesRequestSchema,ReadResourceRequestSchema}from'@modelcontextprotocol/sdk/types.js';function K(){let t=new Map;function e(){let o=Date.now();for(let[l,c]of t)o-c.createdAt>36e5&&t.delete(l);}function r(o,l,c){return e(),new Promise(m=>{let n;try{n=c.createElicitationCompletionNotifier(o);}catch{}t.set(o,{resolver:m,completionNotifier:n,createdAt:Date.now()});})}function s(o){e();let l=t.get(o);l&&(t.delete(o),l.completionNotifier&&l.completionNotifier().catch(()=>{}),l.resolver());}function a(o){let l=t.get(o);l&&(t.delete(o),l.resolver());}return {register:r,complete:s,cancel:a}}function Y(t,e,r){return {async form(s,a){let o=a$2(a),l=await t.elicitInput({message:s,requestedSchema:o});return {action:l.action,content:l.content??{}}},async url(s,a,o){let l=o?.elicitationId??crypto.randomUUID(),c;o?.waitForCompletion&&e&&(c=e(l,t));let m=await t.elicitInput({mode:"url",message:s,url:a,elicitationId:l});if(m.action==="accept"&&c){let n=o?.timeout??3e5,v,y=new Promise((S,T)=>{v=setTimeout(()=>T(new Error("Elicitation timed out")),n);});try{await Promise.race([c,y]);}catch(S){throw r&&r(l),S}finally{clearTimeout(v);}}else c&&r&&r(l);return {action:m.action}}}}function J(t){return async()=>{try{return (await t.listRoots()).roots.map(r=>{let s={uri:r.uri};return r.name!==void 0&&(s.name=r.name),s})}catch{return []}}}function Z(t){async function e(s,a){let o={messages:[{role:"user",content:{type:"text",text:s}}],maxTokens:a?.maxTokens??1024};a?.model!==void 0&&(o.modelPreferences={hints:[{name:a.model}]}),a?.system!==void 0&&(o.systemPrompt=a.system),a?.temperature!==void 0&&(o.temperature=a.temperature),a?.stopSequences!==void 0&&(o.stopSequences=a.stopSequences);let c=(await t.createMessage(o)).content;return c.type==="text"?c.text:""}async function r(s){return t.createMessage(s)}return Object.assign(e,{raw:r})}function D(t,e,r,s,a,o,l,c,m){return {toolName:s,args:a,session:r,signal:o,sessionId:e,elicit:Y(t,c,m),roots:J(t),sample:Z(t),text:a$3,json:b$2,error:c$2,image:d$1,store:l,userStore:c$1(r,l)}}function k(t,e){let r=t.sessions.get(e);if(!r&&(r={data:new Map,grants:new Set,toolOverrides:new Map,resourceOverrides:new Map},t.sessions.set(e,r),t.onSessionCreate))try{Promise.resolve(t.onSessionCreate(e)).catch(()=>{});}catch{}return r}function q(t,e$1,r){let s=k(t,r);return e(e$1.hiddenByMiddlewares,e$1.name,s.toolOverrides,s.grants)}function b(t,e$1,r){let s=k(t,r);return e(e$1.hiddenByMiddlewares,e$1.uri,s.resourceOverrides,s.grants)}function E(t,e$1,r){let s=k(t,r);return e(e$1.hiddenByMiddlewares,e$1.name,s.toolOverrides,s.grants)}function U(t,e,r){(r&&t.serverBySession.get(r)||e).sendToolListChanged().catch(()=>{});}function $(t,e,r){(r&&t.serverBySession.get(r)||e).sendResourceListChanged().catch(()=>{});}function R(t,e,r){let s=k(t,r);return {get(a){return s.data.get(a)},set(a,o){s.data.set(a,o);},authorize(a){s.grants.add(a),U(t,e,r),$(t,e,r);},revoke(a){s.grants.delete(a),U(t,e,r),$(t,e,r);},enableTools(...a){for(let o of a)s.toolOverrides.set(o,"enabled");U(t,e,r);},disableTools(...a){for(let o of a)s.toolOverrides.set(o,"disabled");U(t,e,r);},enableResources(...a){for(let o of a)s.resourceOverrides.set(o,"enabled");$(t,e,r);},disableResources(...a){for(let o of a)s.resourceOverrides.set(o,"disabled");$(t,e,r);}}}function Q(){let t=new Set,e=new InMemoryTaskStore;return {taskStore:new Proxy(e,{get(s,a,o){return a==="updateTaskStatus"?async(l,c,...m)=>(c==="cancelled"&&t.add(l),s.updateTaskStatus.call(s,l,c,...m)):Reflect.get(s,a,o)}}),cancelledTaskIds:t}}function F(t,e,r,s,a){t.setRequestHandler(ListToolsRequestSchema,(o,l)=>{let c=l.sessionId??"default",m=[];for(let n of e.tools.values())q(e,n,c)&&m.push({name:n.name,description:n.description,inputSchema:a$2(n.input)});for(let n of e.tasks.values())E(e,n,c)&&m.push({name:n.name,description:n.description,inputSchema:a$2(n.input),execution:{taskSupport:"required"}});return {tools:m}}),t.setRequestHandler(CallToolRequestSchema,async(o,l)=>{let{name:c,arguments:m}=o.params,n=l.sessionId??"default",v=e.tools.get(c);if(v){if(!q(e,v,n))throw new McpError(ErrorCode.MethodNotFound,`Tool not available: ${c}`);let S=m??{},T=D(t,n,R(e,r,n),c,S,l.signal,e.store,(u,f)=>s.register(u,n,f),s.cancel),d=()=>Promise.resolve(v.handler(S,T));return k$1(v.middlewares,T,d)()}let y=e.tasks.get(c);if(y){if(!E(e,y,n))throw new McpError(ErrorCode.MethodNotFound,`Tool not available: ${c}`);let S=l.taskStore;if(!S)throw new McpError(ErrorCode.InternalError,"Task store not available");let T=await S.createTask({pollInterval:1e3}),d=T.taskId,i={progress(p,w){if(a.has(d))return;let P=w?`${p}% ${w}`:`${p}%`;S.updateTaskStatus(d,"working",P).catch(()=>{});},get cancelled(){return a.has(d)}},u=m??{},f={...D(t,n,R(e,r,n),c,u,l.signal,e.store,(p,w)=>s.register(p,n,w),s.cancel),task:i},g=async()=>{let p=(async()=>{try{let w=await y.handler(u,f);a.has(d)||await S.storeTaskResult(d,"completed",w);}catch(w){if(!a.has(d)){let P=w instanceof Error?w.message:String(w);await S.storeTaskResult(d,"failed",c$2(P)).catch(()=>{});}}})();return e.runningTasks.add(p),p.finally(()=>e.runningTasks.delete(p)),{task:T}};return k$1(y.middlewares,f,g)()}throw new McpError(ErrorCode.MethodNotFound,`Unknown tool: ${c}`)}),t.setRequestHandler(ListResourcesRequestSchema,(o,l)=>{let c=l.sessionId??"default",m=[];for(let n of e.resources.values())!n.isTemplate&&b(e,n,c)&&m.push({uri:n.uri,name:n.name,description:n.description,mimeType:n.mimeType});return {resources:m}}),t.setRequestHandler(ListResourceTemplatesRequestSchema,(o,l)=>{let c=l.sessionId??"default",m=[];for(let n of e.resources.values())n.isTemplate&&b(e,n,c)&&m.push({uriTemplate:n.uri,name:n.name,description:n.description,mimeType:n.mimeType});return {resourceTemplates:m}}),t.setRequestHandler(ReadResourceRequestSchema,async(o,l)=>{let{uri:c}=o.params,m=f(e.resources,c);if(!m)throw new McpError(ErrorCode.InvalidRequest,`Unknown resource: ${c}`);let n=l.sessionId??"default";if(!b(e,m,n))throw new McpError(ErrorCode.InvalidRequest,`Resource not available: ${c}`);let v=R(e,r,n),y={uri:c,session:v,sessionId:n,roots:J(t),store:e.store,userStore:c$1(v,e.store)},S=D(t,n,v,m.uri,{},l.signal,e.store,(i,u)=>s.register(i,n,u),s.cancel),T=async()=>{let i=await m.handler(c,y);return {contents:[{uri:c,mimeType:i.mimeType??m.mimeType,...i.text!=null?{text:i.text}:{},...i.blob!=null?{blob:i.blob}:{}}]}};return k$1(m.middlewares,S,T)()});}function X(t,e,r,s,a,o,l){let c=null;async function m(){return c||(c=(await import('@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js')).WebStandardStreamableHTTPServerTransport),c}let n={tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}};function v(){let y=new Server(t,{capabilities:n,taskStore:r});return l(y,e,s,a,o),y}return function(S){if(S?.sessionless)return async i=>{let u=await m(),f=v(),g=new u({sessionIdGenerator:void 0,enableJsonResponse:S?.enableJsonResponse});return await f.connect(g),g.handleRequest(i)};let T=new Map,d=false;return async i=>{!d&&e.onServerStart&&(d=true,Promise.resolve(e.onServerStart()).catch(()=>{}));let u=await m(),f=i.headers.get("mcp-session-id");if(f){let p=T.get(f);return p?(S?.onRequest&&await S.onRequest(i,f,R(e,s,f)),p.transport.handleRequest(i)):new Response(JSON.stringify({jsonrpc:"2.0",error:{code:-32e3,message:"Session not found"}}),{status:404,headers:{"Content-Type":"application/json"}})}let g=v(),h=new u({sessionIdGenerator:S?.sessionIdGenerator??(()=>crypto.randomUUID()),enableJsonResponse:S?.enableJsonResponse,onsessioninitialized:p=>{T.set(p,{server:g,transport:h}),e.serverBySession.set(p,g),S?.onRequest&&S.onRequest(i,p,R(e,s,p));},onsessionclosed:p=>{T.delete(p),e.serverBySession.delete(p);let w=e.sessions.get(p)?.data??new Map;e.sessions.delete(p),e.onSessionDestroy&&Promise.resolve(e.onSessionDestroy(p,w)).catch(()=>{});}});return await g.connect(h),g.onclose=()=>{for(let[p,w]of T)if(w.server===g){T.delete(p),e.serverBySession.delete(p);let P=e.sessions.get(p)?.data??new Map;e.sessions.delete(p),e.onSessionDestroy&&Promise.resolve(e.onSessionDestroy(p,P)).catch(()=>{});break}},h.handleRequest(i)}}}function ce(t){let e={store:t.store??a(),globalMiddlewares:[],tools:new Map,resources:new Map,tasks:new Map,sessions:new Map,serverBySession:new Map,onServerStart:t.onServerStart,onSessionCreate:t.onSessionCreate,onSessionDestroy:t.onSessionDestroy,runningTasks:new Set},r=K(),{taskStore:s,cancelledTaskIds:a$2}=Q(),o=new Server(t,{capabilities:{tools:{listChanged:true},resources:{listChanged:true},tasks:{list:{},cancel:{},requests:{tools:{call:{}}}}},taskStore:s});F(o,e,o,r,a$2),o.onclose=()=>{let d="default",i=e.sessions.get(d)?.data??new Map;if(e.sessions.delete(d),e.onSessionDestroy)try{Promise.resolve(e.onSessionDestroy(d,i)).catch(()=>{});}catch{}};function l(d){e.globalMiddlewares.push(d);}function c$1(...d){let i=d[0],u=b$1(`tool("${i}")`,d.slice(1));if(typeof u.config.name=="string")throw new TypeError(`tool("${i}"): second-to-last argument must be a config object`);let f=u.config,g=[...e.globalMiddlewares,...u.middlewares],h={name:i,description:f.description,middlewares:g};e.tools.set(i,{name:i,description:f.description,input:f.input,handler:u.handler,middlewares:g,hiddenByMiddlewares:c(h,g)});}function m(...d$1){let i=d$1[0],u=b$1(`resource("${i}")`,d$1.slice(1));if(typeof u.config.name!="string")throw new TypeError(`resource("${i}"): second-to-last argument must be a config object with a "name" property`);let f=u.config,g=[...e.globalMiddlewares,...u.middlewares],h={name:f.name,description:f.description,middlewares:g},p=i.includes("{");e.resources.set(i,{uri:i,isTemplate:p,uriPattern:p?d(i):null,name:f.name,description:f.description,mimeType:f.mimeType,handler:u.handler,middlewares:g,hiddenByMiddlewares:c(h,g)});}function n(...d){let i=d[0],u=b$1(`task("${i}")`,d.slice(1));if(typeof u.config.name=="string")throw new TypeError(`task("${i}"): second-to-last argument must be a config object`);let f=u.config,g=[...e.globalMiddlewares,...u.middlewares],h={name:i,description:f.description,middlewares:g};e.tasks.set(i,{name:i,description:f.description,input:f.input,handler:u.handler,middlewares:g,hiddenByMiddlewares:c(h,g)});}async function v(){let{StdioServerTransport:d}=await import('@modelcontextprotocol/sdk/server/stdio.js'),i=new d;await o.connect(i),e.onServerStart&&await Promise.resolve(e.onServerStart()).catch(()=>{});}let y=X(t,e,s,o,r,a$2,F);async function S(){await Promise.allSettled(e.runningTasks);}let T={use:l,tool:c$1,resource:m,task:n,stdio:v,http:y,drain:S,session:d=>R(e,o,d),completeElicitation:r.complete,store:e.store};return a$1(T,{server:o,getSession:d=>k(e,d),isToolVisible(d,i){let u=e.tools.get(d);return u?q(e,u,i):false},isResourceVisible(d,i){let u=e.resources.get(d);return u?b(e,u,i):false},isTaskVisible(d,i){let u=e.tasks.get(d);return u?E(e,u,i):false},createSessionAPI:d=>R(e,o,d)}),T}export{ce as createMCPServer};
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import { GuardOptions } from './guard.js';
3
3
  import '@modelcontextprotocol/sdk/types.js';
4
4
  import 'zod';
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,11 +1,11 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
5
5
  interface CacheOptions {
6
6
  /** TTL in seconds. */
7
7
  ttl: number;
8
- /** Custom cache key builder. Default: `cache:${toolName}:${JSON.stringify(args)}`. */
8
+ /** Custom cache key builder. Default: `cache:${toolName}:${stableStringify(args)}`. */
9
9
  key?: (toolName: string, args: Record<string, unknown>) => string;
10
10
  }
11
11
  declare function cache(options: CacheOptions): ToolMiddleware;
@@ -1 +1 @@
1
- function l(r){let{ttl:a}=r,n=r.key??((t,e)=>`cache:${t}:${JSON.stringify(e)}`);return {name:"cache",async onCall(t,e){let o=n(t.toolName,t.args),s=await t.store.get(o);return s||e()},async onResult(t,e){if(!t.isError){let o=n(e.toolName,e.args);await e.store.set(o,t,a);}return t}}}export{l as cache};
1
+ function i(n){if(n===null||typeof n!="object")return JSON.stringify(n);if(Array.isArray(n))return `[${n.map(i).join(",")}]`;let r=n;return `{${Object.keys(r).sort().map(t=>`${JSON.stringify(t)}:${i(r[t])}`).join(",")}}`}function c(n){let{ttl:r}=n,e=n.key??((t,o)=>`cache:${t}:${i(o)}`);return {name:"cache",async onCall(t,o){let s=e(t.toolName,t.args),a=await t.store.get(s);return a||o()},async onResult(t,o){if(!t.isError){let s=e(o.toolName,o.args);await o.store.set(s,t,r);}return t}}}export{c as cache};
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware, s as ToolContext } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware, s as ToolContext } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
2
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
3
3
  import '@modelcontextprotocol/sdk/types.js';
4
4
 
5
5
  interface CredentialsOptions<T extends z.ZodObject<z.ZodRawShape>> {
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { s as ToolContext, v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { s as ToolContext, v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { s as ToolContext, v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { s as ToolContext, v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -9,11 +9,31 @@ interface RateLimitOptions {
9
9
  windowMs?: number;
10
10
  /** Error message. */
11
11
  message?: string;
12
- /** Use persistent Store for distributed rate limiting. Default: false (session-scoped). */
12
+ /**
13
+ * Use persistent Store for distributed rate limiting.
14
+ * Default: `false` (session-scoped — each session gets its own counter,
15
+ * so a client can bypass the limit by reconnecting).
16
+ * Set to `true` for production rate limiting across sessions.
17
+ */
13
18
  store?: boolean;
14
- /** Scope rate limiting per user (implies `store: true`). Default: false. */
19
+ /**
20
+ * Scope rate limiting per user (implies `store: true`).
21
+ * Default: `false`.
22
+ *
23
+ * **Warning:** Users without `session.set("user", ...)` all share a single
24
+ * `"anon"` bucket. Ensure the user is set in session before rate-limited calls
25
+ * if per-user isolation is required.
26
+ */
15
27
  perUser?: boolean;
16
28
  }
29
+ /**
30
+ * Rate limiting middleware.
31
+ *
32
+ * **Default behavior is session-scoped** — each MCP session gets its own counter.
33
+ * A client can bypass the limit by creating a new session (reconnecting).
34
+ * For production use, set `store: true` to share counters across sessions,
35
+ * or `perUser: true` to scope limits per authenticated user.
36
+ */
17
37
  declare function rateLimit(options: RateLimitOptions): ToolMiddleware;
18
38
 
19
39
  export { type RateLimitOptions, rateLimit };
@@ -1 +1 @@
1
- import {b}from'../chunk-63JN2KYH.mjs';import {c}from'../chunk-VAAZWX4U.mjs';function g(t){let{max:a,windowMs:o=6e4}=t,w=t.store===true||t.perUser===true,d=t.perUser===true,l=t.message??`Rate limit exceeded. Max ${a} calls per ${o/1e3}s.`,f=Math.ceil(o/1e3);return {name:"rateLimit",async onCall(e,n){let i=Date.now();if(w){let u=d?`rateLimit:${b(e.session)??"anon"}:${e.toolName}`:`rateLimit:${e.toolName}`,s=await e.store.get(u);return !s||i>=s.resetAt?(await e.store.set(u,{count:1,resetAt:i+o},f),n()):s.count>=a?c(l):(await e.store.set(u,{...s,count:s.count+1},f),n())}let m=`rateLimit:${e.toolName}`,r=e.session.get(m);return !r||i>=r.resetAt?(e.session.set(m,{count:1,resetAt:i+o}),n()):r.count>=a?c(l):(e.session.set(m,{...r,count:r.count+1}),n())}}}export{g as rateLimit};
1
+ import {b}from'../chunk-YIQZZYBJ.mjs';import {c}from'../chunk-VAAZWX4U.mjs';function g(t){let{max:a,windowMs:o=6e4}=t,w=t.store===true||t.perUser===true,d=t.perUser===true,l=t.message??`Rate limit exceeded. Max ${a} calls per ${o/1e3}s.`,f=Math.ceil(o/1e3);return {name:"rateLimit",async onCall(e,n){let i=Date.now();if(w){let u=d?`rateLimit:${b(e.session)??"anon"}:${e.toolName}`:`rateLimit:${e.toolName}`,s=await e.store.get(u);return !s||i>=s.resetAt?(await e.store.set(u,{count:1,resetAt:i+o},f),n()):s.count>=a?c(l):(await e.store.set(u,{...s,count:s.count+1},f),n())}let m=`rateLimit:${e.toolName}`,r=e.session.get(m);return !r||i>=r.resetAt?(e.session.set(m,{count:1,resetAt:i+o}),n()):r.count>=a?c(l):(e.session.set(m,{...r,count:r.count+1}),n())}}}export{g as rateLimit};
@@ -1,5 +1,5 @@
1
1
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
2
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
3
3
  import 'zod';
4
4
 
5
5
  interface RetryOptions {
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
@@ -1,4 +1,4 @@
1
- import { s as ToolContext, v as ToolMiddleware } from '../types-P-hHI9qc.js';
1
+ import { s as ToolContext, v as ToolMiddleware } from '../types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
package/dist/store.d.ts CHANGED
@@ -1,9 +1,13 @@
1
- import { n as Store, m as Session, x as UserStore } from './types-P-hHI9qc.js';
1
+ import { n as Store, m as Session, x as UserStore } from './types-CB6NartK.js';
2
2
  import '@modelcontextprotocol/sdk/types.js';
3
3
  import 'zod';
4
4
 
5
- declare function memoryStore(): Store;
5
+ interface MemoryStoreOptions {
6
+ /** Maximum number of entries. When exceeded, expired entries are swept first, then least-recently-accessed entries are evicted. Default: 10000. */
7
+ maxEntries?: number;
8
+ }
9
+ declare function memoryStore(options?: MemoryStoreOptions): Store;
6
10
  declare function resolveUserId(session: Session): string | undefined;
7
11
  declare function createUserStore(session: Session, store: Store): UserStore;
8
12
 
9
- export { createUserStore, memoryStore, resolveUserId };
13
+ export { type MemoryStoreOptions, createUserStore, memoryStore, resolveUserId };
package/dist/store.mjs CHANGED
@@ -1 +1 @@
1
- export{c as createUserStore,a as memoryStore,b as resolveUserId}from'./chunk-63JN2KYH.mjs';
1
+ export{c as createUserStore,a as memoryStore,b as resolveUserId}from'./chunk-YIQZZYBJ.mjs';
package/dist/test.d.ts CHANGED
@@ -1,7 +1,25 @@
1
1
  import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
2
- import { m as Session, M as MCPServer } from './types-P-hHI9qc.js';
2
+ import { m as Session, M as MCPServer } from './types-CB6NartK.js';
3
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
4
  import 'zod';
4
5
 
6
+ interface SessionState {
7
+ data: Map<string, unknown>;
8
+ grants: Set<string>;
9
+ toolOverrides: Map<string, "enabled" | "disabled">;
10
+ resourceOverrides: Map<string, "enabled" | "disabled">;
11
+ }
12
+
13
+ interface InternalAccess {
14
+ server: Server;
15
+ getSession(sessionId: string): SessionState;
16
+ isToolVisible(toolName: string, sessionId: string): boolean;
17
+ isResourceVisible(uri: string, sessionId: string): boolean;
18
+ isTaskVisible(taskName: string, sessionId: string): boolean;
19
+ createSessionAPI(sessionId: string): Session;
20
+ }
21
+ declare function getInternals(server: MCPServer): InternalAccess;
22
+
5
23
  interface TestClient {
6
24
  /** List visible tool names. */
7
25
  listTools(): Promise<string[]>;
@@ -36,4 +54,4 @@ declare const matchers: {
36
54
  };
37
55
  };
38
56
 
39
- export { type TestClient, createTestClient, matchers };
57
+ export { type InternalAccess, type TestClient, createTestClient, getInternals, matchers };
package/dist/test.mjs CHANGED
@@ -1 +1 @@
1
- async function d(n){let{Client:r}=await import('@modelcontextprotocol/sdk/client/index.js'),{InMemoryTransport:c}=await import('@modelcontextprotocol/sdk/inMemory.js'),[o,a]=c.createLinkedPair(),t=new r({name:"lynq-test",version:"1.0.0"},{capabilities:{tasks:{}}}),u=n;await Promise.all([u._server.connect(a),t.connect(o)]);let l=u._createSessionAPI("default");return {async listTools(){return (await t.listTools()).tools.map(s=>s.name)},async callTool(e,s={}){return t.callTool({name:e,arguments:s})},async callToolText(e,s={}){let i=await t.callTool({name:e,arguments:s});if(i.isError){let p=i.content.find(g=>g.type==="text")?.text??"Unknown error";throw new Error(p)}return i.content.find(m=>m.type==="text")?.text??""},async listResources(){return (await t.listResources()).resources.map(s=>s.uri)},async listResourceTemplates(){return (await t.listResourceTemplates()).resourceTemplates.map(s=>s.uriTemplate)},async readResource(e){return (await t.readResource({uri:e})).contents[0]?.text??""},authorize(e){l.authorize(e);},revoke(e){l.revoke(e);},session:l,async close(){await t.close();}}}var y={toHaveTextContent(n,r){let o=n.content.filter(t=>t.type==="text").map(t=>t.text??""),a=o.some(t=>t.includes(r));return {pass:a,message:()=>a?`Expected result not to contain "${r}"`:`Expected result to contain "${r}", got: ${o.join(", ")}`}},toBeError(n){let r=n.isError===true;return {pass:r,message:()=>r?"Expected result not to be an error":"Expected result to be an error (isError: true)"}}};export{d as createTestClient,y as matchers};
1
+ import {b}from'./chunk-CI343GXC.mjs';export{b as getInternals}from'./chunk-CI343GXC.mjs';async function w(o){let{Client:r}=await import('@modelcontextprotocol/sdk/client/index.js'),{InMemoryTransport:u}=await import('@modelcontextprotocol/sdk/inMemory.js'),[n,a]=u.createLinkedPair(),t=new r({name:"lynq-test",version:"1.0.0"},{capabilities:{tasks:{}}}),m=b(o);await Promise.all([m.server.connect(a),t.connect(n)]);let l=m.createSessionAPI("default");return {async listTools(){return (await t.listTools()).tools.map(s=>s.name)},async callTool(e,s={}){return t.callTool({name:e,arguments:s})},async callToolText(e,s={}){let i=await t.callTool({name:e,arguments:s});if(i.isError){let g=i.content.find(T=>T.type==="text")?.text??"Unknown error";throw new Error(g)}return i.content.find(p=>p.type==="text")?.text??""},async listResources(){return (await t.listResources()).resources.map(s=>s.uri)},async listResourceTemplates(){return (await t.listResourceTemplates()).resourceTemplates.map(s=>s.uriTemplate)},async readResource(e){return (await t.readResource({uri:e})).contents[0]?.text??""},authorize(e){l.authorize(e);},revoke(e){l.revoke(e);},session:l,async close(){await t.close();}}}var R={toHaveTextContent(o,r){let n=o.content.filter(t=>t.type==="text").map(t=>t.text??""),a=n.some(t=>t.includes(r));return {pass:a,message:()=>a?`Expected result not to contain "${r}"`:`Expected result to contain "${r}", got: ${n.join(", ")}`}},toBeError(o){let r=o.isError===true;return {pass:r,message:()=>r?"Expected result not to be an error":"Expected result to be an error (isError: true)"}}};export{w as createTestClient,R as matchers};
@@ -38,8 +38,8 @@ interface ServerOptions extends ServerInfo {
38
38
  onServerStart?: () => void | Promise<void>;
39
39
  /** Called when a new session is created. */
40
40
  onSessionCreate?: (sessionId: string) => void | Promise<void>;
41
- /** Called when a session is destroyed (HTTP session close or transport disconnect). */
42
- onSessionDestroy?: (sessionId: string) => void | Promise<void>;
41
+ /** Called when a session is destroyed (HTTP session close or transport disconnect). Session data is provided for cleanup (e.g. resolving user ID to delete store entries). */
42
+ onSessionDestroy?: (sessionId: string, data: ReadonlyMap<string, unknown>) => void | Promise<void>;
43
43
  }
44
44
  interface Session {
45
45
  /** Get a session-scoped value. */
@@ -194,14 +194,29 @@ interface ResourceContext {
194
194
  userStore: UserStore;
195
195
  }
196
196
  type ResourceHandler = (uri: string, c: ResourceContext) => ResourceContent | Promise<ResourceContent>;
197
+ /**
198
+ * Options for the HTTP adapter returned by `server.http()`.
199
+ *
200
+ * **Security note:** Session routing relies on the `Mcp-Session-Id` header.
201
+ * Session IDs are UUIDs (hard to guess) but can leak via logs or proxies.
202
+ * Use `onRequest` to add additional validation (e.g., Bearer token check,
203
+ * IP binding) or `sessionIdGenerator` to produce HMAC-signed session tokens.
204
+ */
197
205
  interface HttpAdapterOptions {
198
206
  /** Disable session management. Default: false. */
199
207
  sessionless?: boolean;
200
- /** Custom session ID generator. Default: crypto.randomUUID(). */
208
+ /**
209
+ * Custom session ID generator. Default: `crypto.randomUUID()`.
210
+ * Can be used to produce HMAC-signed session tokens for additional security.
211
+ */
201
212
  sessionIdGenerator?: () => string;
202
213
  /** Return JSON instead of SSE streams. Default: false. */
203
214
  enableJsonResponse?: boolean;
204
- /** Called on each HTTP request after session is resolved. Use to inject auth headers into sessions. */
215
+ /**
216
+ * Called on each HTTP request after session is resolved.
217
+ * Use to inject HTTP headers (e.g., Bearer tokens) into MCP sessions,
218
+ * or to validate that the requester owns the session (e.g., IP binding, token check).
219
+ */
205
220
  onRequest?: (req: Request, sessionId: string, session: Session) => void | Promise<void>;
206
221
  }
207
222
  interface MCPServer {
@@ -229,6 +244,8 @@ interface MCPServer {
229
244
  completeElicitation(elicitationId: string): void;
230
245
  /** The persistent store instance. */
231
246
  store: Store;
247
+ /** @experimental Wait for all running tasks to settle. For graceful shutdown. */
248
+ drain(): Promise<void>;
232
249
  }
233
250
 
234
251
  export { json as A, text as B, type Elicit as E, type HttpAdapterOptions as H, type MCPServer as M, type ResourceConfig as R, type ServerOptions as S, type TaskConfig as T, type User as U, type ElicitFormResult as a, type ElicitUrlOptions as b, type ElicitUrlResult as c, type ResourceContent as d, type ResourceContext as e, type ResourceHandler as f, type RootInfo as g, type Sample as h, type SampleOptions as i, type SampleRawParams as j, type SampleRawResult as k, type ServerInfo as l, type Session as m, type Store as n, type TaskContext as o, type TaskControl as p, type TaskHandler as q, type ToolConfig as r, type ToolContext as s, type ToolHandler as t, type ToolInfo as u, type ToolMiddleware as v, type ToolResponse as w, type UserStore as x, error as y, image as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynq/lynq",
3
- "version": "0.8.2",
3
+ "version": "0.8.3",
4
4
  "description": "Lightweight MCP server framework. Tool visibility control through middleware.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -1 +0,0 @@
1
- import {createHmac,timingSafeEqual}from'crypto';import {normalizeObjectSchema}from'@modelcontextprotocol/sdk/server/zod-compat.js';import {toJsonSchemaCompat}from'@modelcontextprotocol/sdk/server/zod-json-schema-compat.js';function h(e){if(e==null)return {type:"object"};let t=normalizeObjectSchema(e);return t?toJsonSchemaCompat(t):e}function T(e,t){let o=t[t.length-1];if(typeof o!="function")throw new TypeError(`${e}: last argument must be a handler function`);let n=t[t.length-2];if(n==null||typeof n!="object"||Array.isArray(n))throw new TypeError(`${e}: second-to-last argument must be a config object`);let r=t.slice(0,-2);for(let s of r)if(!s||typeof s!="object"||typeof s.name!="string")throw new TypeError(`${e}: each middleware must have a "name" property`);return {middlewares:r,config:n,handler:o}}function R(e,t){let o=[];for(let n of t)n.onRegister?.(e)===false&&o.push(n.name);return o}function x(e){let o=e.split(/\{[^}]+\}/).map(n=>n.replace(/[.*+?^$|()[\]\\]/g,"\\$&"));return new RegExp(`^${o.join("(.+)")}$`)}function y(e,t,o,n){let r=o.get(t);if(r==="disabled")return false;if(r==="enabled")return true;for(let s of e)if(!n.has(s))return false;return true}function b(e,t){let o=e.get(t);if(o)return o;for(let n of e.values())if(n.isTemplate&&n.uriPattern?.test(t))return n}function $(e,t,o){let n=`${e}:${t}`,r=createHmac("sha256",o).update(n).digest("hex");return `${n}:${r}`}function C(e,t){let o=e.split(":");if(o.length!==3)return null;let[n,r,s]=o,i=createHmac("sha256",t).update(`${n}:${r}`).digest("hex");try{if(!timingSafeEqual(Buffer.from(s,"hex"),Buffer.from(i,"hex")))return null}catch{return null}return {sessionId:n,elicitationId:r}}function M(e,t){if(!e)return false;let o=e.replace(/:\d+$/,"");return t.includes(o)}var S=["localhost","127.0.0.1","::1"];function j(e,t,o){let n=e.filter(l=>l.onCall),r=e.filter(l=>l.onResult).reverse(),s=0,i=async()=>{if(s>=n.length){let a=await o();for(let c of r)a=await c.onResult(a,t);return a}return n[s++].onCall(t,i)};return i}export{h as a,T as b,R as c,x as d,y as e,b as f,$ as g,C as h,M as i,S as j,j as k};
@@ -1 +0,0 @@
1
- function d(){let r=new Map;return {async get(e){let n=r.get(e);if(n){if(n.expiresAt!==void 0&&Date.now()>n.expiresAt){r.delete(e);return}return n.value}},async set(e,n,t){if(r.size>=1e3){let s=Date.now();for(let[i,o]of r)o.expiresAt!==void 0&&s>o.expiresAt&&r.delete(i);}r.set(e,{value:n,expiresAt:t!==void 0?Date.now()+t*1e3:void 0});},async delete(e){r.delete(e);}}}function u(r){let e=r.get("user");if(e){if(typeof e=="string")return e;if(typeof e=="object"&&e!==null){let n=e;if(typeof n.id=="string")return n.id;if(typeof n.id=="number")return String(n.id);if(typeof n.sub=="string")return n.sub}}}function f(r,e){let n=()=>{let t=u(r);if(!t){let s=r.get("user");if(s){let i=typeof s=="object"?JSON.stringify(s):typeof s;throw new Error(`userStore: session has a "user" but could not resolve an ID. Expected: string | { id: string | number } | { sub: string }. Got: ${i}`)}throw new Error("userStore requires a user in session. Call session.set('user', ...) first.")}return t};return {async get(t){return e.get(`user:${n()}:${t}`)},async set(t,s,i){await e.set(`user:${n()}:${t}`,s,i);},async delete(t){await e.delete(`user:${n()}:${t}`);}}}export{d as a,u as b,f as c};