@lunora/mcp 1.0.0-alpha.52 → 1.0.0-alpha.54

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.d.mts CHANGED
@@ -202,8 +202,16 @@ declare const NO_DEPLOYMENT_MESSAGE = "no Lunora dev server is running for this
202
202
  * surface that always works), then the caller's extras, then the deployment
203
203
  * tools. Order also decides precedence — `createToolServer` keeps the first
204
204
  * registration of a duplicated name.
205
+ *
206
+ * `clientFor` is the shared client cache built once by
207
+ * {@link createLocalMcpServer} and threaded into both the tool and resource
208
+ * surfaces. Exported (and called directly by tests) without going through
209
+ * `createLocalMcpServer`, so a caller that omits it gets a private,
210
+ * call-scoped cache — same shape as before this surface was shared, just
211
+ * without the cross-surface sharing that only matters once a resource
212
+ * surface exists alongside it.
205
213
  */
206
- declare const localTools: (options: LocalMcpServerOptions) => ReadonlyArray<McpTool>;
214
+ declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraClient) => ReadonlyArray<McpTool>;
207
215
  /** Build the composed local server without connecting a transport. */
208
216
  declare const createLocalMcpServer: (options?: LocalMcpServerOptions) => Server;
209
217
  /**
package/dist/index.d.ts CHANGED
@@ -202,8 +202,16 @@ declare const NO_DEPLOYMENT_MESSAGE = "no Lunora dev server is running for this
202
202
  * surface that always works), then the caller's extras, then the deployment
203
203
  * tools. Order also decides precedence — `createToolServer` keeps the first
204
204
  * registration of a duplicated name.
205
+ *
206
+ * `clientFor` is the shared client cache built once by
207
+ * {@link createLocalMcpServer} and threaded into both the tool and resource
208
+ * surfaces. Exported (and called directly by tests) without going through
209
+ * `createLocalMcpServer`, so a caller that omits it gets a private,
210
+ * call-scoped cache — same shape as before this surface was shared, just
211
+ * without the cross-surface sharing that only matters once a resource
212
+ * surface exists alongside it.
205
213
  */
206
- declare const localTools: (options: LocalMcpServerOptions) => ReadonlyArray<McpTool>;
214
+ declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraClient) => ReadonlyArray<McpTool>;
207
215
  /** Build the composed local server without connecting a transport. */
208
216
  declare const createLocalMcpServer: (options?: LocalMcpServerOptions) => Server;
