@lunora/mcp 0.0.0 → 1.0.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.mjs ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ import { connectStdio } from './packem_shared/connectStdio-C_mvQBs2.mjs';
3
+
4
+ class BinError extends Error {
5
+ code;
6
+ constructor(message, code) {
7
+ super(message);
8
+ this.name = "BinError";
9
+ this.code = code;
10
+ }
11
+ }
12
+ const runBin = async (environment, dependencies = {}) => {
13
+ const connect = dependencies.connect ?? connectStdio;
14
+ const writeError = dependencies.writeError ?? ((message) => {
15
+ process.stderr.write(message);
16
+ });
17
+ const url = environment.LUNORA_URL;
18
+ if (url === void 0 || url.length === 0) {
19
+ writeError("lunora-mcp: LUNORA_URL environment variable is required\n");
20
+ throw new BinError("LUNORA_URL environment variable is required", 1);
21
+ }
22
+ try {
23
+ await connect({ token: environment.LUNORA_ADMIN_TOKEN, url });
24
+ } catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ writeError(`lunora-mcp: failed to start — ${message}
27
+ `);
28
+ throw new BinError(`failed to start — ${message}`, 1);
29
+ }
30
+ };
31
+
32
+ try {
33
+ await runBin(process.env);
34
+ } catch (error) {
35
+ process.exit(error instanceof BinError ? error.code : 1);
36
+ }
@@ -0,0 +1,30 @@
1
+ import { LunoraClient } from '@lunora/client';
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ interface LunoraMcpServerOptions {
4
+ client?: LunoraClient;
5
+ fetch?: typeof fetch;
6
+ token?: string;
7
+ url?: string;
8
+ }
9
+ declare const createLunoraMcpServer: (options: LunoraMcpServerOptions) => Server;
10
+ declare const connectStdio: (options: LunoraMcpServerOptions) => Promise<Server>;
11
+ interface ToolInputSchema {
12
+ properties: Record<string, unknown>;
13
+ required?: ReadonlyArray<string>;
14
+ type: "object";
15
+ }
16
+ interface ToolDefinition {
17
+ description: string;
18
+ inputSchema: ToolInputSchema;
19
+ name: string;
20
+ }
21
+ interface ToolResult {
22
+ content: {
23
+ text: string;
24
+ type: "text";
25
+ }[];
26
+ isError?: boolean;
27
+ }
28
+ declare const TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
29
+ declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>) => Promise<ToolResult>;
30
+ export { type LunoraMcpServerOptions, TOOL_DEFINITIONS, type ToolDefinition, type ToolInputSchema, type ToolResult, callTool, connectStdio, createLunoraMcpServer };
@@ -0,0 +1,30 @@
1
+ import { LunoraClient } from '@lunora/client';
2
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
+ interface LunoraMcpServerOptions {
4
+ client?: LunoraClient;
5
+ fetch?: typeof fetch;
6
+ token?: string;
7
+ url?: string;
8
+ }
9
+ declare const createLunoraMcpServer: (options: LunoraMcpServerOptions) => Server;
10
+ declare const connectStdio: (options: LunoraMcpServerOptions) => Promise<Server>;
11
+ interface ToolInputSchema {
12
+ properties: Record<string, unknown>;
13
+ required?: ReadonlyArray<string>;
14
+ type: "object";
15
+ }
16
+ interface ToolDefinition {
17
+ description: string;
18
+ inputSchema: ToolInputSchema;
19
+ name: string;
20
+ }
21
+ interface ToolResult {
22
+ content: {
23
+ text: string;
24
+ type: "text";
25
+ }[];
26
+ isError?: boolean;
27
+ }
28
+ declare const TOOL_DEFINITIONS: ReadonlyArray<ToolDefinition>;
29
+ declare const callTool: (client: LunoraClient, name: string, input: Record<string, unknown>) => Promise<ToolResult>;
30
+ export { type LunoraMcpServerOptions, TOOL_DEFINITIONS, type ToolDefinition, type ToolInputSchema, type ToolResult, callTool, connectStdio, createLunoraMcpServer };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ export { connectStdio, createLunoraMcpServer } from './packem_shared/connectStdio-C_mvQBs2.mjs';
2
+ export { TOOL_DEFINITIONS, callTool } from './packem_shared/TOOL_DEFINITIONS-Dpiu38ji.mjs';
@@ -0,0 +1,112 @@
1
+ const RUN_INPUT_SCHEMA = {
2
+ properties: {
3
+ args: { description: "Arguments object passed to the function", type: "object" },
4
+ functionPath: { description: 'Function reference, e.g. "messages:send"', type: "string" },
5
+ shardKey: { description: "Optional shard key when the function is .shardBy()-partitioned", type: "string" }
6
+ },
7
+ required: ["functionPath"],
8
+ type: "object"
9
+ };
10
+ const NO_INPUT_SCHEMA = { properties: {}, type: "object" };
11
+ const FUNCTION_PATH_INPUT_SCHEMA = {
12
+ properties: {
13
+ functionPath: { description: 'Function reference, e.g. "messages:send"', type: "string" }
14
+ },
15
+ required: ["functionPath"],
16
+ type: "object"
17
+ };
18
+ const TOOL_DEFINITIONS = [
19
+ {
20
+ description: "List the deployment's public functions (queries, mutations, actions) with their kinds.",
21
+ inputSchema: NO_INPUT_SCHEMA,
22
+ name: "lunora_list_functions"
23
+ },
24
+ {
25
+ description: "List the deployment's .global() tables and their column shapes.",
26
+ inputSchema: NO_INPUT_SCHEMA,
27
+ name: "lunora_list_tables"
28
+ },
29
+ {
30
+ 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.",
31
+ inputSchema: FUNCTION_PATH_INPUT_SCHEMA,
32
+ name: "lunora_get_function_schema"
33
+ },
34
+ {
35
+ description: "Run a query and return its result. Read-only.",
36
+ inputSchema: RUN_INPUT_SCHEMA,
37
+ name: "lunora_run_query"
38
+ },
39
+ {
40
+ description: "Run a mutation and return its result. Writes data — use with care.",
41
+ inputSchema: RUN_INPUT_SCHEMA,
42
+ name: "lunora_run_mutation"
43
+ },
44
+ {
45
+ description: "Run an action and return its result. May call external services.",
46
+ inputSchema: RUN_INPUT_SCHEMA,
47
+ name: "lunora_run_action"
48
+ }
49
+ ];
50
+ const readFunctionPath = (input) => {
51
+ const { functionPath } = input;
52
+ if (typeof functionPath !== "string" || functionPath.length === 0) {
53
+ throw new Error('"functionPath" is required and must be a non-empty string');
54
+ }
55
+ return functionPath;
56
+ };
57
+ const readRunArguments = (input) => {
58
+ const functionPath = readFunctionPath(input);
59
+ const rawArguments = input.args;
60
+ const isPlainObject = typeof rawArguments === "object" && rawArguments !== null && !Array.isArray(rawArguments);
61
+ const args = isPlainObject ? rawArguments : {};
62
+ const shardKey = typeof input.shardKey === "string" && input.shardKey.length > 0 ? input.shardKey : void 0;
63
+ return { args, functionPath, shardKey };
64
+ };
65
+ const reference = (functionPath) => {
66
+ return { __lunoraRef: functionPath };
67
+ };
68
+ const ok = (value) => {
69
+ const text = value === void 0 ? "null" : JSON.stringify(value, void 0, 2);
70
+ return { content: [{ text, type: "text" }] };
71
+ };
72
+ const callTool = async (client, name, input) => {
73
+ try {
74
+ switch (name) {
75
+ case "lunora_get_function_schema": {
76
+ const functionPath = readFunctionPath(input);
77
+ const functions = await client.listFunctions();
78
+ const descriptor = functions.find((function_) => function_.path === functionPath);
79
+ if (descriptor === void 0) {
80
+ return { content: [{ text: `function not found: ${functionPath}`, type: "text" }], isError: true };
81
+ }
82
+ return ok({ args: descriptor.args ?? [], kind: descriptor.kind, path: descriptor.path });
83
+ }
84
+ case "lunora_list_functions": {
85
+ return ok(await client.listFunctions());
86
+ }
87
+ case "lunora_list_tables": {
88
+ return ok(await client.listGlobalTables());
89
+ }
90
+ case "lunora_run_action": {
91
+ const { args, functionPath, shardKey } = readRunArguments(input);
92
+ return ok(await client.action(reference(functionPath), args, { shardKey }));
93
+ }
94
+ case "lunora_run_mutation": {
95
+ const { args, functionPath, shardKey } = readRunArguments(input);
96
+ return ok(await client.mutation(reference(functionPath), args, { shardKey }));
97
+ }
98
+ case "lunora_run_query": {
99
+ const { args, functionPath, shardKey } = readRunArguments(input);
100
+ return ok(await client.query(reference(functionPath), args, { shardKey }));
101
+ }
102
+ default: {
103
+ return { content: [{ text: `unknown tool: ${name}`, type: "text" }], isError: true };
104
+ }
105
+ }
106
+ } catch (error) {
107
+ const message = error instanceof Error ? error.message : String(error);
108
+ return { content: [{ text: message, type: "text" }], isError: true };
109
+ }
110
+ };
111
+
112
+ export { TOOL_DEFINITIONS, callTool };
@@ -0,0 +1,64 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { LunoraClient } from '@lunora/client';
5
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
6
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
7
+ import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
8
+ import { TOOL_DEFINITIONS, callTool } from './TOOL_DEFINITIONS-Dpiu38ji.mjs';
9
+
10
+ const resolveVersion = () => {
11
+ try {
12
+ let directory = dirname(fileURLToPath(import.meta.url));
13
+ for (let depth = 0; depth < 8; depth += 1) {
14
+ try {
15
+ const raw = readFileSync(join(directory, "package.json"), "utf8");
16
+ const pkg = JSON.parse(raw);
17
+ if (pkg.name === "@lunora/mcp" && typeof pkg.version === "string" && pkg.version.length > 0) {
18
+ return pkg.version;
19
+ }
20
+ } catch {
21
+ }
22
+ const parent = dirname(directory);
23
+ if (parent === directory) {
24
+ break;
25
+ }
26
+ directory = parent;
27
+ }
28
+ } catch {
29
+ }
30
+ return "0.0.0";
31
+ };
32
+ const SERVER_INFO = { name: "lunora", version: resolveVersion() };
33
+ const resolveClient = (options) => {
34
+ if (options.client !== void 0) {
35
+ return options.client;
36
+ }
37
+ if (options.url === void 0) {
38
+ throw new Error("createLunoraMcpServer requires either a `client` or a `url`");
39
+ }
40
+ const client = new LunoraClient({ fetch: options.fetch, url: options.url });
41
+ if (options.token !== void 0) {
42
+ client.setAuthToken(options.token);
43
+ }
44
+ return client;
45
+ };
46
+ const createLunoraMcpServer = (options) => {
47
+ const client = resolveClient(options);
48
+ const server = new Server(SERVER_INFO, { capabilities: { tools: {} } });
49
+ server.setRequestHandler(ListToolsRequestSchema, () => {
50
+ return { tools: [...TOOL_DEFINITIONS] };
51
+ });
52
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
53
+ const result = await callTool(client, request.params.name, request.params.arguments ?? {});
54
+ return result;
55
+ });
56
+ return server;
57
+ };
58
+ const connectStdio = async (options) => {
59
+ const server = createLunoraMcpServer(options);
60
+ await server.connect(new StdioServerTransport());
61
+ return server;
62
+ };
63
+
64
+ export { connectStdio, createLunoraMcpServer };
package/package.json CHANGED
@@ -1,31 +1,58 @@
1
1
  {
2
2
  "name": "@lunora/mcp",
3
- "version": "0.0.0",
3
+ "version": "1.0.0-alpha.2",
4
4
  "description": "Model Context Protocol server exposing a Lunora deployment to AI agents",
5
- "license": "FSL-1.1-Apache-2.0",
5
+ "keywords": [
6
+ "ai-agents",
7
+ "cloudflare",
8
+ "durable-objects",
9
+ "llm",
10
+ "lunora",
11
+ "mcp",
12
+ "model-context-protocol",
13
+ "workers"
14
+ ],
6
15
  "homepage": "https://lunora.sh",
16
+ "bugs": "https://github.com/anolilab/lunora/issues",
17
+ "license": "FSL-1.1-Apache-2.0",
18
+ "author": {
19
+ "name": "Daniel Bannert",
20
+ "email": "d.bannert@anolilab.de"
21
+ },
7
22
  "repository": {
8
23
  "type": "git",
9
24
  "url": "git+https://github.com/anolilab/lunora.git",
10
25
  "directory": "packages/mcp"
11
26
  },
12
- "bugs": {
13
- "url": "https://github.com/anolilab/lunora/issues"
27
+ "bin": {
28
+ "lunora-mcp": "./dist/bin.mjs"
14
29
  },
15
- "keywords": [
16
- "lunora",
17
- "cloudflare",
18
- "workers",
19
- "durable-objects",
20
- "mcp",
21
- "model-context-protocol",
22
- "ai-agents",
23
- "llm"
30
+ "files": [
31
+ "dist",
32
+ "__assets__",
33
+ "README.md",
34
+ "LICENSE.md"
24
35
  ],
36
+ "type": "module",
37
+ "sideEffects": false,
38
+ "main": "./dist/index.mjs",
39
+ "module": "./dist/index.mjs",
40
+ "types": "./dist/index.d.ts",
41
+ "exports": {
42
+ ".": {
43
+ "types": "./dist/index.d.ts",
44
+ "import": "./dist/index.mjs"
45
+ },
46
+ "./package.json": "./package.json"
47
+ },
25
48
  "publishConfig": {
26
49
  "access": "public"
27
50
  },
28
- "files": [
29
- "README.md"
30
- ]
51
+ "dependencies": {
52
+ "@lunora/client": "1.0.0-alpha.2",
53
+ "@modelcontextprotocol/sdk": "^1.29.0"
54
+ },
55
+ "engines": {
56
+ "node": "^22.15.0 || >=24.11.0"
57
+ }
31
58
  }