@lunora/mcp 1.0.0-alpha.266 → 1.0.0-alpha.268

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.
Files changed (27) hide show
  1. package/dist/bin.mjs +1 -1
  2. package/dist/index.d.mts +3 -2
  3. package/dist/index.d.ts +3 -2
  4. package/dist/index.mjs +1 -1
  5. package/dist/node/index.d.mts +5 -4
  6. package/dist/node/index.d.ts +5 -4
  7. package/dist/node/index.mjs +1 -1
  8. package/dist/packem_shared/LOCAL_SERVER_NAME-xQYvyGAB.mjs +1 -0
  9. package/dist/packem_shared/{READ_ONLY_TOOL_DEFINITIONS-BimWNHPm.mjs → READ_ONLY_TOOL_DEFINITIONS-DI9mSjr0.mjs} +1 -1
  10. package/dist/packem_shared/{connectFunctionStdio-BUJLHLSs.mjs → connectFunctionStdio-C4FoDfG8.mjs} +1 -1
  11. package/dist/packem_shared/{connectStdio-CGRp07EO.mjs → connectStdio-d78bTcl1.mjs} +1 -1
  12. package/dist/packem_shared/{createAuthedMcpFetchHandler-mn8Eh3Xo.mjs → createAuthedMcpFetchHandler-Biw5KD-9.mjs} +1 -1
  13. package/dist/packem_shared/{createFunctionMcpServer-DI_L4fPb.mjs → createFunctionMcpServer-BWaeQOFi.mjs} +1 -1
  14. package/dist/packem_shared/createLunoraMcpServer-Dv-ke-g5.mjs +1 -0
  15. package/dist/packem_shared/{createMcpFetchHandler-D_kQUgVT.mjs → createMcpFetchHandler-McfnLMme.mjs} +1 -1
  16. package/dist/packem_shared/{function-server.d-D_0-WiS2.d.mts → function-server.d-BoX-fd2B.d.mts} +4 -3
  17. package/dist/packem_shared/{function-server.d-ByIkBRXs.d.ts → function-server.d-CnHt2Sb1.d.ts} +4 -3
  18. package/dist/packem_shared/package-B4stRteb.mjs +1 -0
  19. package/dist/packem_shared/tools-BMou4kPK.mjs +2 -0
  20. package/dist/worker/index.d.mts +5 -4
  21. package/dist/worker/index.d.ts +5 -4
  22. package/dist/worker/index.mjs +1 -1
  23. package/package.json +4 -4
  24. package/dist/packem_shared/LOCAL_SERVER_NAME-BAK3cHeB.mjs +0 -1
  25. package/dist/packem_shared/createLunoraMcpServer-BC7nvLcl.mjs +0 -1
  26. package/dist/packem_shared/package-7WeW8c_h.mjs +0 -1
  27. package/dist/packem_shared/tools-Bylr9LPQ.mjs +0 -2
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{parseAgentsEnv as N}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import l from"./packem_shared/connectStdio-CGRp07EO.mjs";const E=new Set(["1","on","true","yes"]),o=r=>r!==void 0&&E.has(r.trim().toLowerCase());class s extends Error{code;constructor(e,a){super(e),this.name="BinError",this.code=a}}const O=async(r,e={})=>{const a=e.connect??l,i=e.writeError??(t=>{process.stderr.write(t)}),n=r.LUNORA_URL;if(n===void 0||n.length===0)throw i(`lunora-mcp: LUNORA_URL environment variable is required
2
+ import{parseAgentsEnv as N}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import l from"./packem_shared/connectStdio-d78bTcl1.mjs";const E=new Set(["1","on","true","yes"]),o=r=>r!==void 0&&E.has(r.trim().toLowerCase());class s extends Error{code;constructor(e,a){super(e),this.name="BinError",this.code=a}}const O=async(r,e={})=>{const a=e.connect??l,i=e.writeError??(t=>{process.stderr.write(t)}),n=r.LUNORA_URL;if(n===void 0||n.length===0)throw i(`lunora-mcp: LUNORA_URL environment variable is required
3
3
  `),new s("LUNORA_URL environment variable is required",1);const c=r.LUNORA_ADMIN_TOKEN;if(c===void 0||c.length===0)throw i(`lunora-mcp: LUNORA_ADMIN_TOKEN environment variable is required (every tool reads admin-gated routes)
4
4
  `),new s("LUNORA_ADMIN_TOKEN environment variable is required",1);const A=Number(r.LUNORA_MCP_AGENT_TIMEOUT_MS),_=Number.isFinite(A)&&A>0?A:void 0;try{await a({agents:N(r.LUNORA_MCP_AGENTS),allowAgents:o(r.LUNORA_MCP_ALLOW_AGENTS),allowDataReads:o(r.LUNORA_MCP_ALLOW_DATA_READS),allowObservability:o(r.LUNORA_MCP_ALLOW_OBSERVABILITY),allowWrites:o(r.LUNORA_MCP_ALLOW_WRITES),token:c,url:n,..._===void 0?{}:{agentMaxWaitMs:_}})}catch(t){const L=t instanceof Error?t.message:String(t);throw i(`lunora-mcp: failed to start — ${L}
5
5
  `),new s(`failed to start — ${L}`,1)}};try{await O(process.env)}catch(r){process.exit(r instanceof s?r.code:1)}
package/dist/index.d.mts CHANGED
@@ -74,11 +74,12 @@ type C as CallAgentToolOptions, type F as FunctionMcpServerOptions, type L as Lu
74
74
  * better-auth's MCP OAuth gate (`requireMcpAuth` from `@lunora/auth/plugins`)
75
75
  * and can scope tool exposure to the access token's own scopes.
76
76
  */
77
- type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, e as createLunoraMcpServer, p as parseAgentsEnv } from "./packem_shared/function-server.d-D_0-WiS2.mjs";
77
+ type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, e as createLunoraMcpServer, p as parseAgentsEnv } from "./packem_shared/function-server.d-BoX-fd2B.mjs";
78
78
  export { type AuthedMcpFetchHandlerOptions, type AuthedMcpServerOptions, type McpAccessTokenClaims, type McpAuthProtect, type McpFetchHandlerOptions, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpExecutionContext, type PaidMcpFetchHandler, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolHandler, WRITE_TOOL_DEFINITIONS, callTool, createAuthedMcpFetchHandler, createMcpFetchHandler, createPaidMcpServer, mcpTokenScopes, toolDefinitions } from "./worker/index.mjs";
79
79
  export { type M as McpServerInfo, type a as McpTool, type T as ToolDefinition, type b as ToolInputSchema, type c as ToolOutputSchema, type d as ToolResult, e as createToolServer } from "./packem_shared/compose.d-DiPnHeQv.mjs";
80
80
  export { LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, NO_DEPLOYMENT_MESSAGE, connectFunctionStdio, connectLocalStdio, connectStdio, createLocalMcpServer, localTools } from "./node/index.mjs";
81
81
  export { D as DEFAULT_MAX_REQUEST_BYTES, type M as McpFetchHandler, type S as ServeStatelessOptions, s as serveStateless } from "./packem_shared/serve-stateless.d-DD5arqFx.mjs";
82
- import '@lunora/client';
82
+ import '@lunora/client/admin';
83
83
  import '@modelcontextprotocol/sdk/server/index.js';
84
+ import '@lunora/client';
84
85
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
package/dist/index.d.ts CHANGED
@@ -74,11 +74,12 @@ type C as CallAgentToolOptions, type F as FunctionMcpServerOptions, type L as Lu
74
74
  * better-auth's MCP OAuth gate (`requireMcpAuth` from `@lunora/auth/plugins`)
75
75
  * and can scope tool exposure to the access token's own scopes.
76
76
  */
77
- type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, e as createLunoraMcpServer, p as parseAgentsEnv } from "./packem_shared/function-server.d-ByIkBRXs.js";
77
+ type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, e as createLunoraMcpServer, p as parseAgentsEnv } from "./packem_shared/function-server.d-CnHt2Sb1.js";
78
78
  export { type AuthedMcpFetchHandlerOptions, type AuthedMcpServerOptions, type McpAccessTokenClaims, type McpAuthProtect, type McpFetchHandlerOptions, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpExecutionContext, type PaidMcpFetchHandler, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolHandler, WRITE_TOOL_DEFINITIONS, callTool, createAuthedMcpFetchHandler, createMcpFetchHandler, createPaidMcpServer, mcpTokenScopes, toolDefinitions } from "./worker/index.js";
79
79
  export { type M as McpServerInfo, type a as McpTool, type T as ToolDefinition, type b as ToolInputSchema, type c as ToolOutputSchema, type d as ToolResult, e as createToolServer } from "./packem_shared/compose.d-DiPnHeQv.js";
80
80
  export { LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, NO_DEPLOYMENT_MESSAGE, connectFunctionStdio, connectLocalStdio, connectStdio, createLocalMcpServer, localTools } from "./node/index.js";
81
81
  export { D as DEFAULT_MAX_REQUEST_BYTES, type M as McpFetchHandler, type S as ServeStatelessOptions, s as serveStateless } from "./packem_shared/serve-stateless.d-DD5arqFx.js";
82
- import '@lunora/client';
82
+ import '@lunora/client/admin';
83
83
  import '@modelcontextprotocol/sdk/server/index.js';
84
+ import '@lunora/client';
84
85
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
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 a,parseAgentsEnv as T}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{createAuthedMcpFetchHandler as p,mcpTokenScopes as E}from"./packem_shared/createAuthedMcpFetchHandler-mn8Eh3Xo.mjs";import{createToolServer as _}from"./packem_shared/createToolServer-CHAjfuNx.mjs";import{createFunctionMcpServer as f}from"./packem_shared/createFunctionMcpServer-DI_L4fPb.mjs";import{default as s}from"./packem_shared/connectFunctionStdio-BUJLHLSs.mjs";import{createMcpFetchHandler as N}from"./packem_shared/createMcpFetchHandler-D_kQUgVT.mjs";import{LOCAL_SERVER_NAME as x,NO_DEPLOYMENT_MESSAGE as I,connectLocalStdio as L,createLocalMcpServer as i,localTools as M}from"./packem_shared/LOCAL_SERVER_NAME-BAK3cHeB.mjs";import{createPaidMcpServer as D}from"./packem_shared/createPaidMcpServer-CdDLw3G4.mjs";import{createLunoraMcpServer as R}from"./packem_shared/createLunoraMcpServer-BC7nvLcl.mjs";import{default as u}from"./packem_shared/connectStdio-CGRp07EO.mjs";import{R as Y,W as g,c as h,t as B}from"./packem_shared/tools-Bylr9LPQ.mjs";import{DEFAULT_MAX_REQUEST_BYTES as H,serveStateless as P}from"./packem_shared/DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as V}from"./packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,H as DEFAULT_MAX_REQUEST_BYTES,x as LOCAL_SERVER_NAME,I as NO_DEPLOYMENT_MESSAGE,V as OBSERVABILITY_TOOL_DEFINITIONS,Y as READ_ONLY_TOOL_DEFINITIONS,g as WRITE_TOOL_DEFINITIONS,c as agentToolDefinitions,a as callAgentTool,h as callTool,s as connectFunctionStdio,L as connectLocalStdio,u as connectStdio,p as createAuthedMcpFetchHandler,f as createFunctionMcpServer,i as createLocalMcpServer,R as createLunoraMcpServer,N as createMcpFetchHandler,D as createPaidMcpServer,_ as createToolServer,M as localTools,E as mcpTokenScopes,T as parseAgentsEnv,P as serveStateless,B as toolDefinitions};
1
+ import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as c,callAgentTool as a,parseAgentsEnv as T}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{createAuthedMcpFetchHandler as p,mcpTokenScopes as E}from"./packem_shared/createAuthedMcpFetchHandler-Biw5KD-9.mjs";import{createToolServer as _}from"./packem_shared/createToolServer-CHAjfuNx.mjs";import{createFunctionMcpServer as f}from"./packem_shared/createFunctionMcpServer-BWaeQOFi.mjs";import{default as s}from"./packem_shared/connectFunctionStdio-C4FoDfG8.mjs";import{createMcpFetchHandler as N}from"./packem_shared/createMcpFetchHandler-McfnLMme.mjs";import{LOCAL_SERVER_NAME as x,NO_DEPLOYMENT_MESSAGE as I,connectLocalStdio as L,createLocalMcpServer as i,localTools as M}from"./packem_shared/LOCAL_SERVER_NAME-xQYvyGAB.mjs";import{createPaidMcpServer as D}from"./packem_shared/createPaidMcpServer-CdDLw3G4.mjs";import{createLunoraMcpServer as R}from"./packem_shared/createLunoraMcpServer-Dv-ke-g5.mjs";import{default as u}from"./packem_shared/connectStdio-d78bTcl1.mjs";import{R as Y,W as g,c as h,t as B}from"./packem_shared/tools-BMou4kPK.mjs";import{DEFAULT_MAX_REQUEST_BYTES as H,serveStateless as P}from"./packem_shared/DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as V}from"./packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,H as DEFAULT_MAX_REQUEST_BYTES,x as LOCAL_SERVER_NAME,I as NO_DEPLOYMENT_MESSAGE,V as OBSERVABILITY_TOOL_DEFINITIONS,Y as READ_ONLY_TOOL_DEFINITIONS,g as WRITE_TOOL_DEFINITIONS,c as agentToolDefinitions,a as callAgentTool,h as callTool,s as connectFunctionStdio,L as connectLocalStdio,u as connectStdio,p as createAuthedMcpFetchHandler,f as createFunctionMcpServer,i as createLocalMcpServer,R as createLunoraMcpServer,N as createMcpFetchHandler,D as createPaidMcpServer,_ as createToolServer,M as localTools,E as mcpTokenScopes,T as parseAgentsEnv,P as serveStateless,B as toolDefinitions};
@@ -1,8 +1,9 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { F as FunctionMcpServerOptions, L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-D_0-WiS2.mjs";
3
- export { e as createLunoraMcpServer } from "../packem_shared/function-server.d-D_0-WiS2.mjs";
4
- import { LunoraClient } from '@lunora/client';
2
+ import { F as FunctionMcpServerOptions, L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-BoX-fd2B.mjs";
3
+ export { e as createLunoraMcpServer } from "../packem_shared/function-server.d-BoX-fd2B.mjs";
4
+ import { LunoraAdminClient } from '@lunora/client/admin';
5
5
  import { a as McpTool } from "../packem_shared/compose.d-DiPnHeQv.mjs";
6
+ import '@lunora/client';
6
7
  /**
7
8
  * Build a per-function server and connect it over stdio, the transport an editor
8
9
  * spawns. Resolves once the transport is connected; the process then stays alive
@@ -70,7 +71,7 @@ declare const NO_DEPLOYMENT_MESSAGE = "no Lunora dev server is running for this
70
71
  * without the cross-surface sharing that only matters once a resource
71
72
  * surface exists alongside it.
72
73
  */
73
- declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraClient) => ReadonlyArray<McpTool>;
74
+ declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraAdminClient) => ReadonlyArray<McpTool>;
74
75
  /** Build the composed local server without connecting a transport. */
75
76
  declare const createLocalMcpServer: (options?: LocalMcpServerOptions) => Server;
76
77
  /**
@@ -1,8 +1,9 @@
1
1
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
- import { F as FunctionMcpServerOptions, L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-ByIkBRXs.js";
3
- export { e as createLunoraMcpServer } from "../packem_shared/function-server.d-ByIkBRXs.js";
4
- import { LunoraClient } from '@lunora/client';
2
+ import { F as FunctionMcpServerOptions, L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-CnHt2Sb1.js";
3
+ export { e as createLunoraMcpServer } from "../packem_shared/function-server.d-CnHt2Sb1.js";
4
+ import { LunoraAdminClient } from '@lunora/client/admin';
5
5
  import { a as McpTool } from "../packem_shared/compose.d-DiPnHeQv.js";
6
+ import '@lunora/client';
6
7
  /**
7
8
  * Build a per-function server and connect it over stdio, the transport an editor
8
9
  * spawns. Resolves once the transport is connected; the process then stays alive
@@ -70,7 +71,7 @@ declare const NO_DEPLOYMENT_MESSAGE = "no Lunora dev server is running for this
70
71
  * without the cross-surface sharing that only matters once a resource
71
72
  * surface exists alongside it.
72
73
  */
73
- declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraClient) => ReadonlyArray<McpTool>;
74
+ declare const localTools: (options: LocalMcpServerOptions, clientFor?: (deployment: LocalDeployment) => LunoraAdminClient) => ReadonlyArray<McpTool>;
74
75
  /** Build the composed local server without connecting a transport. */
75
76
  declare const createLocalMcpServer: (options?: LocalMcpServerOptions) => Server;
76
77
  /**
@@ -1 +1 @@
1
- import{default as r}from"../packem_shared/connectFunctionStdio-BUJLHLSs.mjs";import{LOCAL_SERVER_NAME as c,NO_DEPLOYMENT_MESSAGE as a,connectLocalStdio as n,createLocalMcpServer as S,localTools as l}from"../packem_shared/LOCAL_SERVER_NAME-BAK3cHeB.mjs";import{createLunoraMcpServer as f}from"../packem_shared/createLunoraMcpServer-BC7nvLcl.mjs";import{default as L}from"../packem_shared/connectStdio-CGRp07EO.mjs";export{c as LOCAL_SERVER_NAME,a as NO_DEPLOYMENT_MESSAGE,r as connectFunctionStdio,n as connectLocalStdio,L as connectStdio,S as createLocalMcpServer,f as createLunoraMcpServer,l as localTools};
1
+ import{default as r}from"../packem_shared/connectFunctionStdio-C4FoDfG8.mjs";import{LOCAL_SERVER_NAME as c,NO_DEPLOYMENT_MESSAGE as a,connectLocalStdio as n,createLocalMcpServer as S,localTools as l}from"../packem_shared/LOCAL_SERVER_NAME-xQYvyGAB.mjs";import{createLunoraMcpServer as f}from"../packem_shared/createLunoraMcpServer-Dv-ke-g5.mjs";import{default as L}from"../packem_shared/connectStdio-d78bTcl1.mjs";export{c as LOCAL_SERVER_NAME,a as NO_DEPLOYMENT_MESSAGE,r as connectFunctionStdio,n as connectLocalStdio,L as connectStdio,S as createLocalMcpServer,f as createLunoraMcpServer,l as localTools};
@@ -0,0 +1 @@
1
+ import{LunoraAdminClient as m}from"@lunora/client/admin";import{StdioServerTransport as f}from"@modelcontextprotocol/sdk/server/stdio.js";import{e as p}from"./promise-memo-OqVPWoUX.mjs";import{createToolServer as v}from"./createToolServer-CHAjfuNx.mjs";import{createRemoteDocsIndex as h}from"./DEFAULT_DOCS_BASE_URL-CiHy_Dbz.mjs";import{docsResources as E}from"./DOCS_URI_SCHEME-DBlxtzS6.mjs";import{docsTools as R}from"./DEFAULT_SEARCH_LIMIT-BMQ6HQ-x.mjs";import{E as O,a as y,t as T,b as _,c as S}from"./tools-BMou4kPK.mjs";import{e as P}from"./tool-result-CPDsNNuJ.mjs";const l=e=>e.docs===!1?void 0:h({...e.docs?.baseUrl===void 0?{}:{baseUrl:e.docs.baseUrl},...e.fetch===void 0?{}:{fetch:e.fetch}}),C="lunora",N="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).",A=8,d=e=>{const n=new Map;return t=>{const r=JSON.stringify([t.url,t.token??""]),c=n.get(r);if(c!==void 0)return c;const o=new m({fetch:e,url:t.url});return t.token!==void 0&&t.token.length>0&&o.setAuthToken(t.token),p(n,A),n.set(r,o),o}},i=e=>e?.token!==void 0&&e.token.length>0,g=(e,n,t)=>{const r=typeof e=="function"?e:()=>e;return T(n,i(r())).filter(c=>!_.has(c.name)).map(c=>({definition:c,handle:async o=>{const s=r();return s===void 0?P("NO_DEPLOYMENT",N):S(t(s),c.name,o,n,i(s))}}))},I=()=>O.map(e=>({definition:e,handle:n=>Promise.resolve(y(e.name,n))})),k="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 e=>e.fetchOpenRpc(),name:"OpenRPC specification",uri:k},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async e=>e.fetchOpenApi(),name:"OpenAPI specification",uri:w}],L=(e,n)=>{const t=typeof e=="function"?e:()=>e,r=async c=>{const o=t();if(o!==void 0)try{return await c.fetch(n(o))}catch{return}};return{list:async()=>(await Promise.all(a.map(async o=>await r(o)===void 0?void 0:{description:o.description,mimeType:"application/json",name:o.name,uri:o.uri}))).filter(o=>o!==void 0),read:async c=>{const o=a.find(u=>u.uri===c);if(o===void 0)return;const s=await r(o);return s===void 0?void 0:{mimeType:"application/json",text:JSON.stringify(s,void 0,2)}}}},x=e=>({list:async()=>(await Promise.all(e.map(async t=>t.list()))).flat(),read:async n=>{for(const t of e){const r=await t.read(n);if(r!==void 0)return r}}}),M=(e,n)=>{const t=[],r=l(e);return r!==void 0&&t.push(...R(r)),t.push(...e.extraTools??[],...I()),e.deployment!==void 0&&t.push(...g(e.deployment,e.allowWrites??!1,n??d(e.fetch))),t},U=(e={})=>{const n=l(e),t=[];n!==void 0&&t.push(E(n));const r=d(e.fetch);return e.deployment!==void 0&&t.push(L(e.deployment,r)),v({name:C,version:e.version??"0.0.0"},M(e,r),t.length===0?void 0:x(t))},V=async(e={})=>{const n=U(e);return await n.connect(new f),n};export{C as LOCAL_SERVER_NAME,N as NO_DEPLOYMENT_MESSAGE,w as OPENAPI_RESOURCE_URI,k as OPENRPC_RESOURCE_URI,V as connectLocalStdio,U as createLocalMcpServer,M as localTools};
@@ -1 +1 @@
1
- import{D as E,O as _,R as s,h as a,S as o,W as S,d as D,c as A,r as N,s as r,t as R}from"./tools-Bylr9LPQ.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as t}from"./OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";import"./tool-result-CPDsNNuJ.mjs";export{E as DATA_READ_SCOPE,_ as OBSERVABILITY_SCOPE,t as OBSERVABILITY_TOOL_DEFINITIONS,s as READ_ONLY_TOOL_DEFINITIONS,a as ROW_READ_TOOL_DEFINITIONS,o as SCOPED_GATES,S as WRITE_TOOL_DEFINITIONS,D as WRITE_TOOL_NAMES,A as callTool,N as readArgumentsBag,r as scopeForTool,R as toolDefinitions};
1
+ import{D as E,O as _,R as s,h as a,S as o,W as S,d as D,c as A,r as N,s as r,t as R}from"./tools-BMou4kPK.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as t}from"./OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";import"./tool-result-CPDsNNuJ.mjs";export{E as DATA_READ_SCOPE,_ as OBSERVABILITY_SCOPE,t as OBSERVABILITY_TOOL_DEFINITIONS,s as READ_ONLY_TOOL_DEFINITIONS,a as ROW_READ_TOOL_DEFINITIONS,o as SCOPED_GATES,S as WRITE_TOOL_DEFINITIONS,D as WRITE_TOOL_NAMES,A as callTool,N as readArgumentsBag,r as scopeForTool,R as toolDefinitions};
@@ -1 +1 @@
1
- import{StdioServerTransport as e}from"@modelcontextprotocol/sdk/server/stdio.js";import{createFunctionMcpServer as n}from"./createFunctionMcpServer-DI_L4fPb.mjs";const a=async t=>{const r=n(t);return await r.connect(new e),r};export{a as default};
1
+ import{StdioServerTransport as e}from"@modelcontextprotocol/sdk/server/stdio.js";import{createFunctionMcpServer as n}from"./createFunctionMcpServer-BWaeQOFi.mjs";const a=async t=>{const r=n(t);return await r.connect(new e),r};export{a as default};
@@ -1 +1 @@
1
- import{StdioServerTransport as i}from"@modelcontextprotocol/sdk/server/stdio.js";import{readFileSync as a}from"node:fs";import{dirname as n,join as c}from"node:path";import{fileURLToPath as s}from"node:url";import{createLunoraMcpServer as m}from"./createLunoraMcpServer-BC7nvLcl.mjs";const p=()=>{let r=n(s(import.meta.url));for(let e=0;e<8;e+=1){try{const o=JSON.parse(a(c(r,"package.json"),"utf8"));if(o.name==="@lunora/mcp"&&typeof o.version=="string"&&o.version.length>0)return o.version}catch{}const t=n(r);if(t===r)break;r=t}},S=async r=>{const e=p(),t=m(e===void 0?r:{version:e,...r});return await t.connect(new i),t};export{S as default};
1
+ import{StdioServerTransport as i}from"@modelcontextprotocol/sdk/server/stdio.js";import{readFileSync as a}from"node:fs";import{dirname as n,join as c}from"node:path";import{fileURLToPath as s}from"node:url";import{createLunoraMcpServer as m}from"./createLunoraMcpServer-Dv-ke-g5.mjs";const p=()=>{let r=n(s(import.meta.url));for(let e=0;e<8;e+=1){try{const o=JSON.parse(a(c(r,"package.json"),"utf8"));if(o.name==="@lunora/mcp"&&typeof o.version=="string"&&o.version.length>0)return o.version}catch{}const t=n(r);if(t===r)break;r=t}},S=async r=>{const e=p(),t=m(e===void 0?r:{version:e,...r});return await t.connect(new i),t};export{S as default};
@@ -1 +1 @@
1
- import{LunoraError as y}from"@lunora/errors";import{isAgentToolName as S}from"./AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{readScreenedBody as g,serveStateless as w}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{resolveClient as d,createLunoraMcpServer as T}from"./createLunoraMcpServer-BC7nvLcl.mjs";import{c as M}from"./tool-call-Bs-QeKp6.mjs";import{d as E,s as _,S as k}from"./tools-Bylr9LPQ.mjs";const A=t=>typeof t.scope!="string"?new Set:new Set(t.scope.split(" ").filter(c=>c!=="")),C=(t,c)=>{const o={...t};for(const{flag:s,scope:n}of k)o[s]=t[s]===!0&&c.has(n);return o},I=(t,c,o)=>{const s=new Set,n=c.agents??[];for(const l of t){const e=M(l);if(e===void 0)continue;(E.has(e)||S(e,n))&&s.add(o);const r=_(e,c);r!==void 0&&s.add(r)}return s},N=256,B=t=>{const{maxRequestBytes:c,stepUp:o}=t;if(o!==void 0&&(typeof o.scope!="string"||o.scope===""||typeof o.challenge!="function"))throw new y("MCP_STEP_UP_MISCONFIGURED","createAuthedMcpFetchHandler: `stepUp` needs a non-empty `scope` and a `challenge` function.");const s=typeof t.server=="function"?void 0:d(t.server),n=new Map,l=e=>{if(e.client!==void 0||e.url===void 0||e.token===void 0||e.token.length===0)return d(e);const r=JSON.stringify([e.url,e.token]),i=n.get(r);if(i!==void 0&&i.fetch===e.fetch)return n.delete(r),n.set(r,i),i.client;const f=d(e);return n.delete(r),n.set(r,{client:f,fetch:e.fetch}),n.size>N&&n.delete(n.keys().next().value),f};return t.protect(async(e,r)=>{const i=A(r),f=typeof t.server=="function"?await t.server(r):{...t.server,client:s};let a;if(o!==void 0){const p=await g(e,c);if("response"in p)return p.response;({parsedBody:a}=p);const m=Array.isArray(a)?a:[a],u=[...I(m,f,o.scope)].filter(v=>!i.has(v));if(u.length>0)throw o.challenge(u)}const h=C(typeof t.server=="function"?{...f,client:l(f)}:f,i);return await w(T(h),e,{maxRequestBytes:c,parsedBody:a})})};export{B as createAuthedMcpFetchHandler,A as mcpTokenScopes};
1
+ import{LunoraError as y}from"@lunora/errors";import{isAgentToolName as S}from"./AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{readScreenedBody as g,serveStateless as w}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{resolveClient as d,createLunoraMcpServer as T}from"./createLunoraMcpServer-Dv-ke-g5.mjs";import{c as M}from"./tool-call-Bs-QeKp6.mjs";import{d as E,s as _,S as k}from"./tools-BMou4kPK.mjs";const A=t=>typeof t.scope!="string"?new Set:new Set(t.scope.split(" ").filter(c=>c!=="")),C=(t,c)=>{const o={...t};for(const{flag:s,scope:n}of k)o[s]=t[s]===!0&&c.has(n);return o},I=(t,c,o)=>{const s=new Set,n=c.agents??[];for(const l of t){const e=M(l);if(e===void 0)continue;(E.has(e)||S(e,n))&&s.add(o);const r=_(e,c);r!==void 0&&s.add(r)}return s},N=256,B=t=>{const{maxRequestBytes:c,stepUp:o}=t;if(o!==void 0&&(typeof o.scope!="string"||o.scope===""||typeof o.challenge!="function"))throw new y("MCP_STEP_UP_MISCONFIGURED","createAuthedMcpFetchHandler: `stepUp` needs a non-empty `scope` and a `challenge` function.");const s=typeof t.server=="function"?void 0:d(t.server),n=new Map,l=e=>{if(e.client!==void 0||e.url===void 0||e.token===void 0||e.token.length===0)return d(e);const r=JSON.stringify([e.url,e.token]),i=n.get(r);if(i!==void 0&&i.fetch===e.fetch)return n.delete(r),n.set(r,i),i.client;const f=d(e);return n.delete(r),n.set(r,{client:f,fetch:e.fetch}),n.size>N&&n.delete(n.keys().next().value),f};return t.protect(async(e,r)=>{const i=A(r),f=typeof t.server=="function"?await t.server(r):{...t.server,client:s};let a;if(o!==void 0){const p=await g(e,c);if("response"in p)return p.response;({parsedBody:a}=p);const m=Array.isArray(a)?a:[a],u=[...I(m,f,o.scope)].filter(v=>!i.has(v));if(u.length>0)throw o.challenge(u)}const h=C(typeof t.server=="function"?{...f,client:l(f)}:f,i);return await w(T(h),e,{maxRequestBytes:c,parsedBody:a})})};export{B as createAuthedMcpFetchHandler,A as mcpTokenScopes};
@@ -1 +1 @@
1
- import{LunoraClient as M}from"@lunora/client";import{Server as P}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as B,CallToolRequestSchema as H}from"@modelcontextprotocol/sdk/types.js";import{p as W}from"./package-7WeW8c_h.mjs";import{LunoraError as A}from"@lunora/errors";import{f as q,w as F,e as g,a as C,b as R,o as N,j as K}from"./tool-result-CPDsNNuJ.mjs";import{e as U,r as Y,f as G,g as Q}from"./tools-Bylr9LPQ.mjs";const l=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),L=/^-?\d+$/,$=1024,J=(t,e,r)=>{const{contentEncoding:n,format:o}=t;if(o==="int64"){if(!L.test(e)||e.length>$)throw new A("BAD_REQUEST",`"${r}" must be a decimal integer string of at most ${String($)} digits`);return BigInt(e)}if(n==="base64")try{return q(e).buffer}catch{throw new A("BAD_REQUEST",`"${r}" must be base64`)}return e},V=(t,e)=>{const{type:r}=t;return typeof r!="string"?!0:r==="integer"||r==="number"?typeof e=="number":r==="array"?Array.isArray(e):r==="object"?l(e):r===typeof e},X=/^(?:[\dA-Z+/]{4})*(?:[\dA-Z+/]{2}==|[\dA-Z+/]{3}=)?$/i,Z=(t,e)=>t.format==="int64"&&!L.test(e)?!1:t.contentEncoding!=="base64"||X.test(e),x=(t,e)=>Object.entries(t).every(([r,n])=>!l(n)||!Object.hasOwn(n,"const")||!Object.hasOwn(e,r)?!0:e[r]===n.const),z=(t,e)=>!V(t,e)||Object.hasOwn(t,"const")&&t.const!==e||l(e)&&l(t.properties)&&!x(t.properties,e)?!1:typeof e!="string"||Z(t,e),tt=(t,e)=>{const r=t.filter(n=>l(n)&&z(n,e));return r.length===1?r[0]:void 0},et=(t,e)=>{const{additionalProperties:r,properties:n}=t,o=l(n)&&Object.hasOwn(n,e)?n[e]:r;return l(o)?o:void 0},S=(t,e,r)=>{const{anyOf:n,items:o}=t;if(e===null)return e;if(Array.isArray(n)){const a=tt(n,e);return a===void 0?e:S(a,e,r)}return typeof e=="string"?J(t,e,r):Array.isArray(e)&&l(o)?e.map((a,c)=>S(o,a,`${r}[${c.toString()}]`)):l(e)?Object.fromEntries(Object.entries(e).map(([a,c])=>{const s=et(t,a);return[a,s===void 0?c:S(s,c,`${r}.${a}`)]})):e},O=(t,e)=>S(t,e,"args"),T=t=>t==="action"||t==="mutation",rt=t=>t==="query"||t==="mutation"||t==="action"||t==="stream",k=64,nt=/[^\w-]/g,ot={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},st={destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},it={description:"Shard key. Only for a function partitioned with .shardBy(); omit it otherwise.",type:"string"},ct="The first call only proposes the write. Confirm it with confirmed: true and the actionDigest the proposal returns.",at={action:t=>`Runs the action "${t}", which may call external services.`,mutation:t=>`Runs the mutation "${t}", which changes data.`,query:t=>`Runs the query "${t}". Read-only.`,stream:t=>`Runs the stream "${t}", which yields chunks. The result is every chunk, in order. Read-only.`},dt=(t,e)=>{const r=t.description??at[t.kind](t.path);return e?`${r} ${ct}`:r},b=()=>new A("BAD_REQUEST","openRpcSpec must be the OpenRPC document codegen emits (the `openRpcSpec` export of `_generated/openrpc`)"),lt=t=>t.replaceAll(nt,"_"),_=t=>Array.isArray(t)?t.some(e=>_(e)):l(t)&&(t.writeOnly===!0||Object.values(t).some(e=>_(e))),ut=t=>{const{properties:e}=t;return l(e)?Object.entries(e).filter(([,r])=>_(r)).map(([r])=>r):[]},ft=t=>{const e=l(t)&&l(t.schema)?t.schema:void 0,r=e!==void 0&&Object.hasOwn(e,"description")&&Object.keys(e).every(n=>n==="description");return e===void 0||r?{mode:"none"}:e.type==="object"?{mode:"object",schema:{...e,type:"object"}}:{mode:"wrapped",schema:{properties:{result:e},type:"object"}}},mt=t=>{const{params:e}=t,r=Array.isArray(e)?e.find(o=>l(o)&&o.name==="args"):void 0,n=l(r)?r.schema:void 0;return l(n)?n:{properties:{},type:"object"}},ht=t=>{if(!l(t))throw b();const{name:e}=t;if(typeof e!="string")throw b();const r=t["x-lunora-function-kind"];if(!rt(r))return;const n=t["x-lunora-description"];return{argsSchema:mt(t),...typeof n=="string"?{description:n}:{},kind:r,output:r==="stream"?{mode:"none"}:ft(t.result),path:e}},pt=(t,e)=>{const r=lt(t);if(r.length>k)throw new A("BAD_REQUEST",`the MCP tool name for "${t}" is ${r.length.toString()} characters; the limit is ${k.toString()}. Rename the function.`);const n=e.get(r);if(n!==void 0)throw new A("BAD_REQUEST",`"${t}" and "${n}" both map to the MCP tool name "${r}". Rename one of them.`);return e.set(r,t),r},gt=t=>{const{required:e}=t.argsSchema;return Array.isArray(e)&&e.length>0},yt=(t,e)=>({properties:{args:t.argsSchema,shardKey:it,...e?U:{}},required:gt(t)?["args"]:[],type:"object"}),At={additionalProperties:!1,properties:{},type:"object"},St=t=>{if(t.mode==="none")return;const e=F(t.schema);return t.mode==="object"?{...e,anyOf:[...e.anyOf??[],At]}:e},Ot=(t,e)=>{const r=T(e.kind),n=`${e.kind} ${e.path}`,o=r?void 0:St(e.output);return{annotations:r?{...st,title:n}:{...ot,title:n},description:dt(e,r),inputSchema:yt(e,r),name:t,...o===void 0?{}:{outputSchema:o}}},wt=t=>({argsSchema:t.argsSchema,kind:t.kind,outputMode:t.output.mode,path:t.path,sensitiveArgs:ut(t.argsSchema)}),Et=(t,e)=>{const r=l(t)?t.methods:void 0;if(!Array.isArray(r))throw b();const n=[],o=new Map,a=new Map;for(const c of r){const s=ht(c);if(s===void 0)continue;const i=pt(s.path,a);o.set(i,wt(s)),(!T(s.kind)||e.allowWrites)&&n.push(Ot(i,s))}return{definitions:n,routes:o}},Rt="lunora",j=t=>({__lunoraRef:t}),bt=t=>typeof t.shardKey=="string"&&t.shardKey.length>0?t.shardKey:void 0,D=(t,e)=>t.outputMode==="object"?e===void 0?{...R(e),structuredContent:{}}:N(e):t.outputMode==="wrapped"?N({result:e}):R(e),_t=async(t,e,r,n,o,a,c)=>{const s=e.kind==="action"?"action":"mutation";O(e.argsSchema,o);const i=G(n),f=await Q(t,{args:o,functionPath:e.path,idempotencyKey:i.idempotencyKey,kind:s,shardKey:a,tool:r},i,e.sensitiveArgs,["args","shardKey","idempotencyKey"]);if(f!==void 0)return f;const d=O(e.argsSchema,o),u=e.sensitiveArgs.length===0?j(e.path):{__lunoraRef:e.path,sensitive:!0},m=s==="action"?await t.action(u,d,{shardKey:a,signal:c}):await t.mutation(u,d,{onlineOnly:!0,shardKey:a,signal:c});return D(e,m)},E=1e4,v=16*1024*1024,Tt=async(t,e,r,n,o)=>{const a={__lunoraRef:e.path},c=t.stream(a,r,{maxBuffer:E+1,shardKey:n}),{signal:s,progress:i}=o,f=()=>{c.cancel()};s?.addEventListener("abort",f,{once:!0}),s?.aborted===!0&&f();const d=[];let u=0,m=Promise.resolve(),p;const w=(h,y)=>{m=m.then(()=>p===void 0?i?.(h,y):void 0).catch(I=>{p={error:I},c.cancel()})};try{for await(const h of c){if(d.length===E)return c.cancel(),g("PAYLOAD_TOO_LARGE",`the stream "${e.path}" yielded more than ${E.toString()} chunks, so it was cancelled and no chunks are returned.`);const y=h===void 0?"null":JSON.stringify(h,K);if(u+=y.length,u>v)return c.cancel(),g("PAYLOAD_TOO_LARGE",`the stream "${e.path}" yielded more than ${v.toString()} characters of JSON, so it was cancelled and no chunks are returned.`);d.push(h),i!==void 0&&w(d.length-1,y)}}finally{s?.removeEventListener("abort",f)}if(await m,p!==void 0)throw p.error;return s?.aborted===!0?g("CANCELLED",`the stream "${e.path}" was cancelled before it completed, after ${d.length.toString()} chunk(s).`):R(d)},Nt=async(t,e,r,n,o,a={})=>{const c=e.get(r);if(c===void 0)return g("NOT_FOUND",`unknown tool: ${r}`);if(T(c.kind)&&!o)return g("FORBIDDEN",`tool "${r}" is disabled: this MCP server is read-only. Enable writes with allowWrites.`);try{const s=Y(n.args),i=bt(n);return c.kind==="query"?D(c,await t.query(j(c.path),O(c.argsSchema,s),{shardKey:i,signal:a.signal})):c.kind==="stream"?await Tt(t,c,O(c.argsSchema,s),i,a):await _t(t,c,r,n,s,i,a.signal)}catch(s){return a.signal?.aborted===!0?g("CANCELLED",`the call to "${r}" was cancelled before it completed. A write already sent is not undone.`):C(s)}},$t=t=>{let e;const r=new Set,n=i=>{i.calls===0&&r.delete(i)&&i.client.close()},o=i=>{r.add(i),n(i)},a=()=>{e!==void 0&&(o(e),e=void 0)};return{acquire:()=>{const i=typeof t.url=="function"?t.url():t.url;if(i===void 0||i.length===0){a();return}if(e?.url!==i){a();const u=new M({fetch:t.fetch,url:i,WebSocket:t.WebSocket});t.token!==void 0&&(u.setAuthToken(t.token),u.setWsToken(t.token)),e={calls:0,client:u,url:i}}const f=e;f.calls+=1;let d=!0;return{client:f.client,done:()=>{d&&(d=!1,f.calls-=1,n(f))}}},release:()=>{a();for(const i of r)r.delete(i),i.client.close()}}},Mt=t=>{const e=t.allowWrites??!1,r=()=>typeof t.openRpcSpec=="function"?t.openRpcSpec():t.openRpcSpec,n=d=>({spec:d,tools:Et(d,{allowWrites:e})});let o=n(r());const{acquire:a,release:c}=$t(t),s=new P({name:t.name??Rt,version:t.version??W.version},{capabilities:{tools:{listChanged:!0}}}),i=()=>{let d;try{d=r()}catch(u){return t.onReloadError?.(u),o.tools}if(d!==o.spec)try{o=n(d),s.sendToolListChanged().catch(()=>{})}catch(u){t.onReloadError?.(u),o={spec:d,tools:o.tools}}return o.tools},f=s.close.bind(s);return s.close=async()=>{c(),await f()},s.setRequestHandler(B,()=>({tools:[...i().definitions]})),s.setRequestHandler(H,async(d,u)=>{let m;try{m=a()}catch(h){return C(h)}if(m===void 0)return g("SERVICE_UNAVAILABLE","no Lunora deployment URL is available yet. Start `lunora dev` or set the deployment URL, then call the tool again.");const{progressToken:p}=u._meta??{},w={signal:u.signal,...p===void 0?{}:{progress:async(h,y)=>{await u.sendNotification({method:"notifications/progress",params:{message:y,progress:h,progressToken:p}})}}};try{return await Nt(m.client,i().routes,d.params.name,d.params.arguments??{},e,w)}finally{m.done()}}),s};export{E as MAX_STREAM_CHUNKS,Nt as callFunctionTool,Mt as createFunctionMcpServer};
1
+ import{LunoraClient as M}from"@lunora/client";import{Server as P}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as B,CallToolRequestSchema as H}from"@modelcontextprotocol/sdk/types.js";import{p as W}from"./package-B4stRteb.mjs";import{LunoraError as A}from"@lunora/errors";import{f as q,w as F,e as g,a as C,b as R,o as N,j as K}from"./tool-result-CPDsNNuJ.mjs";import{e as U,r as Y,f as G,g as Q}from"./tools-BMou4kPK.mjs";const l=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),L=/^-?\d+$/,$=1024,J=(t,e,r)=>{const{contentEncoding:n,format:o}=t;if(o==="int64"){if(!L.test(e)||e.length>$)throw new A("BAD_REQUEST",`"${r}" must be a decimal integer string of at most ${String($)} digits`);return BigInt(e)}if(n==="base64")try{return q(e).buffer}catch{throw new A("BAD_REQUEST",`"${r}" must be base64`)}return e},V=(t,e)=>{const{type:r}=t;return typeof r!="string"?!0:r==="integer"||r==="number"?typeof e=="number":r==="array"?Array.isArray(e):r==="object"?l(e):r===typeof e},X=/^(?:[\dA-Z+/]{4})*(?:[\dA-Z+/]{2}==|[\dA-Z+/]{3}=)?$/i,Z=(t,e)=>t.format==="int64"&&!L.test(e)?!1:t.contentEncoding!=="base64"||X.test(e),x=(t,e)=>Object.entries(t).every(([r,n])=>!l(n)||!Object.hasOwn(n,"const")||!Object.hasOwn(e,r)?!0:e[r]===n.const),z=(t,e)=>!V(t,e)||Object.hasOwn(t,"const")&&t.const!==e||l(e)&&l(t.properties)&&!x(t.properties,e)?!1:typeof e!="string"||Z(t,e),tt=(t,e)=>{const r=t.filter(n=>l(n)&&z(n,e));return r.length===1?r[0]:void 0},et=(t,e)=>{const{additionalProperties:r,properties:n}=t,o=l(n)&&Object.hasOwn(n,e)?n[e]:r;return l(o)?o:void 0},S=(t,e,r)=>{const{anyOf:n,items:o}=t;if(e===null)return e;if(Array.isArray(n)){const a=tt(n,e);return a===void 0?e:S(a,e,r)}return typeof e=="string"?J(t,e,r):Array.isArray(e)&&l(o)?e.map((a,c)=>S(o,a,`${r}[${c.toString()}]`)):l(e)?Object.fromEntries(Object.entries(e).map(([a,c])=>{const s=et(t,a);return[a,s===void 0?c:S(s,c,`${r}.${a}`)]})):e},O=(t,e)=>S(t,e,"args"),T=t=>t==="action"||t==="mutation",rt=t=>t==="query"||t==="mutation"||t==="action"||t==="stream",k=64,nt=/[^\w-]/g,ot={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},st={destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1},it={description:"Shard key. Only for a function partitioned with .shardBy(); omit it otherwise.",type:"string"},ct="The first call only proposes the write. Confirm it with confirmed: true and the actionDigest the proposal returns.",at={action:t=>`Runs the action "${t}", which may call external services.`,mutation:t=>`Runs the mutation "${t}", which changes data.`,query:t=>`Runs the query "${t}". Read-only.`,stream:t=>`Runs the stream "${t}", which yields chunks. The result is every chunk, in order. Read-only.`},dt=(t,e)=>{const r=t.description??at[t.kind](t.path);return e?`${r} ${ct}`:r},b=()=>new A("BAD_REQUEST","openRpcSpec must be the OpenRPC document codegen emits (the `openRpcSpec` export of `_generated/openrpc`)"),lt=t=>t.replaceAll(nt,"_"),_=t=>Array.isArray(t)?t.some(e=>_(e)):l(t)&&(t.writeOnly===!0||Object.values(t).some(e=>_(e))),ut=t=>{const{properties:e}=t;return l(e)?Object.entries(e).filter(([,r])=>_(r)).map(([r])=>r):[]},ft=t=>{const e=l(t)&&l(t.schema)?t.schema:void 0,r=e!==void 0&&Object.hasOwn(e,"description")&&Object.keys(e).every(n=>n==="description");return e===void 0||r?{mode:"none"}:e.type==="object"?{mode:"object",schema:{...e,type:"object"}}:{mode:"wrapped",schema:{properties:{result:e},type:"object"}}},mt=t=>{const{params:e}=t,r=Array.isArray(e)?e.find(o=>l(o)&&o.name==="args"):void 0,n=l(r)?r.schema:void 0;return l(n)?n:{properties:{},type:"object"}},ht=t=>{if(!l(t))throw b();const{name:e}=t;if(typeof e!="string")throw b();const r=t["x-lunora-function-kind"];if(!rt(r))return;const n=t["x-lunora-description"];return{argsSchema:mt(t),...typeof n=="string"?{description:n}:{},kind:r,output:r==="stream"?{mode:"none"}:ft(t.result),path:e}},pt=(t,e)=>{const r=lt(t);if(r.length>k)throw new A("BAD_REQUEST",`the MCP tool name for "${t}" is ${r.length.toString()} characters; the limit is ${k.toString()}. Rename the function.`);const n=e.get(r);if(n!==void 0)throw new A("BAD_REQUEST",`"${t}" and "${n}" both map to the MCP tool name "${r}". Rename one of them.`);return e.set(r,t),r},gt=t=>{const{required:e}=t.argsSchema;return Array.isArray(e)&&e.length>0},yt=(t,e)=>({properties:{args:t.argsSchema,shardKey:it,...e?U:{}},required:gt(t)?["args"]:[],type:"object"}),At={additionalProperties:!1,properties:{},type:"object"},St=t=>{if(t.mode==="none")return;const e=F(t.schema);return t.mode==="object"?{...e,anyOf:[...e.anyOf??[],At]}:e},Ot=(t,e)=>{const r=T(e.kind),n=`${e.kind} ${e.path}`,o=r?void 0:St(e.output);return{annotations:r?{...st,title:n}:{...ot,title:n},description:dt(e,r),inputSchema:yt(e,r),name:t,...o===void 0?{}:{outputSchema:o}}},wt=t=>({argsSchema:t.argsSchema,kind:t.kind,outputMode:t.output.mode,path:t.path,sensitiveArgs:ut(t.argsSchema)}),Et=(t,e)=>{const r=l(t)?t.methods:void 0;if(!Array.isArray(r))throw b();const n=[],o=new Map,a=new Map;for(const c of r){const s=ht(c);if(s===void 0)continue;const i=pt(s.path,a);o.set(i,wt(s)),(!T(s.kind)||e.allowWrites)&&n.push(Ot(i,s))}return{definitions:n,routes:o}},Rt="lunora",j=t=>({__lunoraRef:t}),bt=t=>typeof t.shardKey=="string"&&t.shardKey.length>0?t.shardKey:void 0,D=(t,e)=>t.outputMode==="object"?e===void 0?{...R(e),structuredContent:{}}:N(e):t.outputMode==="wrapped"?N({result:e}):R(e),_t=async(t,e,r,n,o,a,c)=>{const s=e.kind==="action"?"action":"mutation";O(e.argsSchema,o);const i=G(n),f=await Q(t,{args:o,functionPath:e.path,idempotencyKey:i.idempotencyKey,kind:s,shardKey:a,tool:r},i,e.sensitiveArgs,["args","shardKey","idempotencyKey"]);if(f!==void 0)return f;const d=O(e.argsSchema,o),u=e.sensitiveArgs.length===0?j(e.path):{__lunoraRef:e.path,sensitive:!0},m=s==="action"?await t.action(u,d,{shardKey:a,signal:c}):await t.mutation(u,d,{onlineOnly:!0,shardKey:a,signal:c});return D(e,m)},E=1e4,v=16*1024*1024,Tt=async(t,e,r,n,o)=>{const a={__lunoraRef:e.path},c=t.stream(a,r,{maxBuffer:E+1,shardKey:n}),{signal:s,progress:i}=o,f=()=>{c.cancel()};s?.addEventListener("abort",f,{once:!0}),s?.aborted===!0&&f();const d=[];let u=0,m=Promise.resolve(),p;const w=(h,y)=>{m=m.then(()=>p===void 0?i?.(h,y):void 0).catch(I=>{p={error:I},c.cancel()})};try{for await(const h of c){if(d.length===E)return c.cancel(),g("PAYLOAD_TOO_LARGE",`the stream "${e.path}" yielded more than ${E.toString()} chunks, so it was cancelled and no chunks are returned.`);const y=h===void 0?"null":JSON.stringify(h,K);if(u+=y.length,u>v)return c.cancel(),g("PAYLOAD_TOO_LARGE",`the stream "${e.path}" yielded more than ${v.toString()} characters of JSON, so it was cancelled and no chunks are returned.`);d.push(h),i!==void 0&&w(d.length-1,y)}}finally{s?.removeEventListener("abort",f)}if(await m,p!==void 0)throw p.error;return s?.aborted===!0?g("CANCELLED",`the stream "${e.path}" was cancelled before it completed, after ${d.length.toString()} chunk(s).`):R(d)},Nt=async(t,e,r,n,o,a={})=>{const c=e.get(r);if(c===void 0)return g("NOT_FOUND",`unknown tool: ${r}`);if(T(c.kind)&&!o)return g("FORBIDDEN",`tool "${r}" is disabled: this MCP server is read-only. Enable writes with allowWrites.`);try{const s=Y(n.args),i=bt(n);return c.kind==="query"?D(c,await t.query(j(c.path),O(c.argsSchema,s),{shardKey:i,signal:a.signal})):c.kind==="stream"?await Tt(t,c,O(c.argsSchema,s),i,a):await _t(t,c,r,n,s,i,a.signal)}catch(s){return a.signal?.aborted===!0?g("CANCELLED",`the call to "${r}" was cancelled before it completed. A write already sent is not undone.`):C(s)}},$t=t=>{let e;const r=new Set,n=i=>{i.calls===0&&r.delete(i)&&i.client.close()},o=i=>{r.add(i),n(i)},a=()=>{e!==void 0&&(o(e),e=void 0)};return{acquire:()=>{const i=typeof t.url=="function"?t.url():t.url;if(i===void 0||i.length===0){a();return}if(e?.url!==i){a();const u=new M({fetch:t.fetch,url:i,WebSocket:t.WebSocket});t.token!==void 0&&(u.setAuthToken(t.token),u.setWsToken(t.token)),e={calls:0,client:u,url:i}}const f=e;f.calls+=1;let d=!0;return{client:f.client,done:()=>{d&&(d=!1,f.calls-=1,n(f))}}},release:()=>{a();for(const i of r)r.delete(i),i.client.close()}}},Mt=t=>{const e=t.allowWrites??!1,r=()=>typeof t.openRpcSpec=="function"?t.openRpcSpec():t.openRpcSpec,n=d=>({spec:d,tools:Et(d,{allowWrites:e})});let o=n(r());const{acquire:a,release:c}=$t(t),s=new P({name:t.name??Rt,version:t.version??W.version},{capabilities:{tools:{listChanged:!0}}}),i=()=>{let d;try{d=r()}catch(u){return t.onReloadError?.(u),o.tools}if(d!==o.spec)try{o=n(d),s.sendToolListChanged().catch(()=>{})}catch(u){t.onReloadError?.(u),o={spec:d,tools:o.tools}}return o.tools},f=s.close.bind(s);return s.close=async()=>{c(),await f()},s.setRequestHandler(B,()=>({tools:[...i().definitions]})),s.setRequestHandler(H,async(d,u)=>{let m;try{m=a()}catch(h){return C(h)}if(m===void 0)return g("SERVICE_UNAVAILABLE","no Lunora deployment URL is available yet. Start `lunora dev` or set the deployment URL, then call the tool again.");const{progressToken:p}=u._meta??{},w={signal:u.signal,...p===void 0?{}:{progress:async(h,y)=>{await u.sendNotification({method:"notifications/progress",params:{message:y,progress:h,progressToken:p}})}}};try{return await Nt(m.client,i().routes,d.params.name,d.params.arguments??{},e,w)}finally{m.done()}}),s};export{E as MAX_STREAM_CHUNKS,Nt as callFunctionTool,Mt as createFunctionMcpServer};
@@ -0,0 +1 @@
1
+ import{LunoraAdminClient as w}from"@lunora/client/admin";import{LunoraError as l}from"@lunora/errors";import{Server as d}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as g,CallToolRequestSchema as A}from"@modelcontextprotocol/sdk/types.js";import{p as h}from"./package-B4stRteb.mjs";import{agentToolDefinitions as M,isAgentToolName as T,callAgentTool as L}from"./AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{t as N,c as R}from"./tools-BMou4kPK.mjs";const k="lunora",E=e=>{if(e.client!==void 0){if(typeof e.client.listFunctions!="function")throw new l("INTERNAL","createLunoraMcpServer needs a LunoraAdminClient (`@lunora/client/admin`), not a plain LunoraClient.");return e.client}if(e.url===void 0)throw new l("INTERNAL","createLunoraMcpServer requires either a `client` or a `url`");if(e.token===void 0||e.token.length===0)throw new l("UNAUTHENTICATED","createLunoraMcpServer requires a `token` (LUNORA_ADMIN_TOKEN) alongside `url`: every tool reaches admin-gated /_lunora/admin/* routes, so an unauthenticated server can only 403. Writes stay off unless `allowWrites` is set.");const t=new w({fetch:e.fetch,url:e.url});return t.setAuthToken(e.token),t},x=e=>{const t=E(e),o=e.allowWrites??!1,s=e.allowAgents??!1,r=e.agents??[],i=typeof e.token=="string"&&e.token.length>0,c=e.allowObservability===!0&&i,u=e.allowDataReads===!0&&i,a=new d({name:k,version:e.version??h.version},{capabilities:{tools:{}}});return a.setRequestHandler(g,()=>({tools:[...N(o,c,u),...M(r,s)]})),a.setRequestHandler(A,async f=>{const{arguments:v,name:n}=f.params,m=v??{};return T(n,r)?await L(t,n,m,{allowAgents:s,exposures:r,...e.agentMaxWaitMs===void 0?{}:{maxWaitMs:e.agentMaxWaitMs},...e.agentPollIntervalMs===void 0?{}:{pollIntervalMs:e.agentPollIntervalMs}}):await R(t,n,m,o,c,u)}),a};export{x as createLunoraMcpServer,E as resolveClient};
@@ -1 +1 @@
1
- import{serveStateless as c}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{DEFAULT_MAX_REQUEST_BYTES as u}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{resolveClient as s,createLunoraMcpServer as a}from"./createLunoraMcpServer-BC7nvLcl.mjs";const l=e=>{const r=s(e);return t=>c(a({...e,client:r}),t,{maxRequestBytes:e.maxRequestBytes})};export{u as DEFAULT_MAX_REQUEST_BYTES,l as createMcpFetchHandler,c as serveStateless};
1
+ import{serveStateless as c}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{DEFAULT_MAX_REQUEST_BYTES as u}from"./DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{resolveClient as s,createLunoraMcpServer as a}from"./createLunoraMcpServer-Dv-ke-g5.mjs";const l=e=>{const r=s(e);return t=>c(a({...e,client:r}),t,{maxRequestBytes:e.maxRequestBytes})};export{u as DEFAULT_MAX_REQUEST_BYTES,l as createMcpFetchHandler,c as serveStateless};
@@ -1,5 +1,6 @@
1
- import { LunoraClient } from '@lunora/client';
1
+ import { LunoraAdminClient } from '@lunora/client/admin';
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { LunoraClient } from '@lunora/client';
3
4
  import { b as ToolInputSchema, T as ToolDefinition, d as ToolResult } from "./compose.d-DiPnHeQv.mjs";
4
5
  /**
5
6
  * Agent exposure for the MCP server: a durable `@lunora/agent` run fronted as an
@@ -108,10 +109,10 @@ interface LunoraMcpServerOptions {
108
109
  */
109
110
  allowWrites?: boolean;
110
111
  /**
111
- * Pre-built client (test injection). When omitted a `LunoraClient` is
112
+ * Pre-built client (test injection). When omitted a `LunoraAdminClient` is
112
113
  * created from `url`/`token`/`fetch`.
113
114
  */
114
- client?: LunoraClient;
115
+ client?: LunoraAdminClient;
115
116
  /** `fetch` implementation; defaults to the ambient global. */
116
117
  fetch?: typeof fetch;
117
118
  /**
@@ -1,5 +1,6 @@
1
- import { LunoraClient } from '@lunora/client';
1
+ import { LunoraAdminClient } from '@lunora/client/admin';
2
2
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ import { LunoraClient } from '@lunora/client';
3
4
  import { b as ToolInputSchema, T as ToolDefinition, d as ToolResult } from "./compose.d-DiPnHeQv.js";
4
5
  /**
5
6
  * Agent exposure for the MCP server: a durable `@lunora/agent` run fronted as an
@@ -108,10 +109,10 @@ interface LunoraMcpServerOptions {
108
109
  */
109
110
  allowWrites?: boolean;
110
111
  /**
111
- * Pre-built client (test injection). When omitted a `LunoraClient` is
112
+ * Pre-built client (test injection). When omitted a `LunoraAdminClient` is
112
113
  * created from `url`/`token`/`fetch`.
113
114
  */
114
- client?: LunoraClient;
115
+ client?: LunoraAdminClient;
115
116
  /** `fetch` implementation; defaults to the ambient global. */
116
117
  fetch?: typeof fetch;
117
118
  /**
@@ -0,0 +1 @@
1
+ var a="1.0.0-alpha.267";const o={version:a};export{o as p};
@@ -0,0 +1,2 @@
1
+ import{getCatalogEntry as q,resolveHint as Q,findIssueSolution as Y,isInternalCode as S,LunoraError as s}from"@lunora/errors";import{w as G,e as u,o as J,b as l,t as V,c as X,a as z}from"./tool-result-CPDsNNuJ.mjs";import{OBSERVABILITY_TOOL_NAMES as Z,OBSERVABILITY_TOOL_DEFINITIONS as ee,callObservabilityTool as te}from"./OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";import{ADMIN_FUNCTIONS as ne}from"@lunora/shard-engine";import{stableStringify as oe}from"@lunora/wire";import{m as ie}from"./promise-memo-OqVPWoUX.mjs";const re={destructiveHint:!1,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!0},_="https://lunora.sh/docs/errors",se={properties:{code:{description:'The error code to explain, e.g. "CONFLICT" or "RLS_REQUIRED". Case-sensitive; codes are SCREAMING_SNAKE_CASE.',type:"string"},message:{description:"The raw error message, when there is no code (codegen and Cloudflare platform errors arrive as plain text). Matched against the solution tables.",type:"string"}},type:"object"},ae={properties:{code:{description:"The code that was looked up, when one was given.",type:"string"},docsUrl:{description:"Link to this code's section of the published error reference.",type:"string"},found:{description:"False when neither the code nor the message matched anything — the other fields are then absent.",type:"boolean"},hint:{description:"Actionable Markdown remediation, when the catalog or a message rule has one.",type:"string"},internal:{description:"True when the code is redacted on the wire: its real message is logged server-side and never reaches a client, so it is absent from the published reference.",type:"boolean"},solution:{description:"A message-matched solution: { id, header, body }, from Lunora's rules or the Cloudflare platform table.",type:"object"},status:{description:"HTTP/RPC status this code maps to on the wire.",type:"number"},title:{description:"Short human-readable summary of the code.",type:"string"}},required:["found"],type:"object"},I=[{annotations:{...re,title:"Explain a Lunora error"},description:"Explain a Lunora error before guessing at a fix: pass its code (CONFLICT, RLS_REQUIRED, …) or the raw error message, and get the catalog's transport status, title and actionable hint, plus any matched codegen/Cloudflare solution and a link to the reference. Static catalog data — no deployment and no credentials needed.",inputSchema:se,name:"lunora_explain_error",outputSchema:G(ae)}],ce=new Set(I.map(e=>e.name)),E=e=>typeof e=="string"&&e.length>0?e:void 0,de=e=>typeof e=="string"?e:e.join(`
2
+ `),le=(e,t)=>e===void 0||t===void 0||S(e)?_:`${_}#${e.toLowerCase()}`,ue=(e,t)=>{const n=e===void 0?void 0:q(e),o=e===void 0?void 0:Q({code:e}),i=t===void 0?void 0:Y(t),r={docsUrl:le(e,n),found:n!==void 0||i!==void 0};return e!==void 0&&(r.code=e,S(e)&&(r.internal=!0)),n!==void 0&&(r.status=n.status,r.title=n.title),o!==void 0&&(r.hint=de(o)),i!==void 0&&(r.solution={body:i.body,header:i.header,id:i.id}),r},he=(e,t)=>{if(e!=="lunora_explain_error")return u("NOT_FOUND",`unknown error tool: ${e}`);const n=E(t.code),o=E(t.message);return n===void 0&&o===void 0?u("BAD_REQUEST",'lunora_explain_error needs a "code" or a "message" (or both); received neither.'):J(ue(n,o))},pe={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},fe={properties:{cursor:{description:"Opaque cursor from a previous call's continueCursor, to fetch the next page.",type:"string"},depth:{description:"How many hops to follow. 1 (default) is the direct neighbourhood; maximum 4.",type:"number"},direction:{description:'Which way to follow foreign keys: "out" follows the ids this row holds (ticket → customer), "in" the rows that point at it (customer → tickets), "both" (default) does both.',type:"string"},edges:{description:'Restrict the walk to these edge names, each "<table>.<column>" (e.g. "tickets.customerId"). Omit to follow every declared foreign key.',items:{type:"string"},type:"array"},id:{description:"Document id of the row to start from.",type:"string"},limit:{description:"Maximum related rows to return (default 50, maximum 200).",type:"number"},shardKey:{description:"Shard to read from on a .shardBy()-partitioned deployment. Omit for the default (unsharded) shard.",type:"string"},table:{description:'Table the start row lives in, e.g. "customers".',type:"string"}},required:["table","id"],type:"object"},D=[{annotations:{...pe,title:"Find rows related to a row"},description:"Follow the schema's foreign keys out of one row and return the rows it is connected to, each with its hop distance, the edge names walked to reach it, and a depth-decaying score. Use this to answer 'what is connected to this' — a customer's tickets, those tickets' messages — which keyword and semantic search cannot, because the connection lives in a foreign key rather than in the text. Read-only, but it reads through the deployment's ADMIN writer: RLS policies and column masks do not apply to what it returns.",inputSchema:fe,name:"lunora_find_related"}],me=new Set(D.map(e=>e.name)),ge=e=>{const{cursor:t,depth:n,direction:o,edges:i,limit:r}=e;if(t!=null&&typeof t!="string")throw new s("BAD_REQUEST","findRelated: `cursor` must be a string");if(n!==void 0&&typeof n!="number")throw new s("BAD_REQUEST","findRelated: `depth` must be a number");if(o!==void 0&&o!=="both"&&o!=="in"&&o!=="out")throw new s("BAD_REQUEST",'findRelated: `direction` must be one of "in", "out" or "both"');if(r!==void 0&&typeof r!="number")throw new s("BAD_REQUEST","findRelated: `limit` must be a number");if(i!==void 0&&(!Array.isArray(i)||!i.every(a=>typeof a=="string")))throw new s("BAD_REQUEST","findRelated: `edges` must be an array of edge-name strings")},ye=e=>{const{cursor:t,depth:n,direction:o,edges:i,id:r,limit:a,shardKey:d,table:c}=e;if(typeof c!="string"||c.trim()==="")throw new s("BAD_REQUEST","findRelated: `table` is required");if(typeof r!="string"||r.trim()==="")throw new s("BAD_REQUEST","findRelated: `id` is required");if(ge(e),d!==void 0&&(typeof d!="string"||d.trim()===""))throw new s("BAD_REQUEST","findRelated: `shardKey` must be a non-empty string when given");return{args:{id:r,table:c,...typeof t=="string"?{cursor:t}:{},...n===void 0?{}:{depth:n},...o===void 0?{}:{direction:o},...i===void 0?{}:{edges:i},...a===void 0?{}:{limit:a}},shardKey:d}},we=async(e,t,n)=>{if(t!=="lunora_find_related")throw new s("INTERNAL",`unknown row-read tool: ${t}`);const{args:o,shardKey:i}=ye(n),r={__lunoraRef:ne.findRelated};return l(await e.query(r,o,{...i===void 0?{}:{shardKey:i}}))},_e=new TextEncoder,Ee=64,Ae=new Map,C=async e=>ie(Ae,e,async()=>crypto.subtle.importKey("raw",_e.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]),Ee),L=new TextEncoder,Oe=Array.from({length:32},(e,t)=>t);new RegExp(`[${Oe.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const Te=async(e,t)=>{const n=await C(e),o=await crypto.subtle.sign("HMAC",n,L.encode(t));return V(new Uint8Array(o))},be=async(e,t,n)=>{const o=await C(e);return crypto.subtle.verify("HMAC",o,n,L.encode(t))},Re="lunora-mcp-write-confirmation-v1",k=600*1e3,U=".",H=e=>{const t=e.getAuthToken();if(t===null||t==="")throw new s("UNAUTHORIZED","write confirmation needs a bearer token for this deployment: it is the secret half of the digest key, and without it a digest would be forgeable by anyone.");return`${Re}\0${e.url}\0${t}`},P=(e,t)=>`${oe(e)}\0${String(t)}`,ve=async(e,t)=>{const n=Date.now()+k,o=await Te(H(e),P(t,n));return{actionDigest:`${String(n)}${U}${o}`,expiresAt:n}},Ne=async(e,t,n)=>{const o=n.indexOf(U);if(o<=0)return"mismatch";const i=Number(n.slice(0,o));if(!Number.isSafeInteger(i)||i<=0)return"mismatch";if(Date.now()>=i)return"expired";let r;try{r=X(n.slice(o+1))}catch{return"mismatch"}return await be(H(e),P(t,i),r)?"valid":"mismatch"},Se="Optional caller-chosen token folded into the digest. GUARANTEE: a retry after a client timeout can resubmit the confirmation you already hold, for as long as that digest is inside its window, instead of asking for a second review — and a deliberately-repeated identical write sent under a NEW key gets its own digest, so it cannot ride the first review. NOT GUARANTEED: this does not deduplicate the write. The server keeps no state between requests and never forwards the key to the function, so a resubmitted confirmed call executes again. Make the function itself idempotent if the write must happen at most once.",Ie={actionDigest:{description:"The digest returned by the preceding action_required result. Required together with confirmed, and only valid until the expiresAt that result reported — past that, propose again.",type:"string"},confirmed:{description:"Set to true ONLY on the second call, after a human has reviewed the proposed action, and only together with the actionDigest that proposal returned. Omit it on the first call. The server cannot tell whether a human actually reviewed it — that is this client's responsibility, and the operator enabled writes on the understanding that this client asks.",type:"boolean"},idempotencyKey:{description:Se,type:"string"}},De=e=>{const t=typeof e.actionDigest=="string"&&e.actionDigest.length>0?e.actionDigest:void 0,n=typeof e.idempotencyKey=="string"&&e.idempotencyKey.length>0?e.idempotencyKey:void 0;return{actionDigest:t,confirmed:e.confirmed===!0,idempotencyKey:n}},M="«sensitive»",Ce=(e,t)=>{if(t.length===0)return e;const n=Object.fromEntries(Object.entries(e.args).map(([o,i])=>[o,t.includes(o)?M:i]));return{...e,args:n}},Le=["functionPath","args","shardKey","idempotencyKey"],ke=e=>e.length>1?`${e.slice(0,-1).join(", ")} and ${e.at(-1)??""}`:e.join(""),Ue=(e,t,n,o)=>l({actionDigest:t.actionDigest,expiresAt:new Date(t.expiresAt).toISOString(),nextStep:`Show proposedAction to a human. To execute, call ${e.tool} again with the IDENTICAL ${ke(o)}, plus confirmed: true and this actionDigest, before expiresAt. Resend the REAL values of any argument shown as "${M}": that placeholder is display only and will not verify. Nothing has been written or called yet.`,proposedAction:Ce(e,n),status:"action_required"}),He=async(e,t,n,o=[],i=Le)=>{if(!n.confirmed||n.actionDigest===void 0)return Ue(t,await ve(e,t),o,i);const r=await Ne(e,t,n.actionDigest);if(r!=="valid")return r==="expired"?u("CONFIRMATION_EXPIRED",`confirmation rejected: this actionDigest has expired. A confirmation is good for ${String(k/6e4)} minutes from the proposal that issued it, so an approval cannot be replayed in a later session. Nothing was written. Call ${t.tool} again WITHOUT confirmed to get a fresh actionDigest, have it reviewed, then resubmit those same arguments with it.`):u("CONFIRMATION_MISMATCH",`confirmation rejected: the actionDigest does not match this call. A digest is bound to the exact tool, function path, arguments, shard key and idempotency key it was issued for, so any edit to the proposal invalidates it — and a digest from another deployment never matches. Nothing was written. Call ${t.tool} again WITHOUT confirmed to get a fresh actionDigest for the current arguments, have it reviewed, then resubmit those same arguments with it.`)},x={properties:{args:{description:"Arguments object passed to the function",type:"object"},functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"},shardKey:{description:"Optional shard key when the function is .shardBy()-partitioned",type:"string"}},required:["functionPath"],type:"object"},A={properties:{},type:"object"},Pe={properties:{functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"}},required:["functionPath"],type:"object"},p={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},$=[{annotations:{...p,title:"List deployment functions"},description:"List the deployment's public functions (queries, mutations, actions) with their kinds.",inputSchema:A,name:"lunora_list_functions"},{annotations:{...p,title:"List global tables"},description:"List the deployment's .global() tables with their row counts. Names and row counts only — no column shapes.",inputSchema:A,name:"lunora_list_tables"},{annotations:{...p,title:"Describe a function's arguments"},description:"Return a function's argument descriptors (name, validator kind, whether it is optional) and its kind, so a caller can construct a valid arguments object. Call lunora_list_functions first to discover available function paths.",inputSchema:Pe,name:"lunora_get_function_schema"},{annotations:{...p,title:"Run a query"},description:"Run a query and return its result. Read-only.",inputSchema:x,name:"lunora_run_query"}],Me=new Set($.map(e=>e.name)),O={properties:{...x.properties,...Ie},required:["functionPath"],type:"object"},T='TWO-STEP: the first call does NOT execute. It returns status "action_required" with the proposed action, an actionDigest and the expiresAt it is good until; show that to a human, then call again before expiresAt with the IDENTICAL functionPath/args/shardKey plus confirmed: true and that actionDigest. Any change to the target or the arguments produces a different digest and needs a fresh review, and an expired digest is refused rather than re-proposed.',F=[{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run a mutation (writes data)"},description:`Run a mutation. Writes data. ${T}`,inputSchema:O,name:"lunora_run_mutation"},{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run an action (may call external services)"},description:`Run an action. May call external services — send mail, charge a card, hit a third-party API — so the confirmation is the only thing between a proposal and a real-world side effect. ${T}`,inputSchema:O,name:"lunora_run_action"}],xe=new Set(F.map(e=>e.name)),B=e=>{const{functionPath:t}=e;if(typeof t!="string"||t.length===0)throw new s("BAD_REQUEST",'"functionPath" is required and must be a non-empty string');return t},b=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),R=e=>Array.isArray(e)?"an array":`a ${typeof e}`,$e=e=>{if(e==null)return{};if(typeof e=="string"){let t;try{t=JSON.parse(e)}catch{throw new s("BAD_REQUEST",'"args" must be a JSON object; received a string that is not valid JSON')}if(!b(t))throw new s("BAD_REQUEST",`"args" must be a JSON object; the provided string decoded to ${R(t)}`);return t}if(!b(e))throw new s("BAD_REQUEST",`"args" must be a JSON object, got ${R(e)}`);return e},K=e=>{const t=B(e),n=$e(e.args),o=typeof e.shardKey=="string"&&e.shardKey.length>0?e.shardKey:void 0;return{args:n,functionPath:t,shardKey:o}},W=e=>({__lunoraRef:e}),Fe=3e4,h=new WeakMap,m=e=>{const t=Date.now(),n=h.get(e);if(n!==void 0&&n.expiresAt>t)return n.promise;const o=e.listFunctions().catch(i=>{throw h.get(e)?.promise===o&&h.delete(e),i});return h.set(e,{expiresAt:t+Fe,promise:o}),o},j=async(e,t,n)=>{const i=(await m(e)).find(r=>r.path===t);if(i===void 0)throw new s("NOT_FOUND",`function not found or not public: ${t}`);if(i.kind!==n)throw new s("BAD_REQUEST",`function ${t} is a ${i.kind}, not a ${n}`);return i},Be=async(e,t,n,o,i,r)=>{const a=De(i);return He(e,{...o,idempotencyKey:a.idempotencyKey,kind:n,tool:t},a,r)},Ke=e=>(e.args??[]).filter(t=>t.sensitive===!0).map(t=>t.name),We=async(e,t,n)=>{switch(t){case"lunora_get_function_schema":{const o=B(n),r=(await m(e)).find(a=>a.path===o);return r===void 0?u("NOT_FOUND",`function not found: ${o}`):l({args:r.args??[],kind:r.kind,path:r.path})}case"lunora_list_functions":return l(await m(e));case"lunora_list_tables":return l(await e.listGlobalTables());case"lunora_run_query":{const{args:o,functionPath:i,shardKey:r}=K(n);return await j(e,i,"query"),l(await e.query(W(i),o,{shardKey:r}))}default:throw new s("INTERNAL",`unknown read-only tool: ${t}`)}},je=async(e,t,n)=>{if(t!=="lunora_run_action"&&t!=="lunora_run_mutation")throw new s("INTERNAL",`unknown write tool: ${t}`);const o=t==="lunora_run_action"?"action":"mutation",{args:i,functionPath:r,shardKey:a}=K(n);h.delete(e);const d=await j(e,r,o),c=Ke(d),y=await Be(e,t,o,{args:i,functionPath:r,shardKey:a},n,c);if(y!==void 0)return y;const w=c.length===0?W(r):{__lunoraRef:r,sensitive:!0};return l(o==="action"?await e.action(w,i,{shardKey:a}):await e.mutation(w,i,{onlineOnly:!0,shardKey:a}))},v="lunora:data-read",N="lunora:observability",qe=e=>e===!0,f=[{call:We,definitions:$,names:Me},{call:(e,t,n)=>he(t,n),definitions:I,names:ce},{call:we,definitions:D,gate:{flag:"allowDataReads",refuse:e=>`tool "${e}" is disabled: it returns raw table rows read through the deployment's ADMIN writer, so RLS policies and column masks do not apply. Enable it with the LUNORA_MCP_ALLOW_DATA_READS env var or the allowDataReads option; on the authed path the token also needs the ${v} scope.`,scope:v},names:me},{call:te,definitions:ee,gate:{flag:"allowObservability",refuse:e=>`tool "${e}" is disabled: it reads the deployment's logs, request metadata and grouped errors — user data that would land at the model provider. Enable it with the LUNORA_MCP_ALLOW_OBSERVABILITY env var or the allowObservability option; on the authed path the token also needs the ${N} scope.`,scope:N},names:Z},{call:je,definitions:F,gate:{flag:"allowWrites",refuse:e=>`tool "${e}" is disabled: this MCP server is read-only. Enable writes with the LUNORA_MCP_ALLOW_WRITES env var.`},names:xe}],g=(e,t)=>e.gate!==void 0&&!qe(t[e.gate.flag])?e.gate:void 0,ze=(e,t=!1,n=!1)=>{const o={allowDataReads:n,allowObservability:t,allowWrites:e};return f.filter(i=>g(i,o)===void 0).flatMap(i=>i.definitions)},Ze=async(e,t,n,o=!1,i=!1,r=!1)=>{const a=f.find(c=>c.names.has(t));if(a===void 0)return u("NOT_FOUND",`unknown tool: ${t}`);const d=g(a,{allowDataReads:r,allowObservability:i,allowWrites:o});if(d!==void 0)return u("FORBIDDEN",d.refuse(t));try{return await a.call(e,t,n)}catch(c){return z(c)}},et=(e,t)=>{const n=f.find(o=>o.names.has(e));if(!(n?.gate?.scope===void 0||g(n,t)!==void 0))return n.gate.scope},tt=f.flatMap(e=>e.gate?.scope===void 0?[]:[{flag:e.gate.flag,scope:e.gate.scope}]);export{v as D,I as E,N as O,$ as R,tt as S,F as W,he as a,ce as b,Ze as c,xe as d,Ie as e,De as f,He as g,D as h,$e as r,et as s,ze as t};
@@ -1,15 +1,16 @@
1
- import { L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-D_0-WiS2.mjs";
1
+ import { L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-BoX-fd2B.mjs";
2
2
  export { A as AGENT_RUN_INPUT_SCHEMA, a as AGENT_STATUS_TOOL_NAME,
3
3
  /** Worker-safe entry: fetch handlers and tool composition, with no stdio transport or `node:*` imports. */
4
4
  type C as CallAgentToolOptions, type F as FunctionMcpServerOptions,
5
5
  /** Worker-safe entry: fetch handlers and tool composition, with no stdio transport or `node:*` imports. */
6
- type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, p as parseAgentsEnv } from "../packem_shared/function-server.d-D_0-WiS2.mjs";
6
+ type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, p as parseAgentsEnv } from "../packem_shared/function-server.d-BoX-fd2B.mjs";
7
7
  import { M as McpFetchHandler } from "../packem_shared/serve-stateless.d-DD5arqFx.mjs";
8
8
  export { D as DEFAULT_MAX_REQUEST_BYTES, type S as ServeStatelessOptions, s as serveStateless } from "../packem_shared/serve-stateless.d-DD5arqFx.mjs";
9
9
  import { T as ToolDefinition, d as ToolResult, h as ToolAnnotations, b as ToolInputSchema } from "../packem_shared/compose.d-DiPnHeQv.mjs";
10
10
  export { type M as McpServerInfo, type a as McpTool, e as createToolServer } from "../packem_shared/compose.d-DiPnHeQv.mjs";
11
- import { LunoraClient } from '@lunora/client';
11
+ import { LunoraAdminClient } from '@lunora/client/admin';
12
12
  import '@modelcontextprotocol/sdk/server/index.js';
13
+ import '@lunora/client';
13
14
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
14
15
  /**
15
16
  * The observability tools. Descriptions say WHEN to call the tool, not just
@@ -38,7 +39,7 @@ declare const toolDefinitions: (allowWrites: boolean, allowObservability?: boole
38
39
  * a gated tool is refused even if the client somehow names one it was never
39
40
  * shown.
40
41
  */
41
- declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, allowObservability?: boolean, allowDataReads?: boolean) => Promise<ToolResult>;
42
+ declare const callTool: (client: LunoraAdminClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, allowObservability?: boolean, allowDataReads?: boolean) => Promise<ToolResult>;
42
43
  /**
43
44
  * The verified access-token payload better-auth hands a protected handler.
44
45
  *
@@ -1,15 +1,16 @@
1
- import { L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-ByIkBRXs.js";
1
+ import { L as LunoraMcpServerOptions } from "../packem_shared/function-server.d-CnHt2Sb1.js";
2
2
  export { A as AGENT_RUN_INPUT_SCHEMA, a as AGENT_STATUS_TOOL_NAME,
3
3
  /** Worker-safe entry: fetch handlers and tool composition, with no stdio transport or `node:*` imports. */
4
4
  type C as CallAgentToolOptions, type F as FunctionMcpServerOptions,
5
5
  /** Worker-safe entry: fetch handlers and tool composition, with no stdio transport or `node:*` imports. */
6
- type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, p as parseAgentsEnv } from "../packem_shared/function-server.d-ByIkBRXs.js";
6
+ type M as McpAgentExposure, b as agentToolDefinitions, c as callAgentTool, d as createFunctionMcpServer, p as parseAgentsEnv } from "../packem_shared/function-server.d-CnHt2Sb1.js";
7
7
  import { M as McpFetchHandler } from "../packem_shared/serve-stateless.d-DD5arqFx.js";
