@lunora/mcp 1.0.0-alpha.70 → 1.0.0-alpha.71

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 (37) hide show
  1. package/dist/bin.mjs +3 -3
  2. package/dist/docs/index.d.mts +102 -2
  3. package/dist/docs/index.d.ts +102 -2
  4. package/dist/docs/index.mjs +1 -1
  5. package/dist/index.d.mts +51 -1
  6. package/dist/index.d.ts +51 -1
  7. package/dist/index.mjs +1 -1
  8. package/dist/packem_shared/AGENT_RUN_INPUT_SCHEMA-DRSY74ed.mjs +1 -0
  9. package/dist/packem_shared/DEFAULT_DOCS_BASE_URL-CZ3fVsSc.mjs +4 -0
  10. package/dist/packem_shared/{DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs → DEFAULT_SEARCH_LIMIT-DWPt0hvR.mjs} +2 -2
  11. package/dist/packem_shared/DOCS_SERVER_NAME-BWzPxJyZ.mjs +1 -0
  12. package/dist/packem_shared/DOCS_URI_SCHEME-CFANc3vr.mjs +3 -0
  13. package/dist/packem_shared/LOCAL_SERVER_NAME-0Jb4neqA.mjs +1 -0
  14. package/dist/packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-KrCukPbu.mjs +1 -0
  15. package/dist/packem_shared/READ_ONLY_TOOL_DEFINITIONS-DGexf3Tn.mjs +1 -0
  16. package/dist/packem_shared/connectStdio-BCeI0Wqu.mjs +1 -0
  17. package/dist/packem_shared/createMcpFetchHandler-TKDnZTGs.mjs +1 -0
  18. package/dist/packem_shared/createPaidMcpServer-CQO-59WV.mjs +1 -0
  19. package/dist/packem_shared/createToolServer-BtGuPyMU.mjs +1 -0
  20. package/dist/packem_shared/observability-tools-Ce0YK58T.mjs +1 -0
  21. package/dist/packem_shared/serveStateless-Db7J3pAO.mjs +1 -0
  22. package/dist/packem_shared/toDocsSearchHits-CBLmtWXt.mjs +1 -0
  23. package/package.json +3 -3
  24. package/dist/packem_shared/AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs +0 -1
  25. package/dist/packem_shared/DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs +0 -4
  26. package/dist/packem_shared/DOCS_SERVER_NAME-BYSXEkgD.mjs +0 -1
  27. package/dist/packem_shared/DOCS_URI_SCHEME-DbyotZvf.mjs +0 -3
  28. package/dist/packem_shared/LOCAL_SERVER_NAME-BFbVWtCm.mjs +0 -1
  29. package/dist/packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DwJpdhPe.mjs +0 -1
  30. package/dist/packem_shared/READ_ONLY_TOOL_DEFINITIONS-BygXkni2.mjs +0 -1
  31. package/dist/packem_shared/connectStdio-nqnOab_d.mjs +0 -1
  32. package/dist/packem_shared/createMcpFetchHandler-Cz_tRkpm.mjs +0 -1
  33. package/dist/packem_shared/createPaidMcpServer-CwdcSPpN.mjs +0 -1
  34. package/dist/packem_shared/createToolServer-CP5bNUcS.mjs +0 -1
  35. package/dist/packem_shared/observability-tools-GVGcK_kZ.mjs +0 -1
  36. package/dist/packem_shared/serveStateless-BqoRk-xU.mjs +0 -1
  37. package/dist/packem_shared/toDocsSearchHits-C1xXPRPy.mjs +0 -1
