@lunora/mcp 1.0.0-alpha.60 → 1.0.0-alpha.61
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -10
- package/dist/bin.mjs +1 -1
- package/dist/docs/index.d.mts +2 -2
- package/dist/docs/index.d.ts +2 -2
- package/dist/index.d.mts +30 -11
- package/dist/index.d.ts +30 -11
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/LOCAL_SERVER_NAME-BFbVWtCm.mjs +1 -0
- package/dist/packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-DwJpdhPe.mjs +1 -0
- package/dist/packem_shared/READ_ONLY_TOOL_DEFINITIONS-BygXkni2.mjs +1 -0
- package/dist/packem_shared/connectStdio-nqnOab_d.mjs +1 -0
- package/dist/packem_shared/createMcpFetchHandler-Cz_tRkpm.mjs +1 -0
- package/dist/packem_shared/observability-tools-GVGcK_kZ.mjs +1 -0
- package/dist/packem_shared/{serve-stateless.d-DX0di_lv.d.mts → serve-stateless.d-B_q8q39X.d.mts} +14 -0
- package/dist/packem_shared/{serve-stateless.d-DX0di_lv.d.ts → serve-stateless.d-B_q8q39X.d.ts} +14 -0
- package/package.json +2 -1
- package/dist/packem_shared/LOCAL_SERVER_NAME-BoQv1iu8.mjs +0 -1
- package/dist/packem_shared/READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs +0 -1
- package/dist/packem_shared/connectStdio-Dt-DqEgA.mjs +0 -1
- package/dist/packem_shared/createMcpFetchHandler-DjvXAX80.mjs +0 -1
package/README.md
CHANGED
|
@@ -45,16 +45,21 @@ Part of the [Lunora](https://github.com/anolilab/lunora) framework — a type-sa
|
|
|
45
45
|
|
|
46
46
|
## Tools
|
|
47
47
|
|
|
48
|
-
| Tool
|
|
49
|
-
|
|
|
50
|
-
| `lunora_list_functions`
|
|
51
|
-
| `lunora_list_tables`
|
|
52
|
-
| `lunora_get_function_schema`
|
|
53
|
-
| `lunora_run_query`
|
|
54
|
-
| `lunora_run_mutation`
|
|
55
|
-
| `lunora_run_action`
|
|
56
|
-
| `
|
|
57
|
-
| `
|
|
48
|
+
| Tool | Description |
|
|
49
|
+
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `lunora_list_functions` | List the deployment's public functions (queries, mutations, actions) with their kinds. |
|
|
51
|
+
| `lunora_list_tables` | List the deployment's `.global()` tables with their row counts. |
|
|
52
|
+
| `lunora_get_function_schema` | Return a function's argument descriptors and kind by path, so a caller can construct a valid arguments object. |
|
|
53
|
+
| `lunora_run_query` | Run a query and return its result. Read-only. |
|
|
54
|
+
| `lunora_run_mutation` | Run a mutation and return its result. Writes data — use with care. |
|
|
55
|
+
| `lunora_run_action` | Run an action and return its result. May call external services. |
|
|
56
|
+
| `lunora_get_logs` | Read the deployment's recent log entries (newest first). Requires an admin token. |
|
|
57
|
+
| `lunora_get_issues` | List errors grouped into Issues by fingerprint, with counts and triage status. Requires an admin token. |
|
|
58
|
+
| `lunora_get_advisories` | List the deployment's schema/query advisories. Requires an admin token. |
|
|
59
|
+
| `lunora_get_query_insights` | Per-statement execution counts and latency over a recent window. Requires an admin token. |
|
|
60
|
+
| `lunora_get_migration_status` | Which migrations are applied and which are pending. Requires an admin token. |
|
|
61
|
+
| `agent_<name>` | Start a durable [`@lunora/agent`](https://www.npmjs.com/package/@lunora/agent) run and await its answer. One tool per exposed agent. Requires agents enabled. |
|
|
62
|
+
| `lunora_agent_status` | Poll a running agent by `threadKey` and return its answer once finished. Requires agents enabled. |
|
|
58
63
|
|
|
59
64
|
### Recommended agent flow
|
|
60
65
|
|
|
@@ -65,6 +70,25 @@ Part of the [Lunora](https://github.com/anolilab/lunora) framework — a type-sa
|
|
|
65
70
|
→ call the function with a well-formed arguments object
|
|
66
71
|
```
|
|
67
72
|
|
|
73
|
+
### Observability tools (privileged)
|
|
74
|
+
|
|
75
|
+
The five `lunora_get_*` observability tools are read-only, but they surface the
|
|
76
|
+
deployment's **operational data** — log lines, request metadata, and grouped
|
|
77
|
+
error messages, all of which may contain user data, and all of which land in the
|
|
78
|
+
model's context (and therefore at its provider). They are exposed **only when an
|
|
79
|
+
admin token resolved**: without one they are omitted from `ListTools` entirely
|
|
80
|
+
and refused at dispatch, the same omit-don't-refuse rule the write tools use.
|
|
81
|
+
They are independent of `--allow-writes`, which is about changing data, not
|
|
82
|
+
reading operational data.
|
|
83
|
+
|
|
84
|
+
They return `structuredContent` alongside the usual text block, described by each
|
|
85
|
+
tool's `outputSchema` (MCP revision `2025-06-18` and later; older clients keep
|
|
86
|
+
reading the text block). All but `lunora_get_migration_status` take a `limit`
|
|
87
|
+
clamped server-side; migration status takes only `shardKey` and returns every
|
|
88
|
+
migration, because truncating that list would hide the pending one. Each also
|
|
89
|
+
takes an optional `shardKey` — on a `.shardBy()`-partitioned deployment these
|
|
90
|
+
reads are **per-shard**, not deployment-wide.
|
|
91
|
+
|
|
68
92
|
`lunora_get_function_schema` returns a JSON object with three fields:
|
|
69
93
|
|
|
70
94
|
- `path` — the function path (e.g. `"messages:send"`)
|
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-
|
|
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
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
4
|
`),new a(`failed to start — ${_}`,1)}};try{await l(process.env)}catch(r){process.exit(r instanceof a?r.code:1)}
|
package/dist/docs/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as McpResourceProvider, a as McpFetchHandler, T as ToolDefinition, b as McpTool } from "../packem_shared/serve-stateless.d-
|
|
2
|
-
export type { c as McpResourceSummary, d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-
|
|
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";
|
|
3
3
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
4
|
import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
5
5
|
/**
|
package/dist/docs/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { M as McpResourceProvider, a as McpFetchHandler, T as ToolDefinition, b as McpTool } from "../packem_shared/serve-stateless.d-
|
|
2
|
-
export type { c as McpResourceSummary, d as McpServerInfo, e as ToolInputSchema, f as ToolResult } from "../packem_shared/serve-stateless.d-
|
|
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";
|
|
3
3
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
4
|
import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
5
5
|
/**
|
package/dist/index.d.mts
CHANGED
|
@@ -1,29 +1,44 @@
|
|
|
1
1
|
import { LunoraClient } from '@lunora/client';
|
|
2
|
-
import { T as ToolDefinition, f as ToolResult, e as ToolInputSchema, a as McpFetchHandler, b as McpTool } from "./packem_shared/serve-stateless.d-
|
|
3
|
-
export { type d as McpServerInfo, g as createToolServer, s as serveStateless } from "./packem_shared/serve-stateless.d-
|
|
2
|
+
import { T as ToolDefinition, f as ToolResult, e as ToolInputSchema, a as McpFetchHandler, b as McpTool } from "./packem_shared/serve-stateless.d-B_q8q39X.mjs";
|
|
3
|
+
export { type d as McpServerInfo, g as createToolServer, s as serveStateless } from "./packem_shared/serve-stateless.d-B_q8q39X.mjs";
|
|
4
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
5
|
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
7
|
+
/**
|
|
8
|
+
* The observability tools. Descriptions say WHEN to call the tool, not just
|
|
9
|
+
* what it returns — an agent picking between five similar reads needs the
|
|
10
|
+
* trigger, and it pays for these strings on every turn.
|
|
11
|
+
*/
|
|
12
|
+
declare const OBSERVABILITY_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
7
13
|
/** The read-only tool surface: introspection + query. Always exposed. */
|
|
8
14
|
declare const READ_ONLY_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
9
15
|
/** The write tool surface (mutations + actions). Exposed ONLY when writes are enabled. */
|
|
10
16
|
declare const WRITE_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
11
17
|
/**
|
|
12
|
-
* The tools this server advertises
|
|
13
|
-
*
|
|
14
|
-
*
|
|
18
|
+
* The tools this server advertises, in three tiers:
|
|
19
|
+
*
|
|
20
|
+
* - the read-only surface, always exposed;
|
|
21
|
+
* - the observability surface, exposed only when an admin token resolved —
|
|
22
|
+
* read-only, but it surfaces production logs and grouped errors, so an
|
|
23
|
+
* unauthenticated server must not even advertise that it exists;
|
|
24
|
+
* - the write surface, exposed only when `allowWrites` is set.
|
|
25
|
+
*
|
|
26
|
+
* Both gates OMIT rather than refuse: an AI agent can't invoke what it can't
|
|
27
|
+
* see. Dispatch re-checks both in {@link callTool}, so the guarantee does not
|
|
28
|
+
* depend on a client honouring the advertised list.
|
|
15
29
|
*/
|
|
16
|
-
declare const toolDefinitions: (allowWrites: boolean) => ReadonlyArray<ToolDefinition>;
|
|
30
|
+
declare const toolDefinitions: (allowWrites: boolean, hasAdminToken?: boolean) => ReadonlyArray<ToolDefinition>;
|
|
17
31
|
/**
|
|
18
32
|
* Dispatch a tool call against `client`. Unknown tools and thrown errors are
|
|
19
33
|
* returned as `isError` results (rather than rejections) so the calling model
|
|
20
34
|
* sees the failure as tool output, per the MCP convention.
|
|
21
35
|
*
|
|
22
|
-
* `allowWrites` gates the mutation/action tools
|
|
23
|
-
*
|
|
24
|
-
*
|
|
36
|
+
* `allowWrites` gates the mutation/action tools and `hasAdminToken` gates the
|
|
37
|
+
* observability tools: when either is false a call to the gated tool is refused
|
|
38
|
+
* even if the client somehow names it, so both guarantees hold at dispatch, not
|
|
39
|
+
* just in the advertised tool list.
|
|
25
40
|
*/
|
|
26
|
-
declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean) => Promise<ToolResult>;
|
|
41
|
+
declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, hasAdminToken?: boolean) => Promise<ToolResult>;
|
|
27
42
|
/**
|
|
28
43
|
* Agent exposure for the MCP server: a durable `@lunora/agent` run fronted as an
|
|
29
44
|
* MCP tool an external agent can call. The capability boundary is the MCP-server
|
|
@@ -125,6 +140,10 @@ interface LunoraMcpServerOptions {
|
|
|
125
140
|
* therefore NOT enforced by the token's scope; it is enforced in-process via
|
|
126
141
|
* `allowWrites: false` (the default), which omits the write tools from the
|
|
127
142
|
* advertised list and refuses them at dispatch.
|
|
143
|
+
*
|
|
144
|
+
* Its presence is also what gates the observability tools (logs, Issues,
|
|
145
|
+
* advisories, query insights, migration status): without a token they are
|
|
146
|
+
* omitted from `ListTools` and refused at dispatch.
|
|
128
147
|
*/
|
|
129
148
|
token?: string;
|
|
130
149
|
/** Base URL of the deployed Lunora Worker. Required unless `client` is given. */
|
|
@@ -299,4 +318,4 @@ interface PaidMcpServer {
|
|
|
299
318
|
* transient facilitator outage retries on the next call.
|
|
300
319
|
*/
|
|
301
320
|
declare const createPaidMcpServer: (config: PaidMcpServerConfig) => PaidMcpServer;
|
|
302
|
-
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, 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, 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 };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,29 +1,44 @@
|
|
|
1
1
|
import { LunoraClient } from '@lunora/client';
|
|
2
|
-
import { T as ToolDefinition, f as ToolResult, e as ToolInputSchema, a as McpFetchHandler, b as McpTool } from "./packem_shared/serve-stateless.d-
|
|
3
|
-
export { type d as McpServerInfo, g as createToolServer, s as serveStateless } from "./packem_shared/serve-stateless.d-
|
|
2
|
+
import { T as ToolDefinition, f as ToolResult, e as ToolInputSchema, a as McpFetchHandler, b as McpTool } from "./packem_shared/serve-stateless.d-B_q8q39X.js";
|
|
3
|
+
export { type d as McpServerInfo, g as createToolServer, s as serveStateless } from "./packem_shared/serve-stateless.d-B_q8q39X.js";
|
|
4
4
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
5
|
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
6
6
|
import '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
7
|
+
/**
|
|
8
|
+
* The observability tools. Descriptions say WHEN to call the tool, not just
|
|
9
|
+
* what it returns — an agent picking between five similar reads needs the
|
|
10
|
+
* trigger, and it pays for these strings on every turn.
|
|
11
|
+
*/
|
|
12
|
+
declare const OBSERVABILITY_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
7
13
|
/** The read-only tool surface: introspection + query. Always exposed. */
|
|
8
14
|
declare const READ_ONLY_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
9
15
|
/** The write tool surface (mutations + actions). Exposed ONLY when writes are enabled. */
|
|
10
16
|
declare const WRITE_TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
|
|
11
17
|
/**
|
|
12
|
-
* The tools this server advertises
|
|
13
|
-
*
|
|
14
|
-
*
|
|
18
|
+
* The tools this server advertises, in three tiers:
|
|
19
|
+
*
|
|
20
|
+
* - the read-only surface, always exposed;
|
|
21
|
+
* - the observability surface, exposed only when an admin token resolved —
|
|
22
|
+
* read-only, but it surfaces production logs and grouped errors, so an
|
|
23
|
+
* unauthenticated server must not even advertise that it exists;
|
|
24
|
+
* - the write surface, exposed only when `allowWrites` is set.
|
|
25
|
+
*
|
|
26
|
+
* Both gates OMIT rather than refuse: an AI agent can't invoke what it can't
|
|
27
|
+
* see. Dispatch re-checks both in {@link callTool}, so the guarantee does not
|
|
28
|
+
* depend on a client honouring the advertised list.
|
|
15
29
|
*/
|
|
16
|
-
declare const toolDefinitions: (allowWrites: boolean) => ReadonlyArray<ToolDefinition>;
|
|
30
|
+
declare const toolDefinitions: (allowWrites: boolean, hasAdminToken?: boolean) => ReadonlyArray<ToolDefinition>;
|
|
17
31
|
/**
|
|
18
32
|
* Dispatch a tool call against `client`. Unknown tools and thrown errors are
|
|
19
33
|
* returned as `isError` results (rather than rejections) so the calling model
|
|
20
34
|
* sees the failure as tool output, per the MCP convention.
|
|
21
35
|
*
|
|
22
|
-
* `allowWrites` gates the mutation/action tools
|
|
23
|
-
*
|
|
24
|
-
*
|
|
36
|
+
* `allowWrites` gates the mutation/action tools and `hasAdminToken` gates the
|
|
37
|
+
* observability tools: when either is false a call to the gated tool is refused
|
|
38
|
+
* even if the client somehow names it, so both guarantees hold at dispatch, not
|
|
39
|
+
* just in the advertised tool list.
|
|
25
40
|
*/
|
|
26
|
-
declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean) => Promise<ToolResult>;
|
|
41
|
+
declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>, allowWrites?: boolean, hasAdminToken?: boolean) => Promise<ToolResult>;
|
|
27
42
|
/**
|
|
28
43
|
* Agent exposure for the MCP server: a durable `@lunora/agent` run fronted as an
|
|
29
44
|
* MCP tool an external agent can call. The capability boundary is the MCP-server
|
|
@@ -125,6 +140,10 @@ interface LunoraMcpServerOptions {
|
|
|
125
140
|
* therefore NOT enforced by the token's scope; it is enforced in-process via
|
|
126
141
|
* `allowWrites: false` (the default), which omits the write tools from the
|
|
127
142
|
* advertised list and refuses them at dispatch.
|
|
143
|
+
*
|
|
144
|
+
* Its presence is also what gates the observability tools (logs, Issues,
|
|
145
|
+
* advisories, query insights, migration status): without a token they are
|
|
146
|
+
* omitted from `ListTools` and refused at dispatch.
|
|
128
147
|
*/
|
|
129
148
|
token?: string;
|
|
130
149
|
/** Base URL of the deployed Lunora Worker. Required unless `client` is given. */
|
|
@@ -299,4 +318,4 @@ interface PaidMcpServer {
|
|
|
299
318
|
* transient facilitator outage retries on the next call.
|
|
300
319
|
*/
|
|
301
320
|
declare const createPaidMcpServer: (config: PaidMcpServerConfig) => PaidMcpServer;
|
|
302
|
-
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, 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, 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 };
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{AGENT_RUN_INPUT_SCHEMA as r,AGENT_STATUS_TOOL_NAME as t,agentToolDefinitions as
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
|
@@ -0,0 +1 @@
|
|
|
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};
|
package/dist/packem_shared/{serve-stateless.d-DX0di_lv.d.mts → serve-stateless.d-B_q8q39X.d.mts}
RENAMED
|
@@ -42,6 +42,12 @@ interface ToolDefinition {
|
|
|
42
42
|
description: string;
|
|
43
43
|
inputSchema: ToolInputSchema;
|
|
44
44
|
name: string;
|
|
45
|
+
/**
|
|
46
|
+
* JSON Schema for the tool's `structuredContent`. Optional: a tool that
|
|
47
|
+
* emits only a text block declares none, and a client that negotiated an
|
|
48
|
+
* MCP revision older than `2025-06-18` ignores it either way.
|
|
49
|
+
*/
|
|
50
|
+
outputSchema?: ToolInputSchema;
|
|
45
51
|
}
|
|
46
52
|
/** The MCP `CallToolResult` shape this package's tools return. */
|
|
47
53
|
interface ToolResult {
|
|
@@ -50,6 +56,14 @@ interface ToolResult {
|
|
|
50
56
|
type: "text";
|
|
51
57
|
}[];
|
|
52
58
|
isError?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* The machine-readable result, mirroring the text block. Present only for
|
|
61
|
+
* tools that declare an `outputSchema`; per the MCP spec it must be a JSON
|
|
62
|
+
* OBJECT (never a bare array) and must survive `JSON.stringify` — the
|
|
63
|
+
* transport serializes it, so an un-mapped `bigint` here fails the whole
|
|
64
|
+
* response rather than one field.
|
|
65
|
+
*/
|
|
66
|
+
structuredContent?: Record<string, unknown>;
|
|
53
67
|
}
|
|
54
68
|
/** A tool: what to advertise in `ListTools`, and what to run on `CallTool`. */
|
|
55
69
|
interface McpTool {
|
package/dist/packem_shared/{serve-stateless.d-DX0di_lv.d.ts → serve-stateless.d-B_q8q39X.d.ts}
RENAMED
|
@@ -42,6 +42,12 @@ interface ToolDefinition {
|
|
|
42
42
|
description: string;
|
|
43
43
|
inputSchema: ToolInputSchema;
|
|
44
44
|
name: string;
|
|
45
|
+
/**
|
|
46
|
+
* JSON Schema for the tool's `structuredContent`. Optional: a tool that
|
|
47
|
+
* emits only a text block declares none, and a client that negotiated an
|
|
48
|
+
* MCP revision older than `2025-06-18` ignores it either way.
|
|
49
|
+
*/
|
|
50
|
+
outputSchema?: ToolInputSchema;
|
|
45
51
|
}
|
|
46
52
|
/** The MCP `CallToolResult` shape this package's tools return. */
|
|
47
53
|
interface ToolResult {
|
|
@@ -50,6 +56,14 @@ interface ToolResult {
|
|
|
50
56
|
type: "text";
|
|
51
57
|
}[];
|
|
52
58
|
isError?: boolean;
|
|
59
|
+
/**
|
|
60
|
+
* The machine-readable result, mirroring the text block. Present only for
|
|
61
|
+
* tools that declare an `outputSchema`; per the MCP spec it must be a JSON
|
|
62
|
+
* OBJECT (never a bare array) and must survive `JSON.stringify` — the
|
|
63
|
+
* transport serializes it, so an un-mapped `bigint` here fails the whole
|
|
64
|
+
* response rather than one field.
|
|
65
|
+
*/
|
|
66
|
+
structuredContent?: Record<string, unknown>;
|
|
53
67
|
}
|
|
54
68
|
/** A tool: what to advertise in `ListTools`, and what to run on `CallTool`. */
|
|
55
69
|
interface McpTool {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/mcp",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.61",
|
|
4
4
|
"description": "Model Context Protocol server exposing a Lunora deployment to AI agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agents",
|
|
@@ -55,6 +55,7 @@
|
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@lunora/client": "1.0.0-alpha.43",
|
|
57
57
|
"@lunora/errors": "1.0.0-alpha.16",
|
|
58
|
+
"@lunora/shard-engine": "1.0.0-alpha.16",
|
|
58
59
|
"@modelcontextprotocol/sdk": "^1.29.0"
|
|
59
60
|
},
|
|
60
61
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraClient as p}from"@lunora/client";import{StdioServerTransport as u}from"@modelcontextprotocol/sdk/server/stdio.js";import{createToolServer as f}from"./createToolServer-CP5bNUcS.mjs";import{createRemoteDocsIndex as m}from"./DEFAULT_DOCS_BASE_URL-DhaPz6PK.mjs";import{docsResources as v}from"./DOCS_URI_SCHEME-DbyotZvf.mjs";import{docsTools as h}from"./DEFAULT_SEARCH_LIMIT-CKtOASrB.mjs";import{toolDefinitions as y,callTool as O}from"./READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";const R=(t,e)=>{if(t.size<e)return;const o=t.keys().next().value;o!==void 0&&t.delete(o)},c=t=>t.docs===!1?void 0:m({...t.docs?.baseUrl===void 0?{}:{baseUrl:t.docs.baseUrl},...t.fetch===void 0?{}:{fetch:t.fetch}}),E="lunora",P="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).",_=8,l=t=>{const e=new Map;return o=>{const n=JSON.stringify([o.url,o.token??""]),r=e.get(n);if(r!==void 0)return r;const i=new p({fetch:t,url:o.url});return o.token!==void 0&&o.token.length>0&&i.setAuthToken(o.token),R(e,_),e.set(n,i),i}},w=(t,e,o)=>{const n=typeof t=="function"?t:()=>t;return y(e).map(r=>({definition:r,handle:async i=>{const s=n();return s===void 0?{content:[{text:P,type:"text"}],isError:!0}:O(o(s),r.name,i,e)}}))},S="lunora-spec:openrpc",T="lunora-spec:openapi",a=[{description:"The deployment's generated OpenRPC 1.x document — every RPC function's path, kind, and argument schema in one read, instead of list_functions plus one get_function_schema call per function.",fetch:async t=>t.fetchOpenRpc(),name:"OpenRPC specification",uri:S},{description:"The deployment's generated OpenAPI 3.1 document.",fetch:async t=>t.fetchOpenApi(),name:"OpenAPI specification",uri:T}],g=(t,e)=>{const o=typeof t=="function"?t:()=>t,n=async r=>{const i=o();if(i!==void 0)try{return await r.fetch(e(i))}catch{return}};return{list:async()=>(await Promise.all(a.map(async r=>await n(r)===void 0?void 0:{description:r.description,mimeType:"application/json",name:r.name,uri:r.uri}))).filter(r=>r!==void 0),read:async r=>{const i=a.find(d=>d.uri===r);if(i===void 0)return;const s=await n(i);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 e=>e.list()))).flat(),read:async e=>{for(const o of t){const n=await o.read(e);if(n!==void 0)return n}}}),x=(t,e)=>{const o=[],n=c(t);return n!==void 0&&o.push(...h(n)),o.push(...t.extraTools??[]),t.deployment!==void 0&&o.push(...w(t.deployment,t.allowWrites??!1,e??l(t.fetch))),o},C=(t={})=>{const e=c(t),o=[];e!==void 0&&o.push(v(e));const n=l(t.fetch);return t.deployment!==void 0&&o.push(g(t.deployment,n)),f({name:E,version:t.version??"0.0.0"},x(t,n),o.length===0?void 0:A(o))},$=async(t={})=>{const e=C(t);return await e.connect(new u),e};export{E as LOCAL_SERVER_NAME,P as NO_DEPLOYMENT_MESSAGE,T as OPENAPI_RESOURCE_URI,S as OPENRPC_RESOURCE_URI,$ as connectLocalStdio,C as createLocalMcpServer,x as localTools};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraError as u}from"@lunora/errors";const h={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"},m={properties:{},type:"object"},E={properties:{functionPath:{description:'Function reference, e.g. "messages:send"',type:"string"}},required:["functionPath"],type:"object"},c={destructiveHint:!1,idempotentHint:!0,openWorldHint:!0,readOnlyHint:!0},g=[{annotations:{...c,title:"List deployment functions"},description:"List the deployment's public functions (queries, mutations, actions) with their kinds.",inputSchema:m,name:"lunora_list_functions"},{annotations:{...c,title:"List global tables"},description:"List the deployment's .global() tables and their column shapes.",inputSchema:m,name:"lunora_list_tables"},{annotations:{...c,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:E,name:"lunora_get_function_schema"},{annotations:{...c,title:"Run a query"},description:"Run a query and return its result. Read-only.",inputSchema:h,name:"lunora_run_query"}],S=[{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:h,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:h,name:"lunora_run_action"}],A=new Set(S.map(t=>t.name)),T=t=>t===!0?[...g,...S]:g,O=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},_=t=>typeof t=="object"&&t!==null&&!Array.isArray(t),w=t=>Array.isArray(t)?"an array":`a ${typeof t}`,v=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(!_(e))throw new u("BAD_REQUEST",`"args" must be a JSON object; the provided string decoded to ${w(e)}`);return e}if(!_(t))throw new u("BAD_REQUEST",`"args" must be a JSON object, got ${w(t)}`);return t},d=t=>{const e=O(t),n=v(t.args),i=typeof t.shardKey=="string"&&t.shardKey.length>0?t.shardKey:void 0;return{args:n,functionPath:e,shardKey:i}},f=t=>({__lunoraRef:t}),b=t=>{let e="";for(let n=0;n<t.length;n+=32768)e+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(e)},R=(t,e)=>{if(typeof e=="bigint")return e.toString();if(e instanceof ArrayBuffer)return b(new Uint8Array(e));if(ArrayBuffer.isView(e)){const n=e;return b(new Uint8Array(n.buffer,n.byteOffset,n.byteLength))}return e},s=t=>({content:[{text:t===void 0?"null":JSON.stringify(t,R,2),type:"text"}]}),N=3e4,l=new WeakMap,y=t=>{const e=Date.now(),n=l.get(t);if(n!==void 0&&n.expiresAt>e)return n.promise;const i=t.listFunctions().catch(r=>{throw l.get(t)?.promise===i&&l.delete(t),r});return l.set(t,{expiresAt:e+N,promise:i}),i},p=async(t,e,n)=>{const i=(await y(t)).find(r=>r.path===e);if(i===void 0)throw new u("NOT_FOUND",`function not found or not public: ${e}`);if(i.kind!==n)throw new u("BAD_REQUEST",`function ${e} is a ${i.kind}, not a ${n}`)},L=async(t,e,n,i=!1)=>{try{if(i!==!0&&A.has(e))return{content:[{text:`tool "${e}" is disabled: this MCP server is read-only. Enable writes with the LUNORA_MCP_ALLOW_WRITES env var.`,type:"text"}],isError:!0};switch(e){case"lunora_get_function_schema":{const r=O(n),a=(await y(t)).find(o=>o.path===r);return a===void 0?{content:[{text:`function not found: ${r}`,type:"text"}],isError:!0}:s({args:a.args??[],kind:a.kind,path:a.path})}case"lunora_list_functions":return s(await y(t));case"lunora_list_tables":return s(await t.listGlobalTables());case"lunora_run_action":{const{args:r,functionPath:a,shardKey:o}=d(n);return await p(t,a,"action"),s(await t.action(f(a),r,{shardKey:o}))}case"lunora_run_mutation":{const{args:r,functionPath:a,shardKey:o}=d(n);return await p(t,a,"mutation"),s(await t.mutation(f(a),r,{shardKey:o}))}case"lunora_run_query":{const{args:r,functionPath:a,shardKey:o}=d(n);return await p(t,a,"query"),s(await t.query(f(a),r,{shardKey:o}))}default:return{content:[{text:`unknown tool: ${e}`,type:"text"}],isError:!0}}}catch(r){return{content:[{text:r instanceof Error?r.message:String(r),type:"text"}],isError:!0}}};export{g as READ_ONLY_TOOL_DEFINITIONS,S as WRITE_TOOL_DEFINITIONS,L as callTool,T as toolDefinitions};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{readFileSync as u}from"node:fs";import{dirname as l,join as f}from"node:path";import{fileURLToPath as p}from"node:url";import{LunoraClient as v}from"@lunora/client";import{LunoraError as g}from"@lunora/errors";import{Server as d}from"@modelcontextprotocol/sdk/server/index.js";import{StdioServerTransport as h}from"@modelcontextprotocol/sdk/server/stdio.js";import{ListToolsRequestSchema as w,CallToolRequestSchema as M}from"@modelcontextprotocol/sdk/types.js";import{agentToolDefinitions as S,isAgentToolName as T,callAgentTool as L}from"./AGENT_RUN_INPUT_SCHEMA-ihZg6vIZ.mjs";import{toolDefinitions as k,callTool as x}from"./READ_ONLY_TOOL_DEFINITIONS-48jMcpI-.mjs";const y=()=>{try{let t=l(p(import.meta.url));for(let r=0;r<8;r+=1){try{const a=u(f(t,"package.json"),"utf8"),o=JSON.parse(a);if(o.name==="@lunora/mcp"&&typeof o.version=="string"&&o.version.length>0)return o.version}catch{}const e=l(t);if(e===t)break;t=e}}catch{}return"0.0.0"},A={name:"lunora",version:y()},R=t=>{if(t.client!==void 0)return t.client;if(t.url===void 0)throw new g("INTERNAL","createLunoraMcpServer requires either a `client` or a `url`");const r=new v({fetch:t.fetch,url:t.url});return t.token!==void 0&&r.setAuthToken(t.token),r},q=t=>{const r=R(t),e=t.allowWrites??!1,a=t.allowAgents??!1,o=t.agents??[],n=new d(A,{capabilities:{tools:{}}});return n.setRequestHandler(w,()=>({tools:[...k(e),...S(o,a)]})),n.setRequestHandler(M,async c=>{const{arguments:m,name:s}=c.params,i=m??{};return T(s,o)?await L(r,s,i,{allowAgents:a,exposures:o,...t.agentMaxWaitMs===void 0?{}:{maxWaitMs:t.agentMaxWaitMs},...t.agentPollIntervalMs===void 0?{}:{pollIntervalMs:t.agentPollIntervalMs}}):await x(r,s,i,e)}),n},O=async t=>{const r=q(t);return await r.connect(new h),r};export{O as connectStdio,q as createLunoraMcpServer};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{serveStateless as s}from"./serveStateless-BqoRk-xU.mjs";import{createLunoraMcpServer as t}from"./connectStdio-Dt-DqEgA.mjs";const o=e=>r=>s(t(e),r);export{o as createMcpFetchHandler,s as serveStateless};
|