8
8
  export { D as DEFAULT_MAX_REQUEST_BYTES, type S as ServeStatelessOptions, s as serveStateless } from "../packem_shared/serve-stateless.d-DD5arqFx.js";
9
9
  import { T as ToolDefinition, d as ToolResult, h as ToolAnnotations, b as ToolInputSchema } from "../packem_shared/compose.d-DiPnHeQv.js";
10
10
  export { type M as McpServerInfo, type a as McpTool, e as createToolServer } from "../packem_shared/compose.d-DiPnHeQv.js";
11
- import { LunoraClient } from '@lunora/client';
11
+ import { LunoraAdminClient } from '@lunora/client/admin';
12
12
  import '@modelcontextprotocol/sdk/server/index.js';
13
+ import '@lunora/client';
13
14
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
14
15
  /**
15
16
  * The observability tools. Descriptions say WHEN to call the tool, not just
@@ -38,7 +39,7 @@ declare const toolDefinitions: (allowWrites: boolean, allowObservability?: boole
38
39
  * a gated tool is refused even if the client somehow names one it was never
39
40
  * shown.
40
41
  */
41
- declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, allowObservability?: boolean, allowDataReads?: boolean) => Promise<ToolResult>;
42
+ declare const callTool: (client: LunoraAdminClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, allowObservability?: boolean, allowDataReads?: boolean) => Promise<ToolResult>;
42
43
  /**
43
44
  * The verified access-token payload better-auth hands a protected handler.
44
45
  *
@@ -1 +1 @@
1
- import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as T,callAgentTool as a,parseAgentsEnv as c}from"../packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{createAuthedMcpFetchHandler as _,mcpTokenScopes as E}from"../packem_shared/createAuthedMcpFetchHandler-mn8Eh3Xo.mjs";import{createToolServer as n}from"../packem_shared/createToolServer-CHAjfuNx.mjs";import{createFunctionMcpServer as O}from"../packem_shared/createFunctionMcpServer-DI_L4fPb.mjs";import{createMcpFetchHandler as s}from"../packem_shared/createMcpFetchHandler-D_kQUgVT.mjs";import{createPaidMcpServer as N}from"../packem_shared/createPaidMcpServer-CdDLw3G4.mjs";import{R as m,W as x,c as i,t as D}from"../packem_shared/tools-Bylr9LPQ.mjs";import{DEFAULT_MAX_REQUEST_BYTES as L,serveStateless as M}from"../packem_shared/DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as v}from"../packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,L as DEFAULT_MAX_REQUEST_BYTES,v as OBSERVABILITY_TOOL_DEFINITIONS,m as READ_ONLY_TOOL_DEFINITIONS,x as WRITE_TOOL_DEFINITIONS,T as agentToolDefinitions,a as callAgentTool,i as callTool,_ as createAuthedMcpFetchHandler,O as createFunctionMcpServer,s as createMcpFetchHandler,N as createPaidMcpServer,n as createToolServer,E as mcpTokenScopes,c as parseAgentsEnv,M as serveStateless,D as toolDefinitions};
1
+ import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as T,callAgentTool as a,parseAgentsEnv as c}from"../packem_shared/AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{createAuthedMcpFetchHandler as _,mcpTokenScopes as E}from"../packem_shared/createAuthedMcpFetchHandler-Biw5KD-9.mjs";import{createToolServer as n}from"../packem_shared/createToolServer-CHAjfuNx.mjs";import{createFunctionMcpServer as O}from"../packem_shared/createFunctionMcpServer-BWaeQOFi.mjs";import{createMcpFetchHandler as s}from"../packem_shared/createMcpFetchHandler-McfnLMme.mjs";import{createPaidMcpServer as N}from"../packem_shared/createPaidMcpServer-CdDLw3G4.mjs";import{R as m,W as x,c as i,t as D}from"../packem_shared/tools-BMou4kPK.mjs";import{DEFAULT_MAX_REQUEST_BYTES as L,serveStateless as M}from"../packem_shared/DEFAULT_MAX_REQUEST_BYTES-CbbpkHRK.mjs";import{OBSERVABILITY_TOOL_DEFINITIONS as v}from"../packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,L as DEFAULT_MAX_REQUEST_BYTES,v as OBSERVABILITY_TOOL_DEFINITIONS,m as READ_ONLY_TOOL_DEFINITIONS,x as WRITE_TOOL_DEFINITIONS,T as agentToolDefinitions,a as callAgentTool,i as callTool,_ as createAuthedMcpFetchHandler,O as createFunctionMcpServer,s as createMcpFetchHandler,N as createPaidMcpServer,n as createToolServer,E as mcpTokenScopes,c as parseAgentsEnv,M as serveStateless,D as toolDefinitions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/mcp",
3
- "version": "1.0.0-alpha.266",
3
+ "version": "1.0.0-alpha.268",
4
4
  "description": "Model Context Protocol server exposing a Lunora deployment to AI agents",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -62,10 +62,10 @@
62
62
  },
63
63
  "dependencies": {
64
64
  "@cfworker/json-schema": "^4.1.1",
65
- "@lunora/client": "1.0.0-alpha.256",
65
+ "@lunora/client": "1.0.0-alpha.258",
66
66
  "@lunora/errors": ">=1.0.0-alpha.51 <2.0.0-0",
67
- "@lunora/shard-engine": "1.0.0-alpha.164",
68
- "@lunora/wire": "1.0.0-alpha.2",
67
+ "@lunora/shard-engine": "1.0.0-alpha.167",
68
+ "@lunora/wire": "1.0.0-alpha.3",
69
69
  "@modelcontextprotocol/sdk": "^1.32.0"
70
70
  },
71
71
  "peerDependencies": {
@@ -1 +0,0 @@
1
- import{LunoraClient as f}from"@lunora/client";import{StdioServerTransport as m}from"@modelcontextprotocol/sdk/server/stdio.js";import{e as p}from"./promise-memo-OqVPWoUX.mjs";import{createToolServer as v}from"./createToolServer-CHAjfuNx.mjs";import{createRemoteDocsIndex as h}from"./DEFAULT_DOCS_BASE_URL-CiHy_Dbz.mjs";import{docsResources as E}from"./DOCS_URI_SCHEME-DBlxtzS6.mjs";import{docsTools as R}from"./DEFAULT_SEARCH_LIMIT-BMQ6HQ-x.mjs";import{E as O,a as y,t as T,b as _,c as S}from"./tools-Bylr9LPQ.mjs";import{e as P}from"./tool-result-CPDsNNuJ.mjs";const l=e=>e.docs===!1?void 0:h({...e.docs?.baseUrl===void 0?{}:{baseUrl:e.docs.baseUrl},...e.fetch===void 0?{}:{fetch:e.fetch}}),C="lunora",N="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).",g=8,d=e=>{const n=new Map;return t=>{const r=JSON.stringify([t.url,t.token??""]),c=n.get(r);if(c!==void 0)return c;const o=new f({fetch:e,url:t.url});return t.token!==void 0&&t.token.length>0&&o.setAuthToken(t.token),p(n,g),n.set(r,o),o}},i=e=>e?.token!==void 0&&e.token.length>0,A=(e,n,t)=>{const r=typeof e=="function"?e:()=>e;return T(n,i(r())).filter(c=>!_.has(c.name)).map(c=>({definition:c,handle:async o=>{const s=r();return s===void 0?P("NO_DEPLOYMENT",N):S(t(s),c.name,o,n,i(s))}}))},I=()=>O.map(e=>({definition:e,handle:n=>Promise.resolve(y(e.name,n))})),k="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 e=>e.fetchOpenRpc(),name:"OpenRPC specification",uri:k},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async e=>e.fetchOpenApi(),name:"OpenAPI specification",uri:w}],L=(e,n)=>{const t=typeof e=="function"?e:()=>e,r=async c=>{const o=t();if(o!==void 0)try{return await c.fetch(n(o))}catch{return}};return{list:async()=>(await Promise.all(a.map(async o=>await r(o)===void 0?void 0:{description:o.description,mimeType:"application/json",name:o.name,uri:o.uri}))).filter(o=>o!==void 0),read:async c=>{const o=a.find(u=>u.uri===c);if(o===void 0)return;const s=await r(o);return s===void 0?void 0:{mimeType:"application/json",text:JSON.stringify(s,void 0,2)}}}},x=e=>({list:async()=>(await Promise.all(e.map(async t=>t.list()))).flat(),read:async n=>{for(const t of e){const r=await t.read(n);if(r!==void 0)return r}}}),M=(e,n)=>{const t=[],r=l(e);return r!==void 0&&t.push(...R(r)),t.push(...e.extraTools??[],...I()),e.deployment!==void 0&&t.push(...A(e.deployment,e.allowWrites??!1,n??d(e.fetch))),t},U=(e={})=>{const n=l(e),t=[];n!==void 0&&t.push(E(n));const r=d(e.fetch);return e.deployment!==void 0&&t.push(L(e.deployment,r)),v({name:C,version:e.version??"0.0.0"},M(e,r),t.length===0?void 0:x(t))},V=async(e={})=>{const n=U(e);return await n.connect(new m),n};export{C as LOCAL_SERVER_NAME,N as NO_DEPLOYMENT_MESSAGE,w as OPENAPI_RESOURCE_URI,k as OPENRPC_RESOURCE_URI,V as connectLocalStdio,U as createLocalMcpServer,M as localTools};
@@ -1 +0,0 @@
1
- import{LunoraClient as g}from"@lunora/client";import{LunoraError as m}from"@lunora/errors";import{Server as w}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as d,CallToolRequestSchema as h}from"@modelcontextprotocol/sdk/types.js";import{p as A}from"./package-7WeW8c_h.mjs";import{agentToolDefinitions as M,isAgentToolName as T,callAgentTool as R}from"./AGENT_RUN_INPUT_SCHEMA-BGbKIek4.mjs";import{t as k,c as N}from"./tools-Bylr9LPQ.mjs";const E="lunora",L=e=>{if(e.client!==void 0)return e.client;if(e.url===void 0)throw new m("INTERNAL","createLunoraMcpServer requires either a `client` or a `url`");if(e.token===void 0||e.token.length===0)throw new m("UNAUTHENTICATED","createLunoraMcpServer requires a `token` (LUNORA_ADMIN_TOKEN) alongside `url`: every tool reaches admin-gated /_lunora/admin/* routes, so an unauthenticated server can only 403. Writes stay off unless `allowWrites` is set.");const t=new g({fetch:e.fetch,url:e.url});return t.setAuthToken(e.token),t},C=e=>{const t=L(e),n=e.allowWrites??!1,o=e.allowAgents??!1,r=e.agents??[],s=typeof e.token=="string"&&e.token.length>0,i=e.allowObservability===!0&&s,c=e.allowDataReads===!0&&s,a=new w({name:E,version:e.version??A.version},{capabilities:{tools:{}}});return a.setRequestHandler(d,()=>({tools:[...k(n,i,c),...M(r,o)]})),a.setRequestHandler(h,async v=>{const{arguments:f,name:l}=v.params,u=f??{};return T(l,r)?await R(t,l,u,{allowAgents:o,exposures:r,...e.agentMaxWaitMs===void 0?{}:{maxWaitMs:e.agentMaxWaitMs},...e.agentPollIntervalMs===void 0?{}:{pollIntervalMs:e.agentPollIntervalMs}}):await N(t,l,u,n,i,c)}),a};export{C as createLunoraMcpServer,L as resolveClient};
@@ -1 +0,0 @@
1
- var a="1.0.0-alpha.265";const o={version:a};export{o as p};
@@ -1,2 +0,0 @@
1
- import{getCatalogEntry as q,resolveHint as Q,findIssueSolution as Y,isInternalCode as I,LunoraError as s}from"@lunora/errors";import{w as G,e as u,o as J,b as l,t as V,c as X,a as z}from"./tool-result-CPDsNNuJ.mjs";import{OBSERVABILITY_TOOL_NAMES as Z,OBSERVABILITY_TOOL_DEFINITIONS as ee,callObservabilityTool as te}from"./OBSERVABILITY_TOOL_DEFINITIONS-DQ7AUah0.mjs";import{ADMIN_FUNCTIONS as ne}from"@lunora/shard-engine";import{stableStringify as oe}from"@lunora/wire";import{m as ie}from"./promise-memo-OqVPWoUX.mjs";const re={destructiveHint:!1,idempotentHint:!0,openWorldHint:!1,readOnlyHint:!0},E="https://lunora.sh/docs/errors",se={properties:{code:{description:'The error code to explain, e.g. "CONFLICT" or "RLS_REQUIRED". Case-sensitive; codes are SCREAMING_SNAKE_CASE.',type:"string"},message:{description:"The raw error message, when there is no code (codegen and Cloudflare platform errors arrive as plain text). Matched against the solution tables.",type:"string"}},type:"object"},ae={properties:{code:{description:"The code that was looked up, when one was given.",type:"string"},docsUrl:{description:"Link to this code's section of the published error reference.",type:"string"},found:{description:"False when neither the code nor the message matched anything — the other fields are then absent.",type:"boolean"},hint:{description:"Actionable Markdown remediation, when the catalog or a message rule has one.",type:"string"},internal:{description:"True when the code is redacted on the wire: its real message is logged server-side and never reaches a client, so it is absent from the published reference.",type:"boolean"},solution:{description:"A message-matched solution: { id, header, body }, from Lunora's rules or the Cloudflare platform table.",type:"object"},status:{description:"HTTP/RPC status this code maps to on the wire.",type:"number"},title:{description:"Short human-readable summary of the code.",type:"string"}},required:["found"],type:"object"},D=[{annotations:{...re,title:"Explain a Lunora error"},description:"Explain a Lunora error before guessing at a fix: pass its code (CONFLICT, RLS_REQUIRED, …) or the raw error message, and get the catalog's transport status, title and actionable hint, plus any matched codegen/Cloudflare solution and a link to the reference. Static catalog data — no deployment and no credentials needed.",inputSchema:se,name:"lunora_explain_error",outputSchema:G(ae)}],ce=new Set(D.map(e=>e.name)),A=e=>typeof e=="string"&&e.length>0?e:void 0,de=e=>typeof e=="string"?e:e.join(`
2
- `),le=(e,t)=>t?.docsUrl!==void 0?t.docsUrl:e===void 0||t===void 0||I(e)?E:`${E}#${e.toLowerCase()}`,ue=(e,t)=>{const n=e===void 0?void 0:q(e),o=e===void 0?void 0:Q({code:e}),i=t===void 0?void 0:Y(t),r={docsUrl:le(e,n),found:n!==void 0||i!==void 0};return e!==void 0&&(r.code=e,I(e)&&(r.internal=!0)),n!==void 0&&(r.status=n.status,r.title=n.title),o!==void 0&&(r.hint=de(o)),i!==void 0&&(r.solution={body:i.body,header:i.header,id:i.id}),r},he=(e,t)=>{if(e!=="lunora_explain_error")return u("NOT_FOUND",`unknown error tool: ${e}`);const n=A(t.code),o=A(t.message);return n===void 0&&o===void 0?u("BAD_REQUEST",'lunora_explain_error needs a "code" or a "message" (or both); received neither.'):J(ue(n,o))},pe={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},fe={properties:{cursor:{description:"Opaque cursor from a previous call's continueCursor, to fetch the next page.",type:"string"},depth:{description:"How many hops to follow. 1 (default) is the direct neighbourhood; maximum 4.",type:"number"},direction:{description:'Which way to follow foreign keys: "out" follows the ids this row holds (ticket → customer), "in" the rows that point at it (customer → tickets), "both" (default) does both.',type:"string"},edges:{description:'Restrict the walk to these edge names, each "<table>.<column>" (e.g. "tickets.customerId"). Omit to follow every declared foreign key.',items:{type:"string"},type:"array"},id:{description:"Document id of the row to start from.",type:"string"},limit:{description:"Maximum related rows to return (default 50, maximum 200).",type:"number"},shardKey:{description:"Shard to read from on a .shardBy()-partitioned deployment. Omit for the default (unsharded) shard.",type:"string"},table:{description:'Table the start row lives in, e.g. "customers".',type:"string"}},required:["table","id"],type:"object"},C=[{annotations:{...pe,title:"Find rows related to a row"},description:"Follow the schema's foreign keys out of one row and return the rows it is connected to, each with its hop distance, the edge names walked to reach it, and a depth-decaying score. Use this to answer 'what is connected to this' — a customer's tickets, those tickets' messages — which keyword and semantic search cannot, because the connection lives in a foreign key rather than in the text. Read-only, but it reads through the deployment's ADMIN writer: RLS policies and column masks do not apply to what it returns.",inputSchema:fe,name:"lunora_find_related"}],me=new Set(C.map(e=>e.name)),ge=e=>{const{cursor:t,depth:n,direction:o,edges:i,limit:r}=e;if(t!=null&&typeof t!="string")throw new s("BAD_REQUEST","findRelated: `cursor` must be a string");if(n!==void 0&&typeof n!="number")throw new s("BAD_REQUEST","findRelated: `depth` must be a number");if(o!==void 0&&o!=="both"&&o!=="in"&&o!=="out")throw new s("BAD_REQUEST",'findRelated: `direction` must be one of "in", "out" or "both"');if(r!==void 0&&typeof r!="number")throw new s("BAD_REQUEST","findRelated: `limit` must be a number");if(i!==void 0&&(!Array.isArray(i)||!i.every(a=>typeof a=="string")))throw new s("BAD_REQUEST","findRelated: `edges` must be an array of edge-name strings")},ye=e=>{const{cursor:t,depth:n,direction:o,edges:i,id:r,limit:a,shardKey:d,table:c}=e;if(typeof c!="string"||c.trim()==="")throw new s("BAD_REQUEST","findRelated: `table` is required");if(typeof r!="string"||r.trim()==="")throw new s("BAD_REQUEST","findRelated: `id` is required");if(ge(e),d!==void 0&&(typeof d!="string"||d.trim()===""))throw new s("BAD_REQUEST","findRelated: `shardKey` must be a non-empty string when given");return{args:{id:r,table:c,...typeof t=="string"?{cursor:t}:{},...n===void 0?{}:{depth:n},...o===void 0?{}:{direction:o},...i===void 0?{}:{edges:i},...a===void 0?{}:{limit:a}},shardKey:d}},we=async(e,t,n)=>{if(t!=="lunora_find_related")throw new s("INTERNAL",`unknown row-read tool: ${t}`);const{args:o,shardKey:i}=ye(n),r={__lunoraRef:ne.findRelated};return l(await e.query(r,o,{...i===void 0?{}:{shardKey:i}}))},g=new TextEncoder,_e=Array.from({length:32},(e,t)=>t);new RegExp(`[${_e.map(e=>String.fromCodePoint(e)).join("")}]`,"u");const Ee=64,Ae=new Map,L=async e=>ie(Ae,e,async()=>crypto.subtle.importKey("raw",g.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign","verify"]),Ee),Oe=async(e,t)=>{const n=await L(e),o=await crypto.subtle.sign("HMAC",n,g.encode(t));return V(new Uint8Array(o))},Te=async(e,t,n)=>{const o=await L(e);return crypto.subtle.verify("HMAC",o,n,g.encode(t))},be="lunora-mcp-write-confirmation-v1",U=600*1e3,k=".",H=e=>{const t=e.getAuthToken();if(t===null||t==="")throw new s("UNAUTHORIZED","write confirmation needs a bearer token for this deployment: it is the secret half of the digest key, and without it a digest would be forgeable by anyone.");return`${be}\0${e.url}\0${t}`},P=(e,t)=>`${oe(e)}\0${String(t)}`,Re=async(e,t)=>{const n=Date.now()+U,o=await Oe(H(e),P(t,n));return{actionDigest:`${String(n)}${k}${o}`,expiresAt:n}},ve=async(e,t,n)=>{const o=n.indexOf(k);if(o<=0)return"mismatch";const i=Number(n.slice(0,o));if(!Number.isSafeInteger(i)||i<=0)return"mismatch";if(Date.now()>=i)return"expired";let r;try{r=X(n.slice(o+1))}catch{return"mismatch"}return await Te(H(e),P(t,i),r)?"valid":"mismatch"},Ne="Optional caller-chosen token folded into the digest. GUARANTEE: a retry after a client timeout can resubmit the confirmation you already hold, for as long as that digest is inside its window, instead of asking for a second review — and a deliberately-repeated identical write sent under a NEW key gets its own digest, so it cannot ride the first review. NOT GUARANTEED: this does not deduplicate the write. The server keeps no state between requests and never forwards the key to the function, so a resubmitted confirmed call executes again. Make the function itself idempotent if the write must happen at most once.",Se={actionDigest:{description:"The digest returned by the preceding action_required result. Required together with confirmed, and only valid until the expiresAt that result reported — past that, propose again.",type:"string"},confirmed:{description:"Set to true ONLY on the second call, after a human has reviewed the proposed action, and only together with the actionDigest that proposal returned. Omit it on the first call. The server cannot tell whether a human actually reviewed it — that is this client's responsibility, and the operator enabled writes on the understanding that this client asks.",type:"boolean"},idempotencyKey:{description:Ne,type:"string"}},Ie=e=>{const t=typeof e.actionDigest=="string"&&e.actionDigest.length>0?e.actionDigest:void 0,n=typeof e.idempotencyKey=="string"&&e.idempotencyKey.length>0?e.idempotencyKey:void 0;return{actionDigest:t,confirmed:e.confirmed===!0,idempotencyKey:n}},M="«sensitive»",De=(e,t)=>{if(t.length===0)return e;const n=Object.fromEntries(Object.entries(e.args).map(([o,i])=>[o,t.includes(o)?M:i]));return{...e,args:n}},Ce=["functionPath","args","shardKey","idempotencyKey"],Le=e=>e.length>1?`${e.slice(0,-1).join(", ")} and ${e.at(-1)??""}`:e.join(""),Ue=(e,t,n,o)=>l({actionDigest:t.actionDigest,expiresAt:new Date(t.expiresAt).toISOString(),nextStep:`Show proposedAction to a human. To execute, call ${e.tool} again with the IDENTICAL ${Le(o)}, plus confirmed: true and this actionDigest, before expiresAt. Resend the REAL values of any argument shown as "${M}": that placeholder is display only and will not verify. Nothing has been written or called yet.`,proposedAction:De(e,n),status:"action_required"}),ke=async(e,t,n,o=[],i=Ce)=>{if(!n.confirmed||n.actionDigest===void 0)return Ue(t,await Re(e,t),o,i);const r=await ve(e,t,n.actionDigest);if(r!=="valid")return r==="expired"?u("CONFIRMATION_EXPIRED",`confirmation rejected: this actionDigest has expired. A confirmation is good for ${String(U/6e4)} minutes from the proposal that issued it, so an approval cannot be replayed in a later session. Nothing was written. Call ${t.tool} again WITHOUT confirmed to get a fresh actionDigest, have it reviewed, then resubmit those same arguments with it.`):u("CONFIRMATION_MISMATCH",`confirmation rejected: the actionDigest does not match this call. A digest is bound to the exact tool, function path, arguments, shard key and idempotency key it was issued for, so any edit to the proposal invalidates it — and a digest from another deployment never matches. Nothing was written. Call ${t.tool} again WITHOUT confirmed to get a fresh actionDigest for the current arguments, have it reviewed, then resubmit those same arguments with it.`)},x={properties:{args:{description:"Arguments object passed to the function",type:"object"},functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"},shardKey:{description:"Optional shard key when the function is .shardBy()-partitioned",type:"string"}},required:["functionPath"],type:"object"},O={properties:{},type:"object"},He={properties:{functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"}},required:["functionPath"],type:"object"},p={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},$=[{annotations:{...p,title:"List deployment functions"},description:"List the deployment's public functions (queries, mutations, actions) with their kinds.",inputSchema:O,name:"lunora_list_functions"},{annotations:{...p,title:"List global tables"},description:"List the deployment's .global() tables with their row counts. Names and row counts only — no column shapes.",inputSchema:O,name:"lunora_list_tables"},{annotations:{...p,title:"Describe a function's arguments"},description:"Return a function's argument descriptors (name, validator kind, whether it is optional) and its kind, so a caller can construct a valid arguments object. Call lunora_list_functions first to discover available function paths.",inputSchema:He,name:"lunora_get_function_schema"},{annotations:{...p,title:"Run a query"},description:"Run a query and return its result. Read-only.",inputSchema:x,name:"lunora_run_query"}],Pe=new Set($.map(e=>e.name)),T={properties:{...x.properties,...Se},required:["functionPath"],type:"object"},b='TWO-STEP: the first call does NOT execute. It returns status "action_required" with the proposed action, an actionDigest and the expiresAt it is good until; show that to a human, then call again before expiresAt with the IDENTICAL functionPath/args/shardKey plus confirmed: true and that actionDigest. Any change to the target or the arguments produces a different digest and needs a fresh review, and an expired digest is refused rather than re-proposed.',F=[{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run a mutation (writes data)"},description:`Run a mutation. Writes data. ${b}`,inputSchema:T,name:"lunora_run_mutation"},{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run an action (may call external services)"},description:`Run an action. May call external services — send mail, charge a card, hit a third-party API — so the confirmation is the only thing between a proposal and a real-world side effect. ${b}`,inputSchema:T,name:"lunora_run_action"}],Me=new Set(F.map(e=>e.name)),B=e=>{const{functionPath:t}=e;if(typeof t!="string"||t.length===0)throw new s("BAD_REQUEST",'"functionPath" is required and must be a non-empty string');return t},R=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),v=e=>Array.isArray(e)?"an array":`a ${typeof e}`,xe=e=>{if(e==null)return{};if(typeof e=="string"){let t;try{t=JSON.parse(e)}catch{throw new s("BAD_REQUEST",'"args" must be a JSON object; received a string that is not valid JSON')}if(!R(t))throw new s("BAD_REQUEST",`"args" must be a JSON object; the provided string decoded to ${v(t)}`);return t}if(!R(e))throw new s("BAD_REQUEST",`"args" must be a JSON object, got ${v(e)}`);return e},K=e=>{const t=B(e),n=xe(e.args),o=typeof e.shardKey=="string"&&e.shardKey.length>0?e.shardKey:void 0;return{args:n,functionPath:t,shardKey:o}},W=e=>({__lunoraRef:e}),$e=3e4,h=new WeakMap,m=e=>{const t=Date.now(),n=h.get(e);if(n!==void 0&&n.expiresAt>t)return n.promise;const o=e.listFunctions().catch(i=>{throw h.get(e)?.promise===o&&h.delete(e),i});return h.set(e,{expiresAt:t+$e,promise:o}),o},j=async(e,t,n)=>{const i=(await m(e)).find(r=>r.path===t);if(i===void 0)throw new s("NOT_FOUND",`function not found or not public: ${t}`);if(i.kind!==n)throw new s("BAD_REQUEST",`function ${t} is a ${i.kind}, not a ${n}`);return i},Fe=async(e,t,n,o,i,r)=>{const a=Ie(i);return ke(e,{...o,idempotencyKey:a.idempotencyKey,kind:n,tool:t},a,r)},Be=e=>(e.args??[]).filter(t=>t.sensitive===!0).map(t=>t.name),Ke=async(e,t,n)=>{switch(t){case"lunora_get_function_schema":{const o=B(n),r=(await m(e)).find(a=>a.path===o);return r===void 0?u("NOT_FOUND",`function not found: ${o}`):l({args:r.args??[],kind:r.kind,path:r.path})}case"lunora_list_functions":return l(await m(e));case"lunora_list_tables":return l(await e.listGlobalTables());case"lunora_run_query":{const{args:o,functionPath:i,shardKey:r}=K(n);return await j(e,i,"query"),l(await e.query(W(i),o,{shardKey:r}))}default:throw new s("INTERNAL",`unknown read-only tool: ${t}`)}},We=async(e,t,n)=>{if(t!=="lunora_run_action"&&t!=="lunora_run_mutation")throw new s("INTERNAL",`unknown write tool: ${t}`);const o=t==="lunora_run_action"?"action":"mutation",{args:i,functionPath:r,shardKey:a}=K(n);h.delete(e);const d=await j(e,r,o),c=Be(d),w=await Fe(e,t,o,{args:i,functionPath:r,shardKey:a},n,c);if(w!==void 0)return w;const _=c.length===0?W(r):{__lunoraRef:r,sensitive:!0};return l(o==="action"?await e.action(_,i,{shardKey:a}):await e.mutation(_,i,{onlineOnly:!0,shardKey:a}))},N="lunora:data-read",S="lunora:observability",je=e=>e===!0,f=[{call:Ke,definitions:$,names:Pe},{call:(e,t,n)=>he(t,n),definitions:D,names:ce},{call:we,definitions:C,gate:{flag:"allowDataReads",refuse:e=>`tool "${e}" is disabled: it returns raw table rows read through the deployment's ADMIN writer, so RLS policies and column masks do not apply. Enable it with the LUNORA_MCP_ALLOW_DATA_READS env var or the allowDataReads option; on the authed path the token also needs the ${N} scope.`,scope:N},names:me},{call:te,definitions:ee,gate:{flag:"allowObservability",refuse:e=>`tool "${e}" is disabled: it reads the deployment's logs, request metadata and grouped errors — user data that would land at the model provider. Enable it with the LUNORA_MCP_ALLOW_OBSERVABILITY env var or the allowObservability option; on the authed path the token also needs the ${S} scope.`,scope:S},names:Z},{call:We,definitions:F,gate:{flag:"allowWrites",refuse:e=>`tool "${e}" is disabled: this MCP server is read-only. Enable writes with the LUNORA_MCP_ALLOW_WRITES env var.`},names:Me}],y=(e,t)=>e.gate!==void 0&&!je(t[e.gate.flag])?e.gate:void 0,Xe=(e,t=!1,n=!1)=>{const o={allowDataReads:n,allowObservability:t,allowWrites:e};return f.filter(i=>y(i,o)===void 0).flatMap(i=>i.definitions)},ze=async(e,t,n,o=!1,i=!1,r=!1)=>{const a=f.find(c=>c.names.has(t));if(a===void 0)return u("NOT_FOUND",`unknown tool: ${t}`);const d=y(a,{allowDataReads:r,allowObservability:i,allowWrites:o});if(d!==void 0)return u("FORBIDDEN",d.refuse(t));try{return await a.call(e,t,n)}catch(c){return z(c)}},Ze=(e,t)=>{const n=f.find(o=>o.names.has(e));if(!(n?.gate?.scope===void 0||y(n,t)!==void 0))return n.gate.scope},et=f.flatMap(e=>e.gate?.scope===void 0?[]:[{flag:e.gate.flag,scope:e.gate.scope}]);export{N as D,D as E,S as O,$ as R,et as S,F as W,he as a,ce as b,ze as c,Me as d,Se as e,Ie as f,ke as g,C as h,xe as r,Ze as s,Xe as t};