package/dist/bin.mjs CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env node
2
- import{parseAgentsEnv as A}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{connectStdio as N}from"./packem_shared/connectStdio-nqnOab_d.mjs";const d=new Set(["1","on","true","yes"]),L=r=>r!==void 0&&d.has(r.trim().toLowerCase());class a extends Error{code;constructor(e,o){super(e),this.name="BinError",this.code=o}}const l=async(r,e={})=>{const o=e.connect??N,n=e.writeError??(t=>{process.stderr.write(t)}),s=r.LUNORA_URL;if(s===void 0||s.length===0)throw n(`lunora-mcp: LUNORA_URL environment variable is required
3
- `),new a("LUNORA_URL environment variable is required",1);const i=Number(r.LUNORA_MCP_AGENT_TIMEOUT_MS),c=Number.isFinite(i)&&i>0?i:void 0;try{await o({agents:A(r.LUNORA_MCP_AGENTS),allowAgents:L(r.LUNORA_MCP_ALLOW_AGENTS),allowWrites:L(r.LUNORA_MCP_ALLOW_WRITES),token:r.LUNORA_ADMIN_TOKEN,url:s,...c===void 0?{}:{agentMaxWaitMs:c}})}catch(t){const _=t instanceof Error?t.message:String(t);throw n(`lunora-mcp: failed to start — ${_}
4
- `),new a(`failed to start — ${_}`,1)}};try{await l(process.env)}catch(r){process.exit(r instanceof a?r.code:1)}
2
+ import{parseAgentsEnv as A}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-DRSY74ed.mjs";import{connectStdio as L}from"./packem_shared/connectStdio-BCeI0Wqu.mjs";const N=new Set(["1","on","true","yes"]),_=r=>r!==void 0&&N.has(r.trim().toLowerCase());class i extends Error{code;constructor(o,e){super(o),this.name="BinError",this.code=e}}const w=async(r,o={})=>{const e=o.connect??L,a=o.writeError??(t=>{process.stderr.write(t)}),s=r.LUNORA_URL;if(s===void 0||s.length===0)throw a(`lunora-mcp: LUNORA_URL environment variable is required
3
+ `),new i("LUNORA_URL environment variable is required",1);const n=Number(r.LUNORA_MCP_AGENT_TIMEOUT_MS),c=Number.isFinite(n)&&n>0?n:void 0;try{await e({agents:A(r.LUNORA_MCP_AGENTS),allowAgents:_(r.LUNORA_MCP_ALLOW_AGENTS),allowWrites:_(r.LUNORA_MCP_ALLOW_WRITES),token:r.LUNORA_ADMIN_TOKEN,url:s,...c===void 0?{}:{agentMaxWaitMs:c}})}catch(t){const E=t instanceof Error?t.message:String(t);throw a(`lunora-mcp: failed to start — ${E}
4
+ `),new i(`failed to start — ${E}`,1)}};try{await w(process.env)}catch(r){process.exit(r instanceof i?r.code:1)}
@@ -1,5 +1,55 @@
1
1
  import { M as McpResourceProvider, a as McpFetchHandler, T as ToolDefinition, b as McpTool } from "../packem_shared/serve-stateless.d-B_q8q39X.mjs";
2
- export type { c as McpResourceSummary, d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-B_q8q39X.mjs";
2
+ export type {
3
+ /**
4
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
5
+ * `lunora_get_doc`, and `lunora_list_docs`.
6
+ *
7
+ * Where the package's main entry exposes a deployment to an agent (its
8
+ * functions and data, behind an admin token), this entry exposes the
9
+ * framework's documentation, so an agent writing Lunora code can look up the
10
+ * real API instead of inventing one. It reads published docs only — no
11
+ * credentials, no writes — so a server built from it is safe to host
12
+ * unauthenticated.
13
+ *
14
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
15
+ * its own in-process search index, while anything else (the CLI's
16
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
17
+ * published site over HTTP.
18
+ *
19
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
20
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
21
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
22
+ *
23
+ * Only the documentation surface lives here. The generic composition primitive
24
+ * (`createToolServer`) is exported from the package root, so a consumer using
25
+ * both entries gets one implementation rather than two copies.
26
+ */
27
+ c as McpResourceSummary,
28
+ /**
29
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
30
+ * `lunora_get_doc`, and `lunora_list_docs`.
31
+ *
32
+ * Where the package's main entry exposes a deployment to an agent (its
33
+ * functions and data, behind an admin token), this entry exposes the
34
+ * framework's documentation, so an agent writing Lunora code can look up the
35
+ * real API instead of inventing one. It reads published docs only — no
36
+ * credentials, no writes — so a server built from it is safe to host
37
+ * unauthenticated.
38
+ *
39
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
40
+ * its own in-process search index, while anything else (the CLI's
41
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
42
+ * published site over HTTP.
43
+ *
44
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
45
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
46
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
47
+ *
48
+ * Only the documentation surface lives here. The generic composition primitive
49
+ * (`createToolServer`) is exported from the package root, so a consumer using
50
+ * both entries gets one implementation rather than two copies.
51
+ */
52
+ d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-B_q8q39X.mjs";
3
53
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
54
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
5
55
  /**
@@ -147,4 +197,54 @@ declare const normalizeDocUrl: (raw: string) => string;
147
197
  * read and act on.
148
198
  */
149
199
  declare const docsTools: (index: DocsIndex) => ReadonlyArray<McpTool>;
150
- export { DEFAULT_DOCS_BASE_URL, DEFAULT_SEARCH_LIMIT, DOCS_SERVER_NAME, DOCS_TOOL_DEFINITIONS, DOCS_URI_SCHEME, type DocsIndex, type DocsMcpServerOptions, type DocsPage, type DocsPageSummary, type DocsSearchHit, type FumadocsSearchResult, MAX_SEARCH_LIMIT, type McpFetchHandler, type McpResourceProvider, type McpTool, type RemoteDocsIndexOptions, type ToolDefinition, createDocsMcpFetchHandler, createDocsMcpServer, createRemoteDocsIndex, docsResources, docsTools, fromDocsUri, normalizeDocUrl, toDocsSearchHits, toDocsUri };
200
+ export { DEFAULT_DOCS_BASE_URL, DEFAULT_SEARCH_LIMIT, DOCS_SERVER_NAME, DOCS_TOOL_DEFINITIONS, DOCS_URI_SCHEME, type DocsIndex, type DocsMcpServerOptions, type DocsPage, type DocsPageSummary, type DocsSearchHit, type FumadocsSearchResult, MAX_SEARCH_LIMIT, type McpFetchHandler,
201
+ /**
202
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
203
+ * `lunora_get_doc`, and `lunora_list_docs`.
204
+ *
205
+ * Where the package's main entry exposes a deployment to an agent (its
206
+ * functions and data, behind an admin token), this entry exposes the
207
+ * framework's documentation, so an agent writing Lunora code can look up the
208
+ * real API instead of inventing one. It reads published docs only — no
209
+ * credentials, no writes — so a server built from it is safe to host
210
+ * unauthenticated.
211
+ *
212
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
213
+ * its own in-process search index, while anything else (the CLI's
214
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
215
+ * published site over HTTP.
216
+ *
217
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
218
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
219
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
220
+ *
221
+ * Only the documentation surface lives here. The generic composition primitive
222
+ * (`createToolServer`) is exported from the package root, so a consumer using
223
+ * both entries gets one implementation rather than two copies.
224
+ */
225
+ type McpResourceProvider,
226
+ /**
227
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
228
+ * `lunora_get_doc`, and `lunora_list_docs`.
229
+ *
230
+ * Where the package's main entry exposes a deployment to an agent (its
231
+ * functions and data, behind an admin token), this entry exposes the
232
+ * framework's documentation, so an agent writing Lunora code can look up the
233
+ * real API instead of inventing one. It reads published docs only — no
234
+ * credentials, no writes — so a server built from it is safe to host
235
+ * unauthenticated.
236
+ *
237
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
238
+ * its own in-process search index, while anything else (the CLI's
239
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
240
+ * published site over HTTP.
241
+ *
242
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
243
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
244
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
245
+ *
246
+ * Only the documentation surface lives here. The generic composition primitive
247
+ * (`createToolServer`) is exported from the package root, so a consumer using
248
+ * both entries gets one implementation rather than two copies.
249
+ */
250
+ type McpTool, type RemoteDocsIndexOptions, type ToolDefinition, createDocsMcpFetchHandler, createDocsMcpServer, createRemoteDocsIndex, docsResources, docsTools, fromDocsUri, normalizeDocUrl, toDocsSearchHits, toDocsUri };
@@ -1,5 +1,55 @@
1
1
  import { M as McpResourceProvider, a as McpFetchHandler, T as ToolDefinition, b as McpTool } from "../packem_shared/serve-stateless.d-B_q8q39X.js";
2
- export type { c as McpResourceSummary, d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-B_q8q39X.js";
2
+ export type {
3
+ /**
4
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
5
+ * `lunora_get_doc`, and `lunora_list_docs`.
6
+ *
7
+ * Where the package's main entry exposes a deployment to an agent (its
8
+ * functions and data, behind an admin token), this entry exposes the
9
+ * framework's documentation, so an agent writing Lunora code can look up the
10
+ * real API instead of inventing one. It reads published docs only — no
11
+ * credentials, no writes — so a server built from it is safe to host
12
+ * unauthenticated.
13
+ *
14
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
15
+ * its own in-process search index, while anything else (the CLI's
16
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
17
+ * published site over HTTP.
18
+ *
19
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
20
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
21
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
22
+ *
23
+ * Only the documentation surface lives here. The generic composition primitive
24
+ * (`createToolServer`) is exported from the package root, so a consumer using
25
+ * both entries gets one implementation rather than two copies.
26
+ */
27
+ c as McpResourceSummary,
28
+ /**
29
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
30
+ * `lunora_get_doc`, and `lunora_list_docs`.
31
+ *
32
+ * Where the package's main entry exposes a deployment to an agent (its
33
+ * functions and data, behind an admin token), this entry exposes the
34
+ * framework's documentation, so an agent writing Lunora code can look up the
35
+ * real API instead of inventing one. It reads published docs only — no
36
+ * credentials, no writes — so a server built from it is safe to host
37
+ * unauthenticated.
38
+ *
39
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
40
+ * its own in-process search index, while anything else (the CLI's
41
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
42
+ * published site over HTTP.
43
+ *
44
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
45
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
46
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
47
+ *
48
+ * Only the documentation surface lives here. The generic composition primitive
49
+ * (`createToolServer`) is exported from the package root, so a consumer using
50
+ * both entries gets one implementation rather than two copies.
51
+ */
52
+ d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-B_q8q39X.js";
3
53
  import { Server } from '@modelcontextprotocol/sdk/server/index.js';
4
54
  import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
5
55
  /**
@@ -147,4 +197,54 @@ declare const normalizeDocUrl: (raw: string) => string;
147
197
  * read and act on.
148
198
  */
149
199
  declare const docsTools: (index: DocsIndex) => ReadonlyArray<McpTool>;
150
- export { DEFAULT_DOCS_BASE_URL, DEFAULT_SEARCH_LIMIT, DOCS_SERVER_NAME, DOCS_TOOL_DEFINITIONS, DOCS_URI_SCHEME, type DocsIndex, type DocsMcpServerOptions, type DocsPage, type DocsPageSummary, type DocsSearchHit, type FumadocsSearchResult, MAX_SEARCH_LIMIT, type McpFetchHandler, type McpResourceProvider, type McpTool, type RemoteDocsIndexOptions, type ToolDefinition, createDocsMcpFetchHandler, createDocsMcpServer, createRemoteDocsIndex, docsResources, docsTools, fromDocsUri, normalizeDocUrl, toDocsSearchHits, toDocsUri };
200
+ export { DEFAULT_DOCS_BASE_URL, DEFAULT_SEARCH_LIMIT, DOCS_SERVER_NAME, DOCS_TOOL_DEFINITIONS, DOCS_URI_SCHEME, type DocsIndex, type DocsMcpServerOptions, type DocsPage, type DocsPageSummary, type DocsSearchHit, type FumadocsSearchResult, MAX_SEARCH_LIMIT, type McpFetchHandler,
201
+ /**
202
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
203
+ * `lunora_get_doc`, and `lunora_list_docs`.
204
+ *
205
+ * Where the package's main entry exposes a deployment to an agent (its
206
+ * functions and data, behind an admin token), this entry exposes the
207
+ * framework's documentation, so an agent writing Lunora code can look up the
208
+ * real API instead of inventing one. It reads published docs only — no
209
+ * credentials, no writes — so a server built from it is safe to host
210
+ * unauthenticated.
211
+ *
212
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
213
+ * its own in-process search index, while anything else (the CLI's
214
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
215
+ * published site over HTTP.
216
+ *
217
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
218
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
219
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
220
+ *
221
+ * Only the documentation surface lives here. The generic composition primitive
222
+ * (`createToolServer`) is exported from the package root, so a consumer using
223
+ * both entries gets one implementation rather than two copies.
224
+ */
225
+ type McpResourceProvider,
226
+ /**
227
+ * `@lunora/mcp/docs` — the documentation tool surface: `lunora_search_docs`,
228
+ * `lunora_get_doc`, and `lunora_list_docs`.
229
+ *
230
+ * Where the package's main entry exposes a deployment to an agent (its
231
+ * functions and data, behind an admin token), this entry exposes the
232
+ * framework's documentation, so an agent writing Lunora code can look up the
233
+ * real API instead of inventing one. It reads published docs only — no
234
+ * credentials, no writes — so a server built from it is safe to host
235
+ * unauthenticated.
236
+ *
237
+ * Two backends implement the same `DocsIndex` contract: a docs site wires up
238
+ * its own in-process search index, while anything else (the CLI's
239
+ * `lunora mcp serve`, a script) uses `createRemoteDocsIndex` to read a
240
+ * published site over HTTP.
241
+ *
242
+ * This entry is free of Node built-ins and of `@lunora/client`, so it runs on
243
+ * Workers, Netlify/Vercel functions, Deno, and Bun unchanged —
244
+ * `scripts/check-dist-production.js` asserts that against the emitted chunks.
245
+ *
246
+ * Only the documentation surface lives here. The generic composition primitive
247
+ * (`createToolServer`) is exported from the package root, so a consumer using
248
+ * both entries gets one implementation rather than two copies.
249
+ */
250
+ type McpTool, type RemoteDocsIndexOptions, type ToolDefinition, createDocsMcpFetchHandler, createDocsMcpServer, createRemoteDocsIndex, docsResources, docsTools, fromDocsUri, normalizeDocUrl, toDocsSearchHits, toDocsUri };
@@ -1 +1 @@
1
- import{toDocsSearchHits as e}from"../packem_shared/toDocsSearchHits-C1xXPRPy.mjs";import{DEFAULT_DOCS_BASE_URL as D,createRemoteDocsIndex as t}from"../packem_shared/DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs";import{DOCS_URI_SCHEME as s,docsResources as S,fromDocsUri as E,toDocsUri as I}from"../packem_shared/DOCS_URI_SCHEME-DbyotZvf.mjs";import{DOCS_SERVER_NAME as R,createDocsMcpFetchHandler as p,createDocsMcpServer as A}from"../packem_shared/DOCS_SERVER_NAME-BYSXEkgD.mjs";import{DEFAULT_SEARCH_LIMIT as M,DOCS_TOOL_DEFINITIONS as O,MAX_SEARCH_LIMIT as T,docsTools as U,normalizeDocUrl as a}from"../packem_shared/DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";export{D as DEFAULT_DOCS_BASE_URL,M as DEFAULT_SEARCH_LIMIT,R as DOCS_SERVER_NAME,O as DOCS_TOOL_DEFINITIONS,s as DOCS_URI_SCHEME,T as MAX_SEARCH_LIMIT,p as createDocsMcpFetchHandler,A as createDocsMcpServer,t as createRemoteDocsIndex,S as docsResources,U as docsTools,E as fromDocsUri,a as normalizeDocUrl,e as toDocsSearchHits,I as toDocsUri};
1
+ import{toDocsSearchHits as e}from"../packem_shared/toDocsSearchHits-CBLmtWXt.mjs";import{DEFAULT_DOCS_BASE_URL as D,createRemoteDocsIndex as t}from"../packem_shared/DEFAULT_DOCS_BASE_URL-CZ3fVsSc.mjs";import{DOCS_URI_SCHEME as s,docsResources as S,fromDocsUri as E,toDocsUri as I}from"../packem_shared/DOCS_URI_SCHEME-CFANc3vr.mjs";import{DOCS_SERVER_NAME as R,createDocsMcpFetchHandler as p,createDocsMcpServer as A}from"../packem_shared/DOCS_SERVER_NAME-BWzPxJyZ.mjs";import{DEFAULT_SEARCH_LIMIT as M,DOCS_TOOL_DEFINITIONS as O,MAX_SEARCH_LIMIT as T,docsTools as U,normalizeDocUrl as a}from"../packem_shared/DEFAULT_SEARCH_LIMIT-DWPt0hvR.mjs";export{D as DEFAULT_DOCS_BASE_URL,M as DEFAULT_SEARCH_LIMIT,R as DOCS_SERVER_NAME,O as DOCS_TOOL_DEFINITIONS,s as DOCS_URI_SCHEME,T as MAX_SEARCH_LIMIT,p as createDocsMcpFetchHandler,A as createDocsMcpServer,t as createRemoteDocsIndex,S as docsResources,U as docsTools,E as fromDocsUri,a as normalizeDocUrl,e as toDocsSearchHits,I as toDocsUri};
package/dist/index.d.mts CHANGED
@@ -318,4 +318,54 @@ interface PaidMcpServer {
318
318
  * transient facilitator outage retries on the next call.
319
319
  */
320
320
  declare const createPaidMcpServer: (config: PaidMcpServerConfig) => PaidMcpServer;
321
- export { AGENT_RUN_INPUT_SCHEMA, AGENT_STATUS_TOOL_NAME, type CallAgentToolOptions, LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, type LunoraMcpServerOptions, type McpAgentExposure, type McpFetchHandler, type McpTool, NO_DEPLOYMENT_MESSAGE, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolResult, WRITE_TOOL_DEFINITIONS, agentToolDefinitions, callAgentTool, callTool, connectLocalStdio, connectStdio, createLocalMcpServer, createLunoraMcpServer, createMcpFetchHandler, createPaidMcpServer, localTools, parseAgentsEnv, toolDefinitions };
321
+ export { AGENT_RUN_INPUT_SCHEMA, AGENT_STATUS_TOOL_NAME,
322
+ /**
323
+ * `@lunora/mcp` — Model Context Protocol servers for Lunora. This entry exposes
324
+ * a *deployment* to AI agents; the `@lunora/mcp/docs` subpath exposes the
325
+ * framework's *documentation* (credential-free, and safe to host publicly).
326
+ *
327
+ * The deployment server: It registers tools for introspecting a deployment
328
+ * (`lunora_list_functions`, `lunora_list_tables`) and invoking its functions
329
+ * (`lunora_run_query`, plus `lunora_run_mutation` and `lunora_run_action` when
330
+ * writes are enabled), each backed by `LunoraClient` over HTTP RPC. It also
331
+ * exposes the deployment's observability reads (`lunora_get_logs`,
332
+ * `lunora_get_issues`, `lunora_get_advisories`, `lunora_get_query_insights`,
333
+ * `lunora_get_migration_status`) whenever an admin token resolved — read-only,
334
+ * but privileged, so they are omitted entirely without one. The server is
335
+ * read-only by default — the write tools are exposed only when `allowWrites`
336
+ * (or the `LUNORA_MCP_ALLOW_WRITES` env) is set, and every run tool is
337
+ * allowlisted against the deployment's discovered public functions. It can also
338
+ * front durable `@lunora/agent` runs as `agent_<name>` tools when `allowAgents`
339
+ * (or `LUNORA_MCP_ALLOW_AGENTS` + `LUNORA_MCP_AGENTS`) is set. Run the
340
+ * `lunora-mcp` binary (configured via the `LUNORA_URL`, `LUNORA_ADMIN_TOKEN`,
341
+ * and `LUNORA_MCP_ALLOW_WRITES` env vars) for the stdio transport, serve the
342
+ * server remotely over Streamable HTTP with `createMcpFetchHandler` (a
343
+ * Workers-ready `Request` → `Response` handler), or build a server
344
+ * programmatically with `createLunoraMcpServer` and connect any transport.
345
+ */
346
+ type CallAgentToolOptions, LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, type LunoraMcpServerOptions,
347
+ /**
348
+ * `@lunora/mcp` — Model Context Protocol servers for Lunora. This entry exposes
349
+ * a *deployment* to AI agents; the `@lunora/mcp/docs` subpath exposes the
350
+ * framework's *documentation* (credential-free, and safe to host publicly).
351
+ *
352
+ * The deployment server: It registers tools for introspecting a deployment
353
+ * (`lunora_list_functions`, `lunora_list_tables`) and invoking its functions
354
+ * (`lunora_run_query`, plus `lunora_run_mutation` and `lunora_run_action` when
355
+ * writes are enabled), each backed by `LunoraClient` over HTTP RPC. It also
356
+ * exposes the deployment's observability reads (`lunora_get_logs`,
357
+ * `lunora_get_issues`, `lunora_get_advisories`, `lunora_get_query_insights`,
358
+ * `lunora_get_migration_status`) whenever an admin token resolved — read-only,
359
+ * but privileged, so they are omitted entirely without one. The server is
360
+ * read-only by default — the write tools are exposed only when `allowWrites`
361
+ * (or the `LUNORA_MCP_ALLOW_WRITES` env) is set, and every run tool is
362
+ * allowlisted against the deployment's discovered public functions. It can also
363
+ * front durable `@lunora/agent` runs as `agent_<name>` tools when `allowAgents`
364
+ * (or `LUNORA_MCP_ALLOW_AGENTS` + `LUNORA_MCP_AGENTS`) is set. Run the
365
+ * `lunora-mcp` binary (configured via the `LUNORA_URL`, `LUNORA_ADMIN_TOKEN`,
366
+ * and `LUNORA_MCP_ALLOW_WRITES` env vars) for the stdio transport, serve the
367
+ * server remotely over Streamable HTTP with `createMcpFetchHandler` (a
368
+ * Workers-ready `Request` → `Response` handler), or build a server
369
+ * programmatically with `createLunoraMcpServer` and connect any transport.
370
+ */
371
+ type McpAgentExposure, type McpFetchHandler, type McpTool, NO_DEPLOYMENT_MESSAGE, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolResult, WRITE_TOOL_DEFINITIONS, agentToolDefinitions, callAgentTool, callTool, connectLocalStdio, connectStdio, createLocalMcpServer, createLunoraMcpServer, createMcpFetchHandler, createPaidMcpServer, localTools, parseAgentsEnv, toolDefinitions };
package/dist/index.d.ts CHANGED
@@ -318,4 +318,54 @@ interface PaidMcpServer {
318
318
  * transient facilitator outage retries on the next call.
319
319
  */
320
320
  declare const createPaidMcpServer: (config: PaidMcpServerConfig) => PaidMcpServer;
321
- export { AGENT_RUN_INPUT_SCHEMA, AGENT_STATUS_TOOL_NAME, type CallAgentToolOptions, LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, type LunoraMcpServerOptions, type McpAgentExposure, type McpFetchHandler, type McpTool, NO_DEPLOYMENT_MESSAGE, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolResult, WRITE_TOOL_DEFINITIONS, agentToolDefinitions, callAgentTool, callTool, connectLocalStdio, connectStdio, createLocalMcpServer, createLunoraMcpServer, createMcpFetchHandler, createPaidMcpServer, localTools, parseAgentsEnv, toolDefinitions };
321
+ export { AGENT_RUN_INPUT_SCHEMA, AGENT_STATUS_TOOL_NAME,
322
+ /**
323
+ * `@lunora/mcp` — Model Context Protocol servers for Lunora. This entry exposes
324
+ * a *deployment* to AI agents; the `@lunora/mcp/docs` subpath exposes the
325
+ * framework's *documentation* (credential-free, and safe to host publicly).
326
+ *
327
+ * The deployment server: It registers tools for introspecting a deployment
328
+ * (`lunora_list_functions`, `lunora_list_tables`) and invoking its functions
329
+ * (`lunora_run_query`, plus `lunora_run_mutation` and `lunora_run_action` when
330
+ * writes are enabled), each backed by `LunoraClient` over HTTP RPC. It also
331
+ * exposes the deployment's observability reads (`lunora_get_logs`,
332
+ * `lunora_get_issues`, `lunora_get_advisories`, `lunora_get_query_insights`,
333
+ * `lunora_get_migration_status`) whenever an admin token resolved — read-only,
334
+ * but privileged, so they are omitted entirely without one. The server is
335
+ * read-only by default — the write tools are exposed only when `allowWrites`
336
+ * (or the `LUNORA_MCP_ALLOW_WRITES` env) is set, and every run tool is
337
+ * allowlisted against the deployment's discovered public functions. It can also
338
+ * front durable `@lunora/agent` runs as `agent_<name>` tools when `allowAgents`
339
+ * (or `LUNORA_MCP_ALLOW_AGENTS` + `LUNORA_MCP_AGENTS`) is set. Run the
340
+ * `lunora-mcp` binary (configured via the `LUNORA_URL`, `LUNORA_ADMIN_TOKEN`,
341
+ * and `LUNORA_MCP_ALLOW_WRITES` env vars) for the stdio transport, serve the
342
+ * server remotely over Streamable HTTP with `createMcpFetchHandler` (a
343
+ * Workers-ready `Request` → `Response` handler), or build a server
344
+ * programmatically with `createLunoraMcpServer` and connect any transport.
345
+ */
346
+ type CallAgentToolOptions, LOCAL_SERVER_NAME, type LocalDeployment, type LocalDeploymentSource, type LocalMcpServerOptions, type LunoraMcpServerOptions,
347
+ /**
348
+ * `@lunora/mcp` — Model Context Protocol servers for Lunora. This entry exposes
349
+ * a *deployment* to AI agents; the `@lunora/mcp/docs` subpath exposes the
350
+ * framework's *documentation* (credential-free, and safe to host publicly).
351
+ *
352
+ * The deployment server: It registers tools for introspecting a deployment
353
+ * (`lunora_list_functions`, `lunora_list_tables`) and invoking its functions
354
+ * (`lunora_run_query`, plus `lunora_run_mutation` and `lunora_run_action` when
355
+ * writes are enabled), each backed by `LunoraClient` over HTTP RPC. It also
356
+ * exposes the deployment's observability reads (`lunora_get_logs`,
357
+ * `lunora_get_issues`, `lunora_get_advisories`, `lunora_get_query_insights`,
358
+ * `lunora_get_migration_status`) whenever an admin token resolved — read-only,
359
+ * but privileged, so they are omitted entirely without one. The server is
360
+ * read-only by default — the write tools are exposed only when `allowWrites`
361
+ * (or the `LUNORA_MCP_ALLOW_WRITES` env) is set, and every run tool is
362
+ * allowlisted against the deployment's discovered public functions. It can also
363
+ * front durable `@lunora/agent` runs as `agent_<name>` tools when `allowAgents`
364
+ * (or `LUNORA_MCP_ALLOW_AGENTS` + `LUNORA_MCP_AGENTS`) is set. Run the
365
+ * `lunora-mcp` binary (configured via the `LUNORA_URL`, `LUNORA_ADMIN_TOKEN`,
366
+ * and `LUNORA_MCP_ALLOW_WRITES` env vars) for the stdio transport, serve the
367
+ * server remotely over Streamable HTTP with `createMcpFetchHandler` (a
368
+ * Workers-ready `Request` → `Response` handler), or build a server
369
+ * programmatically with `createLunoraMcpServer` and connect any transport.
370
+ */
371
+ type McpAgentExposure, type McpFetchHandler, type McpTool, NO_DEPLOYMENT_MESSAGE, OBSERVABILITY_TOOL_DEFINITIONS, type PaidMcpChargeConfig, type PaidMcpServer, type PaidMcpServerConfig, READ_ONLY_TOOL_DEFINITIONS, type RegisterPaidToolOptions, type RegisterToolOptions, type ToolDefinition, type ToolHandler, type ToolInputSchema, type ToolResult, WRITE_TOOL_DEFINITIONS, agentToolDefinitions, callAgentTool, callTool, connectLocalStdio, connectStdio, createLocalMcpServer, createLunoraMcpServer, createMcpFetchHandler, createPaidMcpServer, localTools, parseAgentsEnv, toolDefinitions };
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as T,callAgentTool as c,parseAgentsEnv as E}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{createToolServer as S}from"./packem_shared/createToolServer-CP5bNUcS.mjs";import{createMcpFetchHandler as l}from"./packem_shared/createMcpFetchHandler-Cz_tRkpm.mjs";import{LOCAL_SERVER_NAME as N,NO_DEPLOYMENT_MESSAGE as n,connectLocalStdio as p,createLocalMcpServer as A,localTools as I}from"./packem_shared/LOCAL_SERVER_NAME-BFbVWtCm.mjs";import{createPaidMcpServer as f}from"./packem_shared/createPaidMcpServer-CwdcSPpN.mjs";import{connectStdio as m,createLunoraMcpServer as s}from"./packem_shared/connectStdio-nqnOab_d.mjs";import{READ_ONLY_TOOL_DEFINITIONS as M,WRITE_TOOL_DEFINITIONS as D,callTool as v,toolDefinitions as R}from"./packem_shared/READ_ONLY_TOOL_DEFINITIONS-BygXkni2.mjs";import{A as F}from"./packem_shared/observability-tools-GVGcK_kZ.mjs";import{serveStateless as G}from"./packem_shared/serveStateless-BqoRk-xU.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,N as LOCAL_SERVER_NAME,n as NO_DEPLOYMENT_MESSAGE,F as OBSERVABILITY_TOOL_DEFINITIONS,M as READ_ONLY_TOOL_DEFINITIONS,D as WRITE_TOOL_DEFINITIONS,T as agentToolDefinitions,c as callAgentTool,v as callTool,p as connectLocalStdio,m as connectStdio,A as createLocalMcpServer,s as createLunoraMcpServer,l as createMcpFetchHandler,f as createPaidMcpServer,S as createToolServer,I as localTools,E as parseAgentsEnv,G as serveStateless,R as toolDefinitions};
1
+ import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as T,callAgentTool as c,parseAgentsEnv as E}from"./packem_shared/AGENT_RUN_INPUT_SCHEMA-DRSY74ed.mjs";import{createToolServer as O}from"./packem_shared/createToolServer-BtGuPyMU.mjs";import{createMcpFetchHandler as _}from"./packem_shared/createMcpFetchHandler-TKDnZTGs.mjs";import{LOCAL_SERVER_NAME as N,NO_DEPLOYMENT_MESSAGE as n,connectLocalStdio as p,createLocalMcpServer as I,localTools as A}from"./packem_shared/LOCAL_SERVER_NAME-0Jb4neqA.mjs";import{createPaidMcpServer as f}from"./packem_shared/createPaidMcpServer-CQO-59WV.mjs";import{connectStdio as m,createLunoraMcpServer as s}from"./packem_shared/connectStdio-BCeI0Wqu.mjs";import{READ_ONLY_TOOL_DEFINITIONS as M,WRITE_TOOL_DEFINITIONS as D,callTool as v,toolDefinitions as R}from"./packem_shared/READ_ONLY_TOOL_DEFINITIONS-DGexf3Tn.mjs";import{O as F}from"./packem_shared/observability-tools-Ce0YK58T.mjs";import{serveStateless as G}from"./packem_shared/serveStateless-Db7J3pAO.mjs";export{r as AGENT_RUN_INPUT_SCHEMA,t as AGENT_STATUS_TOOL_NAME,N as LOCAL_SERVER_NAME,n as NO_DEPLOYMENT_MESSAGE,F as OBSERVABILITY_TOOL_DEFINITIONS,M as READ_ONLY_TOOL_DEFINITIONS,D as WRITE_TOOL_DEFINITIONS,T as agentToolDefinitions,c as callAgentTool,v as callTool,p as connectLocalStdio,m as connectStdio,I as createLocalMcpServer,s as createLunoraMcpServer,_ as createMcpFetchHandler,f as createPaidMcpServer,O as createToolServer,A as localTools,E as parseAgentsEnv,G as serveStateless,R as toolDefinitions};
@@ -0,0 +1 @@
1
+ const v="agents:agentRun",A="agents:agentThread",b="agents:agentMessages",g="lunora_agent_status",T=new Set(["cancelled","error","idle"]),x=6e4,U=600,L={properties:{prompt:{description:"The task or message for the agent.",type:"string"},threadKey:{description:"Reuse to continue a conversation; omit to start a new thread.",type:"string"},title:{description:"Optional thread title (first run only).",type:"string"}},required:["prompt"],type:"object"},P={properties:{threadKey:{description:"The thread key returned by an agent tool call.",type:"string"}},required:["threadKey"],type:"object"},p=t=>t.toolName??`agent_${t.name}`,G=t=>{if(t===void 0)return[];const n=[];for(const e of t.split(";")){const r=e.trim();if(r.length===0)continue;const o=r.indexOf(":");if(o<=0)continue;const s=r.slice(0,o).trim(),a=r.slice(o+1).trim();s.length===0||a.length===0||n.push({description:a,name:s})}return n},O=(t,n)=>n!==!0||t.length===0?[]:[...t.map(r=>({description:`${r.description} Starts a durable agent run and returns its final answer.`,inputSchema:L,name:p(r)})),{description:"Check the status of a durable agent run (and its answer if finished) by its threadKey.",inputSchema:P,name:g}],q=(t,n)=>t===g||n.some(e=>p(e)===t),k=()=>`mcp-${crypto.randomUUID()}`,l=t=>({__lunoraRef:t}),I=async t=>{await new Promise(n=>{setTimeout(n,t)})},d=t=>({content:[{text:JSON.stringify(t,void 0,2),type:"text"}]}),i=t=>({content:[{text:t,type:"text"}],isError:!0}),u=(t,n)=>{const e=t[n];return typeof e=="string"&&e.length>0?e:void 0},K=t=>{for(let n=t.length-1;n>=0;n-=1){const e=t[n],r=e?.toolCalls,o=Array.isArray(r)&&r.length>0;if(e?.role==="assistant"&&!o)return typeof e.content=="string"?e.content:""}return""},_=t=>t!==null&&typeof t=="object"&&typeof t.status=="string"?t.status:"unknown",S=async(t,n,e,r)=>{const o=await t.query(l(b),{key:n});if(e==="error"){const s=r!==null&&typeof r=="object"?r.error:void 0;return d({error:typeof s=="string"?s:"the agent run failed",status:e,threadKey:n})}return d({status:e,text:K(o),threadKey:n})},R=async(t,n)=>{const e=u(n,"threadKey");if(e===void 0)return i('"threadKey" is required and must be a non-empty string');const r=await t.query(l(A),{key:e}),o=_(r);return T.has(o)?S(t,e,o,r):d({status:o==="unknown"?"running":o,threadKey:e})},C=async(t,n,e,r)=>{try{if(r.allowAgents!==!0)return i(`tool "${n}" is disabled: agent tools are off. Enable them with the LUNORA_MCP_ALLOW_AGENTS env var.`);if(n===g)return await R(t,e);const o=r.exposures.find(c=>p(c)===n);if(o===void 0)return i(`agent tool "${n}" is not exposed by this MCP server`);const s=u(e,"prompt");if(s===void 0)return i('"prompt" is required and must be a non-empty string');const a=u(e,"threadKey")??k(),f=u(e,"title"),{id:w}=await t.mutation(l(v),{agent:o.name,input:s,threadKey:a,...f===void 0?{}:{title:f}}),y=r.pollIntervalMs??U,E=r.maxWaitMs??x,N=r.wait??I,M=Math.max(1,Math.ceil(E/y));for(let c=0;c<M;c+=1){const h=await t.query(l(A),{key:a}),m=_(h);if(T.has(m))return await S(t,a,m,h);await N(y)}return d({hint:"call lunora_agent_status with this threadKey to poll for the answer",runId:w,status:"running",threadKey:a})}catch(o){const s=o instanceof Error?o.message:String(o);return i(s)}};export{L as AGENT_RUN_INPUT_SCHEMA,g as AGENT_STATUS_TOOL_NAME,O as agentToolDefinitions,C as callAgentTool,K as finalAnswer,q as isAgentToolName,G as parseAgentsEnv};
@@ -0,0 +1,4 @@
1
+ import{toDocsSearchHits as h}from"./toDocsSearchHits-CBLmtWXt.mjs";const f="https://lunora.sh",u=1e4,m=t=>t.endsWith("/")?t.slice(0,-1):t,p="\\",g=(t,n,i)=>{for(let s=i;s<t.length;s+=1)if(t[s]===n&&t[s-1]!==p)return s;return-1},d=t=>t.replaceAll(String.raw`\[`,"[").replaceAll(String.raw`\]`,"]").replaceAll(String.raw`\(`,"(").replaceAll(String.raw`\)`,")"),S=t=>{const n=t.trim();if(!n.startsWith("- ["))return;const i=n.lastIndexOf("](");if(i===-1)return;const s=g(n,")",i+2);if(s===-1)return;const o=d(n.slice(3,i).trim()),c=d(n.slice(i+2,s).trim());if(o.length===0||c.length===0)return;const e=n.slice(s+1).trim(),r=e.startsWith(":")?e.slice(1).trim():"";return r.length>0?{description:r,title:o,url:c}:{title:o,url:c}},x=t=>{if(!t.endsWith(")"))return t;const n=t.lastIndexOf(" (");if(n===-1)return t;const i=t.slice(n+2,-1);return i.startsWith("/")||i.startsWith("http")?t.slice(0,n).trim():t},y=(t,n)=>{for(const i of t.split(`
2
+ `)){if(i.startsWith("# "))return x(i.slice(2).trim());if(i.trim().length>0)break}return n},b=t=>{if(!t.startsWith("# "))return t;const n=t.indexOf(`
3
+ `);return n===-1?"":t.slice(n+1).trimStart()},A=(t={})=>{const n=m(t.baseUrl??f),i=t.fetch??globalThis.fetch,s=t.timeoutMs??u,o=async e=>{try{const r=await i(`${n}${e}`,{headers:{accept:"text/plain, application/json"},signal:AbortSignal.timeout(s)});return r.ok?{body:await r.text()}:{missing:!0}}catch(r){return{unreachable:r instanceof Error?r.message:String(r)}}},c=(e,r)=>{if("unreachable"in e)throw new Error(`could not reach the documentation site at ${n}${r}: ${e.unreachable}`);return"missing"in e?void 0:e.body};return{getPage:async e=>{const r=c(await o(`/llms.mdx${e}`),`/llms.mdx${e}`);if(!(r===void 0||r.trim().length===0))return{content:b(r),title:y(r,e),url:e}},listPages:async()=>{const e=c(await o("/llms.txt"),"/llms.txt");if(e===void 0)return[];const r=[];for(const l of e.split(`
4
+ `)){const a=S(l);a!==void 0&&r.push(a)}return r},search:async e=>{const r=`/api/search?query=${encodeURIComponent(e)}`,l=c(await o(r),r);if(l===void 0)return[];let a;try{a=JSON.parse(l)}catch{return[]}return Array.isArray(a)?h(a):[]}}};export{f as DEFAULT_DOCS_BASE_URL,u as DEFAULT_REQUEST_TIMEOUT_MS,A as createRemoteDocsIndex,S as parseIndexLine};
@@ -1,3 +1,3 @@
1
- const w=10,S=50,h="docs",L=500,p={properties:{limit:{description:`Maximum hits to return (default ${String(10)}, max ${String(50)})`,type:"number"},query:{description:'Search terms, e.g. "shardBy" or "optimistic updates"',type:"string"}},required:["query"],type:"object"},g={properties:{url:{description:'Site-relative page URL from a search hit, e.g. "/docs/sharding"',type:"string"}},required:["url"],type:"object"},m={properties:{},type:"object"},i={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},u={annotations:{...i,title:"Search the Lunora documentation"},description:"Search the Lunora documentation and return matching pages and sections. Use this before writing Lunora code (schema, queries, mutations, actions, sharding, .global(), client hooks) so the answer reflects the framework's current API rather than a guess. Follow a hit with lunora_get_doc to read the full page.",inputSchema:p,name:"lunora_search_docs"},l={annotations:{...i,title:"Read a Lunora documentation page"},description:"Return one Lunora documentation page in full, as Markdown. Takes the `url` of a lunora_search_docs hit or a lunora_list_docs entry.",inputSchema:g,name:"lunora_get_doc"},d={annotations:{...i,title:"List the Lunora documentation pages"},description:"List every Lunora documentation page with its title and description. Prefer lunora_search_docs when you know what you're looking for.",inputSchema:m,name:"lunora_list_docs"},$=[u,l,d],o=e=>({content:[{text:JSON.stringify(e,void 0,2),type:"text"}]}),f=e=>({content:[{text:e,type:"text"}],isError:!0}),a=512,c=(e,t)=>{const n=e[t];if(typeof n!="string"||n.trim().length===0)throw new TypeError(`"${t}" is required and must be a non-empty string`);if(n.length>a)throw new RangeError(`"${t}" must be at most ${String(a)} characters`);return n.trim()},_=e=>{const t=typeof e=="string"?Number(e):e;return typeof t!="number"||!Number.isFinite(t)?10:Math.min(50,Math.max(1,Math.floor(t)))},y=e=>{let t=e.trim();if(t.startsWith("http://")||t.startsWith("https://")){const n=t.slice(t.indexOf("//")+2),r=n.indexOf("/");t=r===-1?"/":n.slice(r)}for(const n of["?","#"]){const r=t.indexOf(n);r!==-1&&(t=t.slice(0,r))}for(;t.endsWith("/")&&t.length>1;)t=t.slice(0,-1);if(t.startsWith("/")||(t=t.startsWith("docs/")?`/${t}`:`/${h}/${t}`),t.split("/").includes(".."))throw new RangeError(`"url" must not contain ".." segments: ${e}`);return t},x=e=>[{definition:u,handle:async t=>{const n=c(t,"query"),r=_(t.limit),s=(await e.search(n)).slice(0,r);return s.length===0?o({hits:[],note:`no documentation matched "${n}" — try fewer or more general terms, or lunora_list_docs to browse`}):o({hits:s})}},{definition:l,handle:async t=>{const n=y(c(t,"url")),r=await e.getPage(n);return r===void 0?f(`documentation page not found: ${n}. Use lunora_search_docs or lunora_list_docs to find a valid url.`):{content:[{text:`# ${r.title} (${r.url})
1
+ const T=10,I=50,h="docs",A=500,_={properties:{limit:{description:`Maximum hits to return (default ${String(10)}, max ${String(50)})`,type:"number"},query:{description:'Search terms, e.g. "shardBy" or "optimistic updates"',type:"string"}},required:["query"],type:"object"},p={properties:{url:{description:'Site-relative page URL from a search hit, e.g. "/docs/sharding"',type:"string"}},required:["url"],type:"object"},g={properties:{},type:"object"},i={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},u={annotations:{...i,title:"Search the Lunora documentation"},description:"Search the Lunora documentation and return matching pages and sections. Use this before writing Lunora code (schema, queries, mutations, actions, sharding, .global(), client hooks) so the answer reflects the framework's current API rather than a guess. Follow a hit with lunora_get_doc to read the full page.",inputSchema:_,name:"lunora_search_docs"},l={annotations:{...i,title:"Read a Lunora documentation page"},description:"Return one Lunora documentation page in full, as Markdown. Takes the `url` of a lunora_search_docs hit or a lunora_list_docs entry.",inputSchema:p,name:"lunora_get_doc"},d={annotations:{...i,title:"List the Lunora documentation pages"},description:"List every Lunora documentation page with its title and description. Prefer lunora_search_docs when you know what you're looking for.",inputSchema:g,name:"lunora_list_docs"},L=[u,l,d],o=e=>({content:[{text:JSON.stringify(e,void 0,2),type:"text"}]}),m=e=>({content:[{text:e,type:"text"}],isError:!0}),a=512,c=(e,t)=>{const n=e[t];if(typeof n!="string"||n.trim().length===0)throw new TypeError(`"${t}" is required and must be a non-empty string`);if(n.length>a)throw new RangeError(`"${t}" must be at most ${String(a)} characters`);return n.trim()},f=e=>{const t=typeof e=="string"?Number(e):e;return typeof t!="number"||!Number.isFinite(t)?10:Math.min(50,Math.max(1,Math.floor(t)))},S=e=>{let t=e.trim();if(t.startsWith("http://")||t.startsWith("https://")){const n=t.slice(t.indexOf("//")+2),r=n.indexOf("/");t=r===-1?"/":n.slice(r)}for(const n of["?","#"]){const r=t.indexOf(n);r!==-1&&(t=t.slice(0,r))}for(;t.endsWith("/")&&t.length>1;)t=t.slice(0,-1);if(t.startsWith("/")||(t=t.startsWith("docs/")?`/${t}`:`/${h}/${t}`),t.split("/").includes(".."))throw new RangeError(`"url" must not contain ".." segments: ${e}`);return t},y=e=>[{definition:u,handle:async t=>{const n=c(t,"query"),r=f(t.limit),s=(await e.search(n)).slice(0,r);return s.length===0?o({hits:[],note:`no documentation matched "${n}" — try fewer or more general terms, or lunora_list_docs to browse`}):o({hits:s})}},{definition:l,handle:async t=>{const n=S(c(t,"url")),r=await e.getPage(n);return r===void 0?m(`documentation page not found: ${n}. Use lunora_search_docs or lunora_list_docs to find a valid url.`):{content:[{text:`# ${r.title} (${r.url})
2
2
 
3
- ${r.content}`,type:"text"}]}}},{definition:d,handle:async()=>{const t=await e.listPages();return t.length>500?o({note:`showing the first ${String(500)} of ${String(t.length)} pages — use lunora_search_docs to find the rest`,pages:t.slice(0,500)}):o(t)}}];export{w as DEFAULT_SEARCH_LIMIT,$ as DOCS_TOOL_DEFINITIONS,a as MAX_ARGUMENT_LENGTH,L as MAX_LISTED_PAGES,S as MAX_SEARCH_LIMIT,x as docsTools,y as normalizeDocUrl};
3
+ ${r.content}`,type:"text"}]}}},{definition:d,handle:async()=>{const t=await e.listPages();return t.length>500?o({note:`showing the first ${String(500)} of ${String(t.length)} pages — use lunora_search_docs to find the rest`,pages:t.slice(0,500)}):o(t)}}];export{T as DEFAULT_SEARCH_LIMIT,L as DOCS_TOOL_DEFINITIONS,a as MAX_ARGUMENT_LENGTH,A as MAX_LISTED_PAGES,I as MAX_SEARCH_LIMIT,y as docsTools,S as normalizeDocUrl};
@@ -0,0 +1 @@
1
+ import{createToolServer as d}from"./createToolServer-BtGuPyMU.mjs";import{serveStateless as a}from"./serveStateless-Db7J3pAO.mjs";import{docsResources as i}from"./DOCS_URI_SCHEME-CFANc3vr.mjs";import{docsTools as p}from"./DEFAULT_SEARCH_LIMIT-DWPt0hvR.mjs";const u="lunora-docs",y=128*1024,m=e=>({name:u,version:e??"0.0.0"}),l=e=>d(m(e.version),p(e.index),i(e.index)),S=e=>new TextEncoder().encode(e).length,t=(e,r,o)=>Response.json({error:{code:r,message:o},id:null,jsonrpc:"2.0"},{status:e}),f=async(e,r)=>{if(e.method!=="POST")return{parsedBody:void 0};const o={response:t(413,-32600,`request body exceeds ${String(r)} bytes`)},s=Number(e.headers.get("content-length"));if(Number.isFinite(s)&&s>r)return o;const c=await e.text();if(S(c)>r)return o;let n;try{n=JSON.parse(c)}catch{return{response:t(400,-32700,"parse error: body is not valid JSON")}}return Array.isArray(n)?{response:t(400,-32600,"batched requests are not supported: send one JSON-RPC message per request")}:{parsedBody:n}},g=e=>{const r=e.maxRequestBytes??y;return async o=>{const s=await f(o,r);return"response"in s?s.response:a(l(e),o,s.parsedBody===void 0?void 0:{parsedBody:s.parsedBody})}};export{y as DEFAULT_MAX_REQUEST_BYTES,u as DOCS_SERVER_NAME,g as createDocsMcpFetchHandler,l as createDocsMcpServer};
@@ -0,0 +1,3 @@
1
+ const r="lunora-docs:",i=t=>`${r}${t}`,n=t=>t.startsWith(r)?t.slice(r.length):void 0,c=t=>({list:async()=>(await t.listPages()).map(o=>({...o.description===void 0?{}:{description:o.description},mimeType:"text/markdown",name:o.title,uri:i(o.url)})),read:async s=>{const o=n(s);if(o===void 0)return;const e=await t.getPage(o);return e===void 0?void 0:{mimeType:"text/markdown",text:`# ${e.title} (${e.url})
2
+
3
+ ${e.content}`}}});export{r as DOCS_URI_SCHEME,c as docsResources,n as fromDocsUri,i as toDocsUri};
@@ -0,0 +1 @@
1
+ import{LunoraClient as f}from"@lunora/client";import{StdioServerTransport as p}from"@modelcontextprotocol/sdk/server/stdio.js";import{createToolServer as m}from"./createToolServer-BtGuPyMU.mjs";import{createRemoteDocsIndex as v}from"./DEFAULT_DOCS_BASE_URL-CZ3fVsSc.mjs";import{docsResources as h}from"./DOCS_URI_SCHEME-CFANc3vr.mjs";import{docsTools as y}from"./DEFAULT_SEARCH_LIMIT-DWPt0hvR.mjs";import{toolDefinitions as E,callTool as R}from"./READ_ONLY_TOOL_DEFINITIONS-DGexf3Tn.mjs";const O=(e,n)=>{if(e.size<n)return;const t=e.keys().next().value;t!==void 0&&e.delete(t)},l=e=>e.docs===!1?void 0:v({...e.docs?.baseUrl===void 0?{}:{baseUrl:e.docs.baseUrl},...e.fetch===void 0?{}:{fetch:e.fetch}}),_="lunora",S="no Lunora dev server is running for this project — start one with `lunora dev`, then call this tool again (call lunora_dev_status to check).",T=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),O(n,T),n.set(r,o),o}},i=e=>e?.token!==void 0&&e.token.length>0,C=(e,n,t)=>{const r=typeof e=="function"?e:()=>e;return E(n,i(r())).map(c=>({definition:c,handle:async o=>{const s=r();return s===void 0?{content:[{text:S,type:"text"}],isError:!0}:R(t(s),c.name,o,n,i(s))}}))},P="lunora-spec:openrpc",g="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:P},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async e=>e.fetchOpenApi(),name:"OpenAPI specification",uri:g}],k=(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)}}}},w=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}}}),x=(e,n)=>{const t=[],r=l(e);return r!==void 0&&t.push(...y(r)),t.push(...e.extraTools??[]),e.deployment!==void 0&&t.push(...C(e.deployment,e.allowWrites??!1,n??d(e.fetch))),t},A=(e={})=>{const n=l(e),t=[];n!==void 0&&t.push(h(n));const r=d(e.fetch);return e.deployment!==void 0&&t.push(k(e.deployment,r)),m({name:_,version:e.version??"0.0.0"},x(e,r),t.length===0?void 0:w(t))},j=async(e={})=>{const n=A(e);return await n.connect(new p),n};export{_ as LOCAL_SERVER_NAME,S as NO_DEPLOYMENT_MESSAGE,g as OPENAPI_RESOURCE_URI,P as OPENRPC_RESOURCE_URI,j as connectLocalStdio,A as createLocalMcpServer,x as localTools};
@@ -0,0 +1 @@
1
+ import{D as T,M as a,O as L,a as s,c as _}from"./observability-tools-Ce0YK58T.mjs";export{T as DEFAULT_LIMIT,a as MAX_LIMIT,L as OBSERVABILITY_TOOL_DEFINITIONS,s as OBSERVABILITY_TOOL_NAMES,_ as callObservabilityTool};
@@ -0,0 +1 @@
1
+ import{LunoraError as u}from"@lunora/errors";import{O as A,e as d,a as w,c as E,o as c}from"./observability-tools-Ce0YK58T.mjs";const m={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"},g={properties:{},type:"object"},R={properties:{functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"}},required:["functionPath"],type:"object"},l={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},I=[{annotations:{...l,title:"List deployment functions"},description:"List the deployment's public functions (queries, mutations, actions) with their kinds.",inputSchema:g,name:"lunora_list_functions"},{annotations:{...l,title:"List global tables"},description:"List the deployment's .global() tables and their column shapes.",inputSchema:g,name:"lunora_list_tables"},{annotations:{...l,title:"Describe a function's arguments"},description:"Return a function's argument JSON Schema and kind, so a caller can construct a valid arguments object. Call lunora_list_functions first to discover available function paths.",inputSchema:R,name:"lunora_get_function_schema"},{annotations:{...l,title:"Run a query"},description:"Run a query and return its result. Read-only.",inputSchema:m,name:"lunora_run_query"}],b=[{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run a mutation (writes data)"},description:"Run a mutation and return its result. Writes data — use with care.",inputSchema:m,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 and return its result. May call external services.",inputSchema:m,name:"lunora_run_action"}],L=new Set(b.map(t=>t.name)),U=(t,n=!1)=>[...I,...n===!0?A:[],...t===!0?b:[]],S=t=>{const{functionPath:n}=t;if(typeof n!="string"||n.length===0)throw new u("INTERNAL",'"functionPath" is required and must be a non-empty string');return n},O=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),N=t=>Array.isArray(t)?"an array":`a ${typeof t}`,v=t=>{if(t==null)return{};if(typeof t=="string"){let n;try{n=JSON.parse(t)}catch{throw new u("BAD_REQUEST",'"args" must be a JSON object; received a string that is not valid JSON')}if(!O(n))throw new u("BAD_REQUEST",`"args" must be a JSON object; the provided string decoded to ${N(n)}`);return n}if(!O(t))throw new u("BAD_REQUEST",`"args" must be a JSON object, got ${N(t)}`);return t},f=t=>{const n=S(t),e=v(t.args),o=typeof t.shardKey=="string"&&t.shardKey.length>0?t.shardKey:void 0;return{args:e,functionPath:n,shardKey:o}},p=t=>({__lunoraRef:t}),H=3e4,h=new WeakMap,y=t=>{const n=Date.now(),e=h.get(t);if(e!==void 0&&e.expiresAt>n)return e.promise;const o=t.listFunctions().catch(i=>{throw h.get(t)?.promise===o&&h.delete(t),i});return h.set(t,{expiresAt:n+H,promise:o}),o},_=async(t,n,e)=>{const i=(await y(t)).find(r=>r.path===n);if(i===void 0)throw new u("NOT_FOUND",`function not found or not public: ${n}`);if(i.kind!==e)throw new u("BAD_REQUEST",`function ${n} is a ${i.kind}, not a ${e}`)},k=async(t,n,e,o=!1,i=!1)=>{try{if(o!==!0&&L.has(n))return d(`tool "${n}" is disabled: this MCP server is read-only. Enable writes with the LUNORA_MCP_ALLOW_WRITES env var.`);if(w.has(n))return i!==!0?d(`tool "${n}" is unavailable: it reads the deployment's logs and errors, which needs an admin token. Set LUNORA_ADMIN_TOKEN (or pass --token) and reconnect.`):await E(t,n,e);switch(n){case"lunora_get_function_schema":{const r=S(e),s=(await y(t)).find(T=>T.path===r);return s===void 0?d(`function not found: ${r}`):c({args:s.args??[],kind:s.kind,path:s.path})}case"lunora_list_functions":return c(await y(t));case"lunora_list_tables":return c(await t.listGlobalTables());case"lunora_run_action":{const{args:r,functionPath:a,shardKey:s}=f(e);return await _(t,a,"action"),c(await t.action(p(a),r,{shardKey:s}))}case"lunora_run_mutation":{const{args:r,functionPath:a,shardKey:s}=f(e);return await _(t,a,"mutation"),c(await t.mutation(p(a),r,{shardKey:s}))}case"lunora_run_query":{const{args:r,functionPath:a,shardKey:s}=f(e);return await _(t,a,"query"),c(await t.query(p(a),r,{shardKey:s}))}default:return d(`unknown tool: ${n}`)}}catch(r){const a=r instanceof Error?r.message:String(r);return d(a)}};export{A as OBSERVABILITY_TOOL_DEFINITIONS,I as READ_ONLY_TOOL_DEFINITIONS,b as WRITE_TOOL_DEFINITIONS,k as callTool,U as toolDefinitions};
@@ -0,0 +1 @@
1
+ import{readFileSync as f}from"node:fs";import{dirname as c,join as v}from"node:path";import{fileURLToPath as g}from"node:url";import{LunoraClient as d}from"@lunora/client";import{LunoraError as h}from"@lunora/errors";import{Server as w}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as p}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as S,CallToolRequestSchema as T}from"@modelcontextprotocol/sdk/types.js";import{agentToolDefinitions as M,isAgentToolName as k,callAgentTool as y}from"./AGENT_RUN_INPUT_SCHEMA-DRSY74ed.mjs";import{toolDefinitions as A,callTool as R}from"./READ_ONLY_TOOL_DEFINITIONS-DGexf3Tn.mjs";const L=()=>{try{let e=c(g(import.meta.url));for(let r=0;r<8;r+=1){try{const o=f(v(e,"package.json"),"utf8"),t=JSON.parse(o);if(t.name==="@lunora/mcp"&&typeof t.version=="string"&&t.version.length>0)return t.version}catch{}const n=c(e);if(n===e)break;e=n}}catch{}return"0.0.0"},q={name:"lunora",version:L()},x=e=>{if(e.client!==void 0)return e.client;if(e.url===void 0)throw new h("INTERNAL","createLunoraMcpServer requires either a `client` or a `url`");const r=new d({fetch:e.fetch,url:e.url});return e.token!==void 0&&r.setAuthToken(e.token),r},I=e=>{const r=x(e),n=e.allowWrites??!1,o=e.allowAgents??!1,t=e.agents??[],s=typeof e.token=="string"&&e.token.length>0,a=new w(q,{capabilities:{tools:{}}});return a.setRequestHandler(S,()=>({tools:[...A(n,s),...M(t,o)]})),a.setRequestHandler(T,async m=>{const{arguments:u,name:l}=m.params,i=u??{};return k(l,t)?await y(r,l,i,{allowAgents:o,exposures:t,...e.agentMaxWaitMs===void 0?{}:{maxWaitMs:e.agentMaxWaitMs},...e.agentPollIntervalMs===void 0?{}:{pollIntervalMs:e.agentPollIntervalMs}}):await R(r,l,i,n,s)}),a},V=async e=>{const r=I(e);return await r.connect(new p),r};export{V as connectStdio,I as createLunoraMcpServer};
@@ -0,0 +1 @@
1
+ import{serveStateless as t}from"./serveStateless-Db7J3pAO.mjs";import{createLunoraMcpServer as o}from"./connectStdio-BCeI0Wqu.mjs";const p=e=>r=>t(o(e),r);export{p as createMcpFetchHandler,t as serveStateless};
@@ -0,0 +1 @@
1
+ import{LunoraError as u}from"@lunora/errors";import{Server as v}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as y,CallToolRequestSchema as w}from"@modelcontextprotocol/sdk/types.js";import{serveStateless as g}from"./serveStateless-Db7J3pAO.mjs";const S=async()=>{try{return(await import("@lunora/x402/charge")).createChargeMiddleware}catch(r){throw new u("INTERNAL",`paid MCP tools need the optional peer "@lunora/x402" — install it alongside @lunora/mcp to charge for tools (${r instanceof Error?r.message:String(r)})`)}},T={name:"lunora-paid-mcp",version:"0.0.0"},M="tools/call",d=r=>{if(typeof r!="object"||r===null)return;const{method:s,params:a}=r;if(s!==M||typeof a!="object"||a===null)return;const{name:i}=a;return typeof i=="string"?i:void 0},R=()=>Response.json({error:"A JSON-RPC batch may not reference a paid MCP tool; send paid tools/call requests individually."},{status:400}),b=()=>Response.json({error:"The request body could not be parsed as JSON; a priced MCP tool is registered, so the call cannot be gated."},{status:400}),B=r=>{const s=new Map,a=new Map,i=new Map,m=r.serverInfo??T,l=(e,t,o)=>{if(s.has(e.name))throw new u("BAD_REQUEST",`MCP tool "${e.name}" is already registered.`);const n={description:e.description,inputSchema:e.inputSchema,name:e.name};e.annotations!==void 0&&(n.annotations=e.annotations),s.set(e.name,{definition:n,handler:t}),o!==void 0&&a.set(e.name,o)},p=()=>{const e=new v(m,{capabilities:{tools:{}}});return e.setRequestHandler(y,()=>({tools:[...s.values()].map(t=>t.definition)})),e.setRequestHandler(w,async t=>{const o=s.get(t.params.name);return o===void 0?{content:[{text:`unknown tool: ${t.params.name}`,type:"text"}],isError:!0}:await o.handler(t.params.arguments??{})}),e},h=(e,t)=>{let o=i.get(e);if(o===void 0){const n=S().then(async c=>c({...r.charge,price:t},{resource:e})).catch(c=>{throw i.delete(e),c});o=n,i.set(e,n)}return o};return{fetchHandler:async e=>{let t;try{t=await e.clone().json()}catch{t=void 0}const o=()=>g(p(),e,t===void 0?void 0:{parsedBody:t});if(t===void 0&&a.size>0&&e.method==="POST")return b();if(Array.isArray(t))return t.some(f=>a.has(d(f)??""))?R():o();const n=d(t),c=n===void 0?void 0:a.get(n);return n===void 0||c===void 0?o():(await h(n,c)).handle(e,o)},paidTool:(e,t)=>{l(e,t,e.price)},tool:(e,t)=>{l(e,t)}}};export{B as createPaidMcpServer};
@@ -0,0 +1 @@
1
+ import{Server as l}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as d,CallToolRequestSchema as f,ListResourcesRequestSchema as p,ReadResourceRequestSchema as R}from"@modelcontextprotocol/sdk/types.js";const v=(c,u,o)=>{const s=new Map;for(const e of u)s.has(e.definition.name)||s.set(e.definition.name,e);const m=[...s.values()].map(e=>e.definition),r=new l(c,{capabilities:o===void 0?{tools:{}}:{resources:{},tools:{}}});return r.setRequestHandler(d,()=>({tools:m})),r.setRequestHandler(f,async e=>{const{arguments:n,name:t}=e.params,i=s.get(t);if(i===void 0)return{content:[{text:`unknown tool: ${t}`,type:"text"}],isError:!0};try{return await i.handle(n??{})}catch(a){return{content:[{text:a instanceof Error?a.message:String(a),type:"text"}],isError:!0}}}),o!==void 0&&(r.setRequestHandler(p,async()=>({resources:[...await o.list()]})),r.setRequestHandler(R,async e=>{const{uri:n}=e.params,t=await o.read(n);if(t===void 0)throw new Error(`unknown resource: ${n}`);return{contents:[{mimeType:t.mimeType??"text/plain",text:t.text,uri:n}]}})),r};export{v as createToolServer};
@@ -0,0 +1 @@
1
+ import{LunoraError as v}from"@lunora/errors";import{ADMIN_FUNCTIONS as c}from"@lunora/shard-engine";const f=e=>{let t="";for(let s=0;s<e.length;s+=32768)t+=String.fromCharCode(...e.subarray(s,s+32768));return btoa(t)},b=(e,t)=>{if(typeof t=="bigint")return t.toString();if(t instanceof ArrayBuffer)return f(new Uint8Array(t));if(ArrayBuffer.isView(t)){const r=t;return f(new Uint8Array(r.buffer,r.byteOffset,r.byteLength))}return t},N=e=>JSON.parse(JSON.stringify(e,b)),R=e=>({content:[{text:e===void 0?"null":JSON.stringify(e,b,2),type:"text"}]}),u=e=>({...R(e),structuredContent:N(e)}),V=e=>({content:[{text:e,type:"text"}],isError:!0}),d={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},T=50,I=500,w=["1m","5m","15m","1h"],A=["open","resolved","ignored"],E=["trace","debug","log","info","warn","error","fatal"],h={description:"Shard to read from on a .shardBy()-partitioned deployment. Omit for the default (unsharded) shard — these reads are PER-SHARD, not deployment-wide.",type:"string"},y={description:`Maximum rows to return (default ${T.toString()}, clamped to ${I.toString()}).`,type:"number"},U=e=>{const t=typeof e=="number"?e:Number.NaN;return Number.isFinite(t)?Math.max(1,Math.min(Math.floor(t),I)):T},g=(e,t)=>t.includes(e)?e:void 0,_=e=>typeof e=="string"&&e.length>0?e:void 0,P={properties:{level:{description:`Keep only entries at this severity. One of: ${E.join(", ")}.`,type:"string"},limit:y,shardKey:h},type:"object"},L={properties:{functionPathPrefix:{description:'Keep only Issues whose function path starts with this, e.g. "messages:".',type:"string"},limit:y,shardKey:h,status:{description:`Triage status to keep. One of: ${A.join(", ")}. Default: all.`,type:"string"}},type:"object"},M={properties:{limit:y,shardKey:h},type:"object"},k={properties:{limit:y,range:{description:`Time window to report over. One of: ${w.join(", ")}. Default: 15m.`,type:"string"},shardKey:h},type:"object"},H={properties:{shardKey:h},type:"object"},x={properties:{entries:{description:"Recent log entries, NEWEST FIRST: { level, message, timestamp, functionPath?, fields? }.",type:"array"},total:{description:"Entries available before `limit`/`level` narrowed them.",type:"number"}},required:["entries","total"],type:"object"},C={properties:{issues:{description:"Grouped error Issues, newest first: { hash, title, count, status, functionPath, lastSeen, … }.",type:"array"}},required:["issues"],type:"object"},j={properties:{advisories:{description:"Schema/query advisories: { id, level, title, detail, … }.",type:"array"},total:{description:"Advisories available before `limit` narrowed them.",type:"number"}},required:["advisories","total"],type:"object"},q={properties:{buckets:{description:"Combined throughput/latency series across the range.",type:"array"},capped:{description:"True when the deployment's tracked-statement cap was reached, so coverage is partial.",type:"boolean"},entries:{description:"Per-statement activity in the range, hottest first.",type:"array"},total:{description:"Statements available before `limit` narrowed them.",type:"number"},trackedStatements:{description:"Distinct statements the deployment is tracking.",type:"number"}},required:["entries","buckets"],type:"object"},D={properties:{migrations:{description:"Every declared migration with its applied/pending state.",type:"array"}},required:["migrations"],type:"object"},G=[{annotations:{...d,title:"Read recent logs"},description:"Read the deployment's recent log entries (newest first) after running a function, to see what it printed and where it failed. In-memory and per-shard: resets when the shard hibernates.",inputSchema:P,name:"lunora_get_logs",outputSchema:x},{annotations:{...d,title:"List grouped error Issues"},description:"List errors grouped into Issues by fingerprint, with occurrence counts and triage status — the first call when asking what is currently broken, rather than reading raw logs.",inputSchema:L,name:"lunora_get_issues",outputSchema:C},{annotations:{...d,title:"List schema and query advisories"},description:"List the deployment's schema/query advisories (missing indexes, unsafe policies, and similar lints) before or after changing the schema.",inputSchema:M,name:"lunora_get_advisories",outputSchema:j},{annotations:{...d,title:"Read query insights"},description:"Read per-statement execution counts and latency over a recent time window, to find which query is slow or hot before optimizing one.",inputSchema:k,name:"lunora_get_query_insights",outputSchema:q},{annotations:{...d,title:"Read migration status"},description:"Read which migrations have been applied and which are pending, to check whether a schema change has actually landed on the deployment.",inputSchema:H,name:"lunora_get_migration_status",outputSchema:D}],Y=new Set(G.map(e=>e.name)),p=async(e,t,r,s)=>{const a={__lunoraRef:t};return e.query(a,r,{...s===void 0?{}:{shardKey:s}})},l=(e,t)=>{const r=e?.[t];return Array.isArray(r)?r:[]},$=async(e,t,r)=>{const s=_(r.shardKey),a=U(r.limit);switch(t){case"lunora_get_advisories":{const n=await p(e,c.getAdvisories,{},s),i=l(n,"advisories");return u({advisories:i.slice(0,a),total:i.length})}case"lunora_get_issues":{const n=g(r.status,A),i=_(r.functionPathPrefix),o=await p(e,c.getIssues,{limit:a,...n===void 0?{}:{status:n},...i===void 0?{}:{functionPathPrefix:i}},s);return u({issues:l(o,"issues")})}case"lunora_get_logs":{const n=g(r.level,E),i=await p(e,c.getLogs,{},s),o=l(i,"entries").filter(m=>n===void 0||m.level===n);return u({entries:o.slice(0,a),total:o.length})}case"lunora_get_migration_status":{const n=await p(e,c.migrationStatus,{},s);return u({migrations:l(n,"migrations")})}case"lunora_get_query_insights":{const n=g(r.range,w),i=await p(e,c.getQueryInsights,{...n===void 0?{}:{range:n}},s),o=l(i,"entries"),{buckets:m,capped:O,trackedStatements:S}=i??{};return u({buckets:Array.isArray(m)?m:[],capped:O===!0,entries:o.slice(0,a),total:o.length,trackedStatements:typeof S=="number"?S:o.length})}default:throw new v("INTERNAL",`unknown observability tool: ${t}`)}};export{T as D,I as M,G as O,Y as a,$ as c,V as e,R as o};
@@ -0,0 +1 @@
1
+ import{WebStandardStreamableHTTPServerTransport as o}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";const s=async(t,a,n)=>{const e=new o({enableJsonResponse:!0,sessionIdGenerator:void 0});try{return await t.connect(e),await e.handleRequest(a,n)}finally{e.close().catch(()=>{}),t.close().catch(()=>{})}};export{s as serveStateless};
@@ -0,0 +1 @@
1
+ const e=t=>typeof t=="object"&&t!==null,i=t=>t.split("<mark>").join("").split("</mark>").join(""),l=t=>Array.isArray(t)?t.filter(o=>typeof o=="string"):[],p=t=>{if(!e(t)||typeof t.url!="string"||t.url.length===0)return;const o=t,r=typeof o.content=="string"?i(o.content):"",s=l(o.breadcrumbs),n=o.type==="page",c=n?r:s.at(-1)??r;return{...n||r.length===0?{}:{excerpt:r},...s.length>0?{section:s.join(" › ")}:{},title:c.length>0?c:t.url,url:t.url}},u=t=>{const o=[];for(const r of t){const s=p(r);s!==void 0&&o.push(s)}return o};export{u as toDocsSearchHits};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/mcp",
3
- "version": "1.0.0-alpha.70",
3
+ "version": "1.0.0-alpha.71",
4
4
  "description": "Model Context Protocol server exposing a Lunora deployment to AI agents",