209
217
  /**
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as c,callAgentTool as T,parseAgentsEnv as a}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{createToolServer as E}from"./packem_shared/createToolServer-CP5bNUcS.mjs";import{createMcpFetchHandler as _}from"./packem_shared/createMcpFetchHandler-DjvXAX80.mjs";import{LOCAL_SERVER_NAME as p,NO_DEPLOYMENT_MESSAGE as N,connectLocalStdio as O,createLocalMcpServer as A,localTools as f}from"./packem_shared/LOCAL_SERVER_NAME-CIbH2DKO.mjs";import{createPaidMcpServer as i}from"./packem_shared/createPaidMcpServer-Ba3uY4WX.mjs";import{connectStdio as m,createLunoraMcpServer as s}from"./packem_shared/connectStdio-Dt-DqEgA.mjs";import{READ_ONLY_TOOL_DEFINITIONS as I,WRITE_TOOL_DEFINITIONS as v,callTool as D,toolDefinitions as R}from"./packem_shared/READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";import{serveStateless as g}from"./packem_shared/serveStateless-BqoRk-xU.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,p as LOCAL_SERVER_NAME,N as NO_DEPLOYMENT_MESSAGE,I as READ_ONLY_TOOL_DEFINITIONS,v as WRITE_TOOL_DEFINITIONS,c as agentToolDefinitions,T as callAgentTool,D as callTool,O as connectLocalStdio,m as connectStdio,A as createLocalMcpServer,s as createLunoraMcpServer,_ as createMcpFetchHandler,i as createPaidMcpServer,E as createToolServer,f as localTools,a as parseAgentsEnv,g as serveStateless,R as toolDefinitions};
1
+ import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as c,callAgentTool as T,parseAgentsEnv as a}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{createToolServer as E}from"./packem_shared/createToolServer-CP5bNUcS.mjs";import{createMcpFetchHandler as _}from"./packem_shared/createMcpFetchHandler-DjvXAX80.mjs";import{LOCAL_SERVER_NAME as p,NO_DEPLOYMENT_MESSAGE as N,connectLocalStdio as O,createLocalMcpServer as A,localTools as f}from"./packem_shared/LOCAL_SERVER_NAME-Cj2isKb9.mjs";import{createPaidMcpServer as i}from"./packem_shared/createPaidMcpServer-CwdcSPpN.mjs";import{connectStdio as m,createLunoraMcpServer as s}from"./packem_shared/connectStdio-Dt-DqEgA.mjs";import{READ_ONLY_TOOL_DEFINITIONS as I,WRITE_TOOL_DEFINITIONS as v,callTool as D,toolDefinitions as R}from"./packem_shared/READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";import{serveStateless as g}from"./packem_shared/serveStateless-BqoRk-xU.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,p as LOCAL_SERVER_NAME,N as NO_DEPLOYMENT_MESSAGE,I as READ_ONLY_TOOL_DEFINITIONS,v as WRITE_TOOL_DEFINITIONS,c as agentToolDefinitions,T as callAgentTool,D as callTool,O as connectLocalStdio,m as connectStdio,A as createLocalMcpServer,s as createLunoraMcpServer,_ as createMcpFetchHandler,i as createPaidMcpServer,E as createToolServer,f as localTools,a as parseAgentsEnv,g as serveStateless,R as toolDefinitions};
@@ -0,0 +1 @@
1
+ import{LunoraClient as p}from"@lunora/client";import{StdioServerTransport as u}from"@modelcontextprotocol/sdk/server/stdio.js";import{createToolServer as f}from"./createToolServer-CP5bNUcS.mjs";import{createRemoteDocsIndex as c}from"./DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs";import{docsResources as m}from"./DOCS_URI_SCHEME-DbyotZvf.mjs";import{docsTools as h}from"./DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";import{toolDefinitions as v,callTool as y}from"./READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";const O=(t,e)=>{if(t.size<e)return;const o=t.keys().next().value;o!==void 0&&t.delete(o)},R="lunora",E="no Lunora dev server is running for this project — start one with `lunora dev`, then call this tool again (call lunora_dev_status to check).",P=8,l=t=>{const e=new Map;return o=>{const r=JSON.stringify([o.url,o.token??""]),n=e.get(r);if(n!==void 0)return n;const s=new p({fetch:t,url:o.url});return o.token!==void 0&&o.token.length>0&&s.setAuthToken(o.token),O(e,P),e.set(r,s),s}},T=(t,e,o)=>{const r=typeof t=="function"?t:()=>t;return v(e).map(n=>({definition:n,handle:async s=>{const i=r();return i===void 0?{content:[{text:E,type:"text"}],isError:!0}:y(o(i),n.name,s,e)}}))},_="lunora-spec:openrpc",w="lunora-spec:openapi",a=[{description:"The deployment's generated OpenRPC 1.x document — every RPC function's path, kind, and argument schema in one read, instead of list_functions plus one get_function_schema call per function.",fetch:async t=>t.fetchOpenRpc(),name:"OpenRPC specification",uri:_},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async t=>t.fetchOpenApi(),name:"OpenAPI specification",uri:w}],S=(t,e)=>{const o=typeof t=="function"?t:()=>t,r=async n=>{const s=o();if(s!==void 0)try{return await n.fetch(e(s))}catch{return}};return{list:async()=>(await Promise.all(a.map(async n=>await r(n)===void 0?void 0:{description:n.description,mimeType:"application/json",name:n.name,uri:n.uri}))).filter(n=>n!==void 0),read:async n=>{const s=a.find(d=>d.uri===n);if(s===void 0)return;const i=await r(s);return i===void 0?void 0:{mimeType:"application/json",text:JSON.stringify(i,void 0,2)}}}},g=t=>({list:async()=>(await Promise.all(t.map(async e=>e.list()))).flat(),read:async e=>{for(const o of t){const r=await o.read(e);if(r!==void 0)return r}}}),A=(t,e)=>{const o=[];return t.docs!==!1&&o.push(...h(c({...t.docs?.baseUrl===void 0?{}:{baseUrl:t.docs.baseUrl},...t.fetch===void 0?{}:{fetch:t.fetch}}))),o.push(...t.extraTools??[]),t.deployment!==void 0&&o.push(...T(t.deployment,t.allowWrites??!1,e??l(t.fetch))),o},U=(t={})=>{const e=t.docs===!1?void 0:c({...t.docs?.baseUrl===void 0?{}:{baseUrl:t.docs.baseUrl},...t.fetch===void 0?{}:{fetch:t.fetch}}),o=[];e!==void 0&&o.push(m(e));const r=l(t.fetch);return t.deployment!==void 0&&o.push(S(t.deployment,r)),f({name:R,version:t.version??"0.0.0"},A(t,r),o.length===0?void 0:g(o))},D=async(t={})=>{const e=U(t);return await e.connect(new u),e};export{R as LOCAL_SERVER_NAME,E as NO_DEPLOYMENT_MESSAGE,w as OPENAPI_RESOURCE_URI,_ as OPENRPC_RESOURCE_URI,D as connectLocalStdio,U as createLocalMcpServer,A as localTools};
@@ -0,0 +1 @@
1
+ import{LunoraError as p}from"@lunora/errors";import{Server as f}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as y,CallToolRequestSchema as g}from"@modelcontextprotocol/sdk/types.js";import{serveStateless as w}from"./serveStateless-BqoRk-xU.mjs";const S=async()=>{try{return(await import("@lunora/x402/charge")).createChargeMiddleware}catch(a){throw new p("INTERNAL",`paid MCP tools need the optional peer "@lunora/x402" — install it alongside @lunora/mcp to charge for tools (${a instanceof Error?a.message:String(a)})`)}},M={name:"lunora-paid-mcp",version:"0.0.0"},R="tools/call",d=a=>{if(typeof a!="object"||a===null)return;const{method:s,params:n}=a;if(s!==R||typeof n!="object"||n===null)return;const{name:i}=n;return typeof i=="string"?i:void 0},C=()=>Response.json({error:"A JSON-RPC batch may not reference a paid MCP tool; send paid tools/call requests individually."},{status:400}),P=()=>Response.json({error:"The request body could not be parsed as JSON; a priced MCP tool is registered, so the call cannot be gated."},{status:400}),j=a=>{const s=new Map,n=new Map,i=new Map,m=a.serverInfo??M,l=(e,t,o)=>{if(s.has(e.name))throw new p("BAD_REQUEST",`MCP tool "${e.name}" is already registered.`);const r={description:e.description,inputSchema:e.inputSchema,name:e.name};e.annotations!==void 0&&(r.annotations=e.annotations),s.set(e.name,{definition:r,handler:t}),o!==void 0&&n.set(e.name,o)},u=()=>{const e=new f(m,{capabilities:{tools:{}}});return e.setRequestHandler(y,()=>({tools:[...s.values()].map(t=>t.definition)})),e.setRequestHandler(g,async t=>{const o=s.get(t.params.name);return o===void 0?{content:[{text:`unknown tool: ${t.params.name}`,type:"text"}],isError:!0}:await o.handler(t.params.arguments??{})}),e},h=(e,t)=>{let o=i.get(e);if(o===void 0){const r=S().then(async c=>c({...a.charge,price:t},{resource:e})).catch(c=>{throw i.delete(e),c});o=r,i.set(e,r)}return o};return{fetchHandler:async e=>{let t;try{t=await e.clone().json()}catch{t=void 0}const o=()=>w(u(),e,t===void 0?void 0:{parsedBody:t});if(t===void 0&&n.size>0&&e.method==="POST")return P();if(Array.isArray(t))return t.some(v=>n.has(d(v)??""))?C():o();const r=d(t),c=r===void 0?void 0:n.get(r);return r===void 0||c===void 0?o():(await h(r,c)).handle(e,o)},paidTool:(e,t)=>{l(e,t,e.price)},tool:(e,t)=>{l(e,t)}}};export{j as createPaidMcpServer};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/mcp",
3
- "version": "1.0.0-alpha.52",
3
+ "version": "1.0.0-alpha.54",
4
4
  "description": "Model Context Protocol server exposing a Lunora deployment to AI agents",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -53,8 +53,8 @@
53
53
  "access": "public"
54
54
  },
55
55
  "dependencies": {
56
- "@lunora/client": "1.0.0-alpha.35",
57
- "@lunora/errors": "1.0.0-alpha.10",
56
+ "@lunora/client": "1.0.0-alpha.37",
57
+ "@lunora/errors": "1.0.0-alpha.12",
58
58
  "@modelcontextprotocol/sdk": "^1.29.0"
59
59
  },
60
60
  "peerDependencies": {
@@ -1 +0,0 @@
1
- import{LunoraClient as l}from"@lunora/client";import{StdioServerTransport as d}from"@modelcontextprotocol/sdk/server/stdio.js";import{createToolServer as f}from"./createToolServer-CP5bNUcS.mjs";import{createRemoteDocsIndex as a}from"./DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs";import{docsResources as u}from"./DOCS_URI_SCHEME-DbyotZvf.mjs";import{docsTools as m}from"./DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";import{toolDefinitions as p,callTool as v}from"./READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";const h="lunora",S="no Lunora dev server is running for this project — start one with `lunora dev`, then call this tool again (call lunora_dev_status to check).",T=o=>{const t=new Map;return e=>{const n=JSON.stringify([e.url,e.token??""]),s=t.get(n);if(s!==void 0)return s;const r=new l({fetch:o,url:e.url});return e.token!==void 0&&e.token.length>0&&r.setAuthToken(e.token),t.set(n,r),r}},y=(o,t,e)=>{const n=typeof o=="function"?o:()=>o,s=T(e);return p(t).map(r=>({definition:r,handle:async i=>{const c=n();return c===void 0?{content:[{text:S,type:"text"}],isError:!0}:v(s(c),r.name,i,t)}}))},E=o=>{const t=[];return o.docs!==!1&&t.push(...m(a({...o.docs?.baseUrl===void 0?{}:{baseUrl:o.docs.baseUrl},...o.fetch===void 0?{}:{fetch:o.fetch}}))),t.push(...o.extraTools??[]),o.deployment!==void 0&&t.push(...y(o.deployment,o.allowWrites??!1,o.fetch)),t},L=(o={})=>{const t=o.docs===!1?void 0:a({...o.docs?.baseUrl===void 0?{}:{baseUrl:o.docs.baseUrl},...o.fetch===void 0?{}:{fetch:o.fetch}});return f({name:h,version:o.version??"0.0.0"},E(o),t===void 0?void 0:u(t))},x=async(o={})=>{const t=L(o);return await t.connect(new d),t};export{h as LOCAL_SERVER_NAME,S as NO_DEPLOYMENT_MESSAGE,x as connectLocalStdio,L as createLocalMcpServer,E as localTools};
@@ -1 +0,0 @@
1
- import{LunoraError as p}from"@lunora/errors";import{Server as f}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as y,CallToolRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{serveStateless as g}from"./serveStateless-BqoRk-xU.mjs";const S=async()=>{try{return(await import("@lunora/x402/charge")).createChargeMiddleware}catch(a){throw new p("INTERNAL",`paid MCP tools need the optional peer "@lunora/x402" — install it alongside @lunora/mcp to charge for tools (${a instanceof Error?a.message:String(a)})`)}},M={name:"lunora-paid-mcp",version:"0.0.0"},R="tools/call",d=a=>{if(typeof a!="object"||a===null)return;const{method:s,params:n}=a;if(s!==R||typeof n!="object"||n===null)return;const{name:i}=n;return typeof i=="string"?i:void 0},C=()=>Response.json({error:"A JSON-RPC batch may not reference a paid MCP tool; send paid tools/call requests individually."},{status:400}),T=a=>{const s=new Map,n=new Map,i=new Map,m=a.serverInfo??M,l=(e,t,o)=>{if(s.has(e.name))throw new p("BAD_REQUEST",`MCP tool "${e.name}" is already registered.`);const r={description:e.description,inputSchema:e.inputSchema,name:e.name};e.annotations!==void 0&&(r.annotations=e.annotations),s.set(e.name,{definition:r,handler:t}),o!==void 0&&n.set(e.name,o)},u=()=>{const e=new f(m,{capabilities:{tools:{}}});return e.setRequestHandler(y,()=>({tools:[...s.values()].map(t=>t.definition)})),e.setRequestHandler(w,async t=>{const o=s.get(t.params.name);return o===void 0?{content:[{text:`unknown tool: ${t.params.name}`,type:"text"}],isError:!0}:await o.handler(t.params.arguments??{})}),e},h=(e,t)=>{let o=i.get(e);if(o===void 0){const r=S().then(async c=>c({...a.charge,price:t},{resource:e})).catch(c=>{throw i.delete(e),c});o=r,i.set(e,r)}return o};return{fetchHandler:async e=>{let t;try{t=await e.clone().json()}catch{t=void 0}const o=()=>g(u(),e,t===void 0?void 0:{parsedBody:t});if(Array.isArray(t))return t.some(v=>n.has(d(v)??""))?C():o();const r=d(t),c=r===void 0?void 0:n.get(r);return r===void 0||c===void 0?o():(await h(r,c)).handle(e,o)},paidTool:(e,t)=>{l(e,t,e.price)},tool:(e,t)=>{l(e,t)}}};export{T as createPaidMcpServer};