5
5
  "keywords": [
6
6
  "ai-agents",
@@ -53,10 +53,10 @@
53
53
  "access": "public"
54
54
  },
55
55
  "dependencies": {
56
- "@lunora/client": "1.0.0-alpha.49",
56
+ "@lunora/client": "1.0.0-alpha.50",
57
57
  "@lunora/errors": "1.0.0-alpha.21",
58
58
  "@lunora/shard-engine": "1.0.0-alpha.27",
59
- "@modelcontextprotocol/sdk": "^1.29.0"
59
+ "@modelcontextprotocol/sdk": "^1.30.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@lunora/x402": ">=1.0.0-alpha.21 <2.0.0-0"
@@ -1 +0,0 @@
1
- const N="agents:agentRun",w="agents:agentThread",S="agents:agentMessages",p="lunora_agent_status",_=new Set(["cancelled","error","idle"]),E=6e4,M=600,k={properties:{prompt:{description:"The task or message for the agent.",type:"string"},threadKey:{description:"Reuse to continue a conversation; omit to start a new thread.",type:"string"},title:{description:"Optional thread title (first run only).",type:"string"}},required:["prompt"],type:"object"},O={properties:{threadKey:{description:"The thread key returned by an agent tool call.",type:"string"}},required:["threadKey"],type:"object"},y=t=>t.toolName??`agent_${t.name}`,I=t=>{if(t===void 0)return[];const n=[];for(const e of t.split(";")){const r=e.trim();if(r.length===0)continue;const a=r.indexOf(":");if(a<=0)continue;const s=r.slice(0,a).trim(),o=r.slice(a+1).trim();s.length===0||o.length===0||n.push({description:o,name:s})}return n},L=(t,n)=>n!==!0||t.length===0?[]:[...t.map(e=>({description:`${e.description} Starts a durable agent run and returns its final answer.`,inputSchema:k,name:y(e)})),{description:"Check the status of a durable agent run (and its answer if finished) by its threadKey.",inputSchema:O,name:p}],P=(t,n)=>t===p||n.some(e=>y(e)===t),q=()=>`mcp-${crypto.randomUUID()}`,c=t=>({__lunoraRef:t}),U=async t=>{await new Promise(n=>{setTimeout(n,t)})},d=t=>({content:[{text:JSON.stringify(t,void 0,2),type:"text"}]}),i=t=>({content:[{text:t,type:"text"}],isError:!0}),l=(t,n)=>{const e=t[n];return typeof e=="string"&&e.length>0?e:void 0},C=t=>{for(let n=t.length-1;n>=0;n-=1){const e=t[n],r=e?.toolCalls,a=Array.isArray(r)&&r.length>0;if(e?.role==="assistant"&&!a)return typeof e.content=="string"?e.content:""}return""},A=t=>t!==null&&typeof t=="object"&&typeof t.status=="string"?t.status:"unknown",v=async(t,n,e,r)=>{const a=await t.query(c(S),{key:n});if(e==="error"){const s=r!==null&&typeof r=="object"?r.error:void 0;return d({error:typeof s=="string"?s:"the agent run failed",status:e,threadKey:n})}return d({status:e,text:C(a),threadKey:n})},R=async(t,n)=>{const e=l(n,"threadKey");if(e===void 0)return i('"threadKey" is required and must be a non-empty string');const r=await t.query(c(w),{key:e}),a=A(r);return _.has(a)?v(t,e,a,r):d({status:a==="unknown"?"running":a,threadKey:e})},$=async(t,n,e,r)=>{try{if(r.allowAgents!==!0)return i(`tool "${n}" is disabled: agent tools are off. Enable them with the LUNORA_MCP_ALLOW_AGENTS env var.`);if(n===p)return await R(t,e);const a=r.exposures.find(u=>y(u)===n);if(a===void 0)return i(`agent tool "${n}" is not exposed by this MCP server`);const s=l(e,"prompt");if(s===void 0)return i('"prompt" is required and must be a non-empty string');const o=l(e,"threadKey")??q(),h=l(e,"title"),{id:T}=await t.mutation(c(N),{agent:a.name,input:s,threadKey:o,...h===void 0?{}:{title:h}}),g=r.pollIntervalMs??M,b=r.maxWaitMs??E,K=r.wait??U,x=Math.max(1,Math.ceil(b/g));for(let u=0;u<x;u+=1){const f=await t.query(c(w),{key:o}),m=A(f);if(_.has(m))return await v(t,o,m,f);await K(g)}return d({hint:"call lunora_agent_status with this threadKey to poll for the answer",runId:T,status:"running",threadKey:o})}catch(a){const s=a instanceof Error?a.message:String(a);return i(s)}};export{k as AGENT_RUN_INPUT_SCHEMA,p as AGENT_STATUS_TOOL_NAME,L as agentToolDefinitions,$ as callAgentTool,C as finalAnswer,P as isAgentToolName,I as parseAgentsEnv};
@@ -1,4 +0,0 @@
1
- import{toDocsSearchHits as h}from"./toDocsSearchHits-C1xXPRPy.mjs";const m="https://lunora.sh",f=1e4,d=t=>t.endsWith("/")?t.slice(0,-1):t,g="\\",p=(t,e,i)=>{for(let s=i;s<t.length;s+=1)if(t[s]===e&&t[s-1]!==g)return s;return-1},u=t=>t.replaceAll(String.raw`\[`,"[").replaceAll(String.raw`\]`,"]").replaceAll(String.raw`\(`,"(").replaceAll(String.raw`\)`,")"),S=t=>{const e=t.trim();if(!e.startsWith("- ["))return;const i=e.lastIndexOf("](");if(i===-1)return;const s=p(e,")",i+2);if(s===-1)return;const a=u(e.slice(3,i).trim()),c=u(e.slice(i+2,s).trim());if(a.length===0||c.length===0)return;const n=e.slice(s+1).trim(),r=n.startsWith(":")?n.slice(1).trim():"";return r.length>0?{description:r,title:a,url:c}:{title:a,url:c}},x=t=>{if(!t.endsWith(")"))return t;const e=t.lastIndexOf(" (");if(e===-1)return t;const i=t.slice(e+2,-1);return i.startsWith("/")||i.startsWith("http")?t.slice(0,e).trim():t},y=(t,e)=>{for(const i of t.split(`
2
- `)){if(i.startsWith("# "))return x(i.slice(2).trim());if(i.trim().length>0)break}return e},w=t=>{if(!t.startsWith("# "))return t;const e=t.indexOf(`
3
- `);return e===-1?"":t.slice(e+1).trimStart()},A=(t={})=>{const e=d(t.baseUrl??m),i=t.fetch??globalThis.fetch,s=t.timeoutMs??f,a=async n=>{try{const r=await i(`${e}${n}`,{headers:{accept:"text/plain, application/json"},signal:AbortSignal.timeout(s)});return r.ok?{body:await r.text()}:{missing:!0}}catch(r){return{unreachable:r instanceof Error?r.message:String(r)}}},c=(n,r)=>{if("unreachable"in n)throw new Error(`could not reach the documentation site at ${e}${r}: ${n.unreachable}`);return"missing"in n?void 0:n.body};return{getPage:async n=>{const r=c(await a(`/llms.mdx${n}`),`/llms.mdx${n}`);if(!(r===void 0||r.trim().length===0))return{content:w(r),title:y(r,n),url:n}},listPages:async()=>{const n=c(await a("/llms.txt"),"/llms.txt");if(n===void 0)return[];const r=[];for(const o of n.split(`
4
- `)){const l=S(o);l!==void 0&&r.push(l)}return r},search:async n=>{const r=`/api/search?query=${encodeURIComponent(n)}`,o=c(await a(r),r);if(o===void 0)return[];let l;try{l=JSON.parse(o)}catch{return[]}return Array.isArray(l)?h(l):[]}}};export{m as DEFAULT_DOCS_BASE_URL,f as DEFAULT_REQUEST_TIMEOUT_MS,A as createRemoteDocsIndex,S as parseIndexLine};
@@ -1 +0,0 @@
1
- import{createToolServer as d}from"./createToolServer-CP5bNUcS.mjs";import{serveStateless as c}from"./serveStateless-BqoRk-xU.mjs";import{docsResources as i}from"./DOCS_URI_SCHEME-DbyotZvf.mjs";import{docsTools as p}from"./DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";const u="lunora-docs",m=128*1024,y=e=>({name:u,version:e??"0.0.0"}),S=e=>d(y(e.version),p(e.index),i(e.index)),l=e=>new TextEncoder().encode(e).length,n=(e,r,s)=>Response.json({error:{code:r,message:s},id:null,jsonrpc:"2.0"},{status:e}),v=async(e,r)=>{if(e.method!=="POST")return{parsedBody:void 0};const s={response:n(413,-32600,`request body exceeds ${String(r)} bytes`)},o=Number(e.headers.get("content-length"));if(Number.isFinite(o)&&o>r)return s;const a=await e.text();if(l(a)>r)return s;let t;try{t=JSON.parse(a)}catch{return{response:n(400,-32700,"parse error: body is not valid JSON")}}return Array.isArray(t)?{response:n(400,-32600,"batched requests are not supported: send one JSON-RPC message per request")}:{parsedBody:t}},B=e=>{const r=e.maxRequestBytes??m;return async s=>{const o=await v(s,r);return"response"in o?o.response:c(S(e),s,o.parsedBody===void 0?void 0:{parsedBody:o.parsedBody})}};export{m as DEFAULT_MAX_REQUEST_BYTES,u as DOCS_SERVER_NAME,B as createDocsMcpFetchHandler,S as createDocsMcpServer};
@@ -1,3 +0,0 @@
1
- const s="lunora-docs:",r=t=>`${s}${t}`,a=t=>t.startsWith(s)?t.slice(s.length):void 0,n=t=>({list:async()=>(await t.listPages()).map(i=>({...i.description===void 0?{}:{description:i.description},mimeType:"text/markdown",name:i.title,uri:r(i.url)})),read:async i=>{const e=a(i);if(e===void 0)return;const o=await t.getPage(e);return o===void 0?void 0:{mimeType:"text/markdown",text:`# ${o.title} (${o.url})
2
-
3
- ${o.content}`}}});export{s as DOCS_URI_SCHEME,n as docsResources,a as fromDocsUri,r as toDocsUri};
@@ -1 +0,0 @@
1
- import{LunoraClient as u}from"@lunora/client";import{StdioServerTransport as f}from"@modelcontextprotocol/sdk/server/stdio.js";import{createToolServer as m}from"./createToolServer-CP5bNUcS.mjs";import{createRemoteDocsIndex as v}from"./DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs";import{docsResources as h}from"./DOCS_URI_SCHEME-DbyotZvf.mjs";import{docsTools as y}from"./DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";import{toolDefinitions as O,callTool as R}from"./READ_ONLY_TOOL_DEFINITIONS-BygXkni2.mjs";const E=(t,n)=>{if(t.size<n)return;const o=t.keys().next().value;o!==void 0&&t.delete(o)},l=t=>t.docs===!1?void 0:v({...t.docs?.baseUrl===void 0?{}:{baseUrl:t.docs.baseUrl},...t.fetch===void 0?{}:{fetch:t.fetch}}),_="lunora",g="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).",w=8,d=t=>{const n=new Map;return o=>{const e=JSON.stringify([o.url,o.token??""]),i=n.get(e);if(i!==void 0)return i;const r=new u({fetch:t,url:o.url});return o.token!==void 0&&o.token.length>0&&r.setAuthToken(o.token),E(n,w),n.set(e,r),r}},a=t=>t?.token!==void 0&&t.token.length>0,P=(t,n,o)=>{const e=typeof t=="function"?t:()=>t;return O(n,a(e())).map(i=>({definition:i,handle:async r=>{const s=e();return s===void 0?{content:[{text:g,type:"text"}],isError:!0}:R(o(s),i.name,r,n,a(s))}}))},S="lunora-spec:openrpc",T="lunora-spec:openapi",c=[{description:"The deployment's generated OpenRPC 1.x document — every RPC function's path, kind, and argument schema in one read, instead of list_functions plus one get_function_schema call per function.",fetch:async t=>t.fetchOpenRpc(),name:"OpenRPC specification",uri:S},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async t=>t.fetchOpenApi(),name:"OpenAPI specification",uri:T}],k=(t,n)=>{const o=typeof t=="function"?t:()=>t,e=async i=>{const r=o();if(r!==void 0)try{return await i.fetch(n(r))}catch{return}};return{list:async()=>(await Promise.all(c.map(async i=>await e(i)===void 0?void 0:{description:i.description,mimeType:"application/json",name:i.name,uri:i.uri}))).filter(i=>i!==void 0),read:async i=>{const r=c.find(p=>p.uri===i);if(r===void 0)return;const s=await e(r);return s===void 0?void 0:{mimeType:"application/json",text:JSON.stringify(s,void 0,2)}}}},A=t=>({list:async()=>(await Promise.all(t.map(async n=>n.list()))).flat(),read:async n=>{for(const o of t){const e=await o.read(n);if(e!==void 0)return e}}}),x=(t,n)=>{const o=[],e=l(t);return e!==void 0&&o.push(...y(e)),o.push(...t.extraTools??[]),t.deployment!==void 0&&o.push(...P(t.deployment,t.allowWrites??!1,n??d(t.fetch))),o},C=(t={})=>{const n=l(t),o=[];n!==void 0&&o.push(h(n));const e=d(t.fetch);return t.deployment!==void 0&&o.push(k(t.deployment,e)),m({name:_,version:t.version??"0.0.0"},x(t,e),o.length===0?void 0:A(o))},b=async(t={})=>{const n=C(t);return await n.connect(new f),n};export{_ as LOCAL_SERVER_NAME,g as NO_DEPLOYMENT_MESSAGE,T as OPENAPI_RESOURCE_URI,S as OPENRPC_RESOURCE_URI,b as connectLocalStdio,C as createLocalMcpServer,x as localTools};
@@ -1 +0,0 @@
1
- import"@lunora/errors";import"@lunora/shard-engine";import{S as L,a as o,A as s,q as A,D as _}from"./observability-tools-GVGcK_kZ.mjs";export{L as DEFAULT_LIMIT,o as MAX_LIMIT,s as OBSERVABILITY_TOOL_DEFINITIONS,A as OBSERVABILITY_TOOL_NAMES,_ as callObservabilityTool};
@@ -1 +0,0 @@
1
- import{LunoraError as u}from"@lunora/errors";import{A as E,f as l,q as N,D as R,u as o}from"./observability-tools-GVGcK_kZ.mjs";const y={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"},g={properties:{},type:"object"},v={properties:{functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"}},required:["functionPath"],type:"object"},d={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},A=[{annotations:{...d,title:"List deployment functions"},description:"List the deployment's public functions (queries, mutations, actions) with their kinds.",inputSchema:g,name:"lunora_list_functions"},{annotations:{...d,title:"List global tables"},description:"List the deployment's .global() tables and their column shapes.",inputSchema:g,name:"lunora_list_tables"},{annotations:{...d,title:"Describe a function's arguments"},description:"Return a function's argument JSON Schema and kind, so a caller can construct a valid arguments object. Call lunora_list_functions first to discover available function paths.",inputSchema:v,name:"lunora_get_function_schema"},{annotations:{...d,title:"Run a query"},description:"Run a query and return its result. Read-only.",inputSchema:y,name:"lunora_run_query"}],O=[{annotations:{destructiveHint:!0,idempotentHint:!1,openWorldHint:!0,readOnlyHint:!1,title:"Run a mutation (writes data)"},description:"Run a mutation and return its result. Writes data — use with care.",inputSchema:y,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 and return its result. May call external services.",inputSchema:y,name:"lunora_run_action"}],T=new Set(O.map(t=>t.name)),$=(t,e=!1)=>[...A,...e===!0?E:[],...t===!0?O:[]],S=t=>{const{functionPath:e}=t;if(typeof e!="string"||e.length===0)throw new u("INTERNAL",'"functionPath" is required and must be a non-empty string');return e},w=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),b=t=>Array.isArray(t)?"an array":`a ${typeof t}`,D=t=>{if(t==null)return{};if(typeof t=="string"){let e;try{e=JSON.parse(t)}catch{throw new u("BAD_REQUEST",'"args" must be a JSON object; received a string that is not valid JSON')}if(!w(e))throw new u("BAD_REQUEST",`"args" must be a JSON object; the provided string decoded to ${b(e)}`);return e}if(!w(t))throw new u("BAD_REQUEST",`"args" must be a JSON object, got ${b(t)}`);return t},p=t=>{const e=S(t),a=D(t.args),i=typeof t.shardKey=="string"&&t.shardKey.length>0?t.shardKey:void 0;return{args:a,functionPath:e,shardKey:i}},f=t=>({__lunoraRef:t}),L=3e4,h=new WeakMap,_=t=>{const e=Date.now(),a=h.get(t);if(a!==void 0&&a.expiresAt>e)return a.promise;const i=t.listFunctions().catch(c=>{throw h.get(t)?.promise===i&&h.delete(t),c});return h.set(t,{expiresAt:e+L,promise:i}),i},m=async(t,e,a)=>{const i=(await _(t)).find(c=>c.path===e);if(i===void 0)throw new u("NOT_FOUND",`function not found or not public: ${e}`);if(i.kind!==a)throw new u("BAD_REQUEST",`function ${e} is a ${i.kind}, not a ${a}`)},k=async(t,e,a,i=!1,c=!1)=>{try{if(i!==!0&&T.has(e))return l(`tool "${e}" is disabled: this MCP server is read-only. Enable writes with the LUNORA_MCP_ALLOW_WRITES env var.`);if(N.has(e))return c!==!0?l(`tool "${e}" is unavailable: it reads the deployment's logs and errors, which needs an admin token. Set LUNORA_ADMIN_TOKEN (or pass --token) and reconnect.`):await R(t,e,a);switch(e){case"lunora_get_function_schema":{const r=S(a),n=(await _(t)).find(s=>s.path===r);return n===void 0?l(`function not found: ${r}`):o({args:n.args??[],kind:n.kind,path:n.path})}case"lunora_list_functions":return o(await _(t));case"lunora_list_tables":return o(await t.listGlobalTables());case"lunora_run_action":{const{args:r,functionPath:n,shardKey:s}=p(a);return await m(t,n,"action"),o(await t.action(f(n),r,{shardKey:s}))}case"lunora_run_mutation":{const{args:r,functionPath:n,shardKey:s}=p(a);return await m(t,n,"mutation"),o(await t.mutation(f(n),r,{shardKey:s}))}case"lunora_run_query":{const{args:r,functionPath:n,shardKey:s}=p(a);return await m(t,n,"query"),o(await t.query(f(n),r,{shardKey:s}))}default:return l(`unknown tool: ${e}`)}}catch(r){const n=r instanceof Error?r.message:String(r);return l(n)}};export{E as OBSERVABILITY_TOOL_DEFINITIONS,A as READ_ONLY_TOOL_DEFINITIONS,O as WRITE_TOOL_DEFINITIONS,k as callTool,$ as toolDefinitions};
@@ -1 +0,0 @@
1
- import{readFileSync as f}from"node:fs";import{dirname as c,join as p}from"node:path";import{fileURLToPath as v}from"node:url";import{LunoraClient as g}from"@lunora/client";import{LunoraError as h}from"@lunora/errors";import{Server as d}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as w}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as M,CallToolRequestSchema as S}from"@modelcontextprotocol/sdk/types.js";import{agentToolDefinitions as T,isAgentToolName as k,callAgentTool as y}from"./AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{toolDefinitions as L,callTool as x}from"./READ_ONLY_TOOL_DEFINITIONS-BygXkni2.mjs";const A=()=>{try{let t=c(v(import.meta.url));for(let r=0;r<8;r+=1){try{const n=f(p(t,"package.json"),"utf8"),o=JSON.parse(n);if(o.name==="@lunora/mcp"&&typeof o.version=="string"&&o.version.length>0)return o.version}catch{}const e=c(t);if(e===t)break;t=e}}catch{}return"0.0.0"},R={name:"lunora",version:A()},q=t=>{if(t.client!==void 0)return t.client;if(t.url===void 0)throw new h("INTERNAL","createLunoraMcpServer requires either a `client` or a `url`");const r=new g({fetch:t.fetch,url:t.url});return t.token!==void 0&&r.setAuthToken(t.token),r},W=t=>{const r=q(t),e=t.allowWrites??!1,n=t.allowAgents??!1,o=t.agents??[],i=typeof t.token=="string"&&t.token.length>0,a=new d(R,{capabilities:{tools:{}}});return a.setRequestHandler(M,()=>({tools:[...L(e,i),...T(o,n)]})),a.setRequestHandler(S,async m=>{const{arguments:u,name:s}=m.params,l=u??{};return k(s,o)?await y(r,s,l,{allowAgents:n,exposures:o,...t.agentMaxWaitMs===void 0?{}:{maxWaitMs:t.agentMaxWaitMs},...t.agentPollIntervalMs===void 0?{}:{pollIntervalMs:t.agentPollIntervalMs}}):await x(r,s,l,e,i)}),a},O=async t=>{const r=W(t);return await r.connect(new w),r};export{O as connectStdio,W as createLunoraMcpServer};
@@ -1 +0,0 @@
1
- import{serveStateless as s}from"./serveStateless-BqoRk-xU.mjs";import{createLunoraMcpServer as t}from"./connectStdio-nqnOab_d.mjs";const c=e=>r=>s(t(e),r);export{c as createMcpFetchHandler,s as serveStateless};
@@ -1 +0,0 @@
1
- import{LunoraError as p}from"@lunora/errors";import{Server as f}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as y,CallToolRequestSchema as g}from"@modelcontextprotocol/sdk/types.js";import{serveStateless as w}from"./serveStateless-BqoRk-xU.mjs";const S=async()=>{try{return(await import("@lunora/x402/charge")).createChargeMiddleware}catch(a){throw new p("INTERNAL",`paid MCP tools need the optional peer "@lunora/x402" — install it alongside @lunora/mcp to charge for tools (${a instanceof Error?a.message:String(a)})`)}},M={name:"lunora-paid-mcp",version:"0.0.0"},R="tools/call",d=a=>{if(typeof a!="object"||a===null)return;const{method:s,params:n}=a;if(s!==R||typeof n!="object"||n===null)return;const{name:i}=n;return typeof i=="string"?i:void 0},C=()=>Response.json({error:"A JSON-RPC batch may not reference a paid MCP tool; send paid tools/call requests individually."},{status:400}),P=()=>Response.json({error:"The request body could not be parsed as JSON; a priced MCP tool is registered, so the call cannot be gated."},{status:400}),j=a=>{const s=new Map,n=new Map,i=new Map,m=a.serverInfo??M,l=(e,t,o)=>{if(s.has(e.name))throw new p("BAD_REQUEST",`MCP tool "${e.name}" is already registered.`);const r={description:e.description,inputSchema:e.inputSchema,name:e.name};e.annotations!==void 0&&(r.annotations=e.annotations),s.set(e.name,{definition:r,handler:t}),o!==void 0&&n.set(e.name,o)},u=()=>{const e=new f(m,{capabilities:{tools:{}}});return e.setRequestHandler(y,()=>({tools:[...s.values()].map(t=>t.definition)})),e.setRequestHandler(g,async t=>{const o=s.get(t.params.name);return o===void 0?{content:[{text:`unknown tool: ${t.params.name}`,type:"text"}],isError:!0}:await o.handler(t.params.arguments??{})}),e},h=(e,t)=>{let o=i.get(e);if(o===void 0){const r=S().then(async c=>c({...a.charge,price:t},{resource:e})).catch(c=>{throw i.delete(e),c});o=r,i.set(e,r)}return o};return{fetchHandler:async e=>{let t;try{t=await e.clone().json()}catch{t=void 0}const o=()=>w(u(),e,t===void 0?void 0:{parsedBody:t});if(t===void 0&&n.size>0&&e.method==="POST")return P();if(Array.isArray(t))return t.some(v=>n.has(d(v)??""))?C():o();const r=d(t),c=r===void 0?void 0:n.get(r);return r===void 0||c===void 0?o():(await h(r,c)).handle(e,o)},paidTool:(e,t)=>{l(e,t,e.price)},tool:(e,t)=>{l(e,t)}}};export{j as createPaidMcpServer};
@@ -1 +0,0 @@
1
- import{Server as l}from"@modelcontextprotocol/sdk/server/index.js";import{ListToolsRequestSchema as d,CallToolRequestSchema as p,ListResourcesRequestSchema as R,ReadResourceRequestSchema as f}from"@modelcontextprotocol/sdk/types.js";const h=(c,u,s)=>{const n=new Map;for(const e of u)n.has(e.definition.name)||n.set(e.definition.name,e);const m=[...n.values()].map(e=>e.definition),r=new l(c,{capabilities:s===void 0?{tools:{}}:{resources:{},tools:{}}});return r.setRequestHandler(d,()=>({tools:m})),r.setRequestHandler(p,async e=>{const{arguments:o,name:t}=e.params,i=n.get(t);if(i===void 0)return{content:[{text:`unknown tool: ${t}`,type:"text"}],isError:!0};try{return await i.handle(o??{})}catch(a){return{content:[{text:a instanceof Error?a.message:String(a),type:"text"}],isError:!0}}}),s!==void 0&&(r.setRequestHandler(R,async()=>({resources:[...await s.list()]})),r.setRequestHandler(f,async e=>{const{uri:o}=e.params,t=await s.read(o);if(t===void 0)throw new Error(`unknown resource: ${o}`);return{contents:[{mimeType:t.mimeType??"text/plain",text:t.text,uri:o}]}})),r};export{h as createToolServer};
@@ -1 +0,0 @@
1
- import{LunoraError as N}from"@lunora/errors";import{ADMIN_FUNCTIONS as u}from"@lunora/shard-engine";const b=e=>{let t="";for(let r=0;r<e.length;r+=32768)t+=String.fromCharCode(...e.subarray(r,r+32768));return btoa(t)},v=(e,t)=>{if(typeof t=="bigint")return t.toString();if(t instanceof ArrayBuffer)return b(new Uint8Array(t));if(ArrayBuffer.isView(t)){const r=t;return b(new Uint8Array(r.buffer,r.byteOffset,r.byteLength))}return t},R=e=>JSON.parse(JSON.stringify(e,v)),x=e=>({content:[{text:e===void 0?"null":JSON.stringify(e,v,2),type:"text"}]}),p=e=>({...x(e),structuredContent:R(e)}),F=e=>({content:[{text:e,type:"text"}],isError:!0}),d={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},S=50,_=500,k=["1m","5m","15m","1h"],j=["open","resolved","ignored"],q=["trace","debug","log","info","warn","error","fatal"],h={description:"Shard to read from on a .shardBy()-partitioned deployment. Omit for the default (unsharded) shard — these reads are PER-SHARD, not deployment-wide.",type:"string"},y={description:`Maximum rows to return (default ${S.toString()}, clamped to ${_.toString()}).`,type:"number"},I=e=>{const t=typeof e=="number"?e:Number.NaN;return Number.isFinite(t)?Math.max(1,Math.min(Math.floor(t),_)):S},g=(e,t)=>t.includes(e)?e:void 0,w=e=>typeof e=="string"&&e.length>0?e:void 0,O={properties:{level:{description:`Keep only entries at this severity. One of: ${q.join(", ")}.`,type:"string"},limit:y,shardKey:h},type:"object"},P={properties:{functionPathPrefix:{description:'Keep only Issues whose function path starts with this, e.g. "messages:".',type:"string"},limit:y,shardKey:h,status:{description:`Triage status to keep. One of: ${j.join(", ")}. Default: all.`,type:"string"}},type:"object"},E={properties:{limit:y,shardKey:h},type:"object"},K={properties:{limit:y,range:{description:`Time window to report over. One of: ${k.join(", ")}. Default: 15m.`,type:"string"},shardKey:h},type:"object"},L={properties:{shardKey:h},type:"object"},T={properties:{entries:{description:"Recent log entries, NEWEST FIRST: { level, message, timestamp, functionPath?, fields? }.",type:"array"},total:{description:"Entries available before `limit`/`level` narrowed them.",type:"number"}},required:["entries","total"],type:"object"},$={properties:{issues:{description:"Grouped error Issues, newest first: { hash, title, count, status, functionPath, lastSeen, … }.",type:"array"}},required:["issues"],type:"object"},C={properties:{advisories:{description:"Schema/query advisories: { id, level, title, detail, … }.",type:"array"},total:{description:"Advisories available before `limit` narrowed them.",type:"number"}},required:["advisories","total"],type:"object"},D={properties:{buckets:{description:"Combined throughput/latency series across the range.",type:"array"},capped:{description:"True when the deployment's tracked-statement cap was reached, so coverage is partial.",type:"boolean"},entries:{description:"Per-statement activity in the range, hottest first.",type:"array"},total:{description:"Statements available before `limit` narrowed them.",type:"number"},trackedStatements:{description:"Distinct statements the deployment is tracking.",type:"number"}},required:["entries","buckets"],type:"object"},H={properties:{migrations:{description:"Every declared migration with its applied/pending state.",type:"array"}},required:["migrations"],type:"object"},M=[{annotations:{...d,title:"Read recent logs"},description:"Read the deployment's recent log entries (newest first) after running a function, to see what it printed and where it failed. In-memory and per-shard: resets when the shard hibernates.",inputSchema:O,name:"lunora_get_logs",outputSchema:T},{annotations:{...d,title:"List grouped error Issues"},description:"List errors grouped into Issues by fingerprint, with occurrence counts and triage status — the first call when asking what is currently broken, rather than reading raw logs.",inputSchema:P,name:"lunora_get_issues",outputSchema:$},{annotations:{...d,title:"List schema and query advisories"},description:"List the deployment's schema/query advisories (missing indexes, unsafe policies, and similar lints) before or after changing the schema.",inputSchema:E,name:"lunora_get_advisories",outputSchema:C},{annotations:{...d,title:"Read query insights"},description:"Read per-statement execution counts and latency over a recent time window, to find which query is slow or hot before optimizing one.",inputSchema:K,name:"lunora_get_query_insights",outputSchema:D},{annotations:{...d,title:"Read migration status"},description:"Read which migrations have been applied and which are pending, to check whether a schema change has actually landed on the deployment.",inputSchema:L,name:"lunora_get_migration_status",outputSchema:H}],J=new Set(M.map(e=>e.name)),c=async(e,t,r,s)=>{const o={__lunoraRef:t};return e.query(o,r,{...s===void 0?{}:{shardKey:s}})},l=(e,t)=>{const r=e?.[t];return Array.isArray(r)?r:[]},W=async(e,t,r)=>{const s=w(r.shardKey),o=I(r.limit);switch(t){case"lunora_get_advisories":{const i=await c(e,u.getAdvisories,{},s),n=l(i,"advisories");return p({advisories:n.slice(0,o),total:n.length})}case"lunora_get_issues":{const i=g(r.status,j),n=w(r.functionPathPrefix),a=await c(e,u.getIssues,{limit:o,...i===void 0?{}:{status:i},...n===void 0?{}:{functionPathPrefix:n}},s);return p({issues:l(a,"issues")})}case"lunora_get_logs":{const i=g(r.level,q),n=await c(e,u.getLogs,{},s),a=l(n,"entries").filter(m=>i===void 0||m.level===i);return p({entries:a.slice(0,o),total:a.length})}case"lunora_get_migration_status":{const i=await c(e,u.migrationStatus,{},s);return p({migrations:l(i,"migrations")})}case"lunora_get_query_insights":{const i=g(r.range,k),n=await c(e,u.getQueryInsights,{...i===void 0?{}:{range:i}},s),a=l(n,"entries"),{buckets:m,capped:A,trackedStatements:f}=n??{};return p({buckets:Array.isArray(m)?m:[],capped:A===!0,entries:a.slice(0,o),total:a.length,trackedStatements:typeof f=="number"?f:a.length})}default:throw new N("INTERNAL",`unknown observability tool: ${t}`)}};export{M as A,W as D,S,_ as a,F as f,J as q,x as u};
@@ -1 +0,0 @@
1
- import{WebStandardStreamableHTTPServerTransport as n}from"@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js";const o=async(a,s,t)=>{const e=new n({enableJsonResponse:!0,sessionIdGenerator:void 0});try{return await a.connect(e),await e.handleRequest(s,t)}finally{e.close().catch(()=>{}),a.close().catch(()=>{})}};export{o as serveStateless};
@@ -1 +0,0 @@
1
- const i=r=>typeof r=="object"&&r!==null,l=r=>r.split("<mark>").join("").split("</mark>").join(""),c=r=>Array.isArray(r)?r.filter(t=>typeof t=="string"):[],u=r=>{if(!i(r)||typeof r.url!="string"||r.url.length===0)return;const t=r,n=typeof t.content=="string"?l(t.content):"",e=c(t.breadcrumbs),o=t.type==="page",s=o?n:e.at(-1)??n;return{...o||n.length===0?{}:{excerpt:n},...e.length>0?{section:e.join(" › ")}:{},title:s.length>0?s:r.url,url:r.url}},p=r=>{const t=[];for(const n of r){const e=u(n);e!==void 0&&t.push(e)}return t};export{p as toDocsSearchHits};