@lunora/mcp 1.0.0-alpha.7 → 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.
- package/LICENSE.md +126 -0
- package/README.md +139 -9
- package/dist/bin.mjs +3 -35
- package/dist/docs/index.d.mts +250 -0
- package/dist/docs/index.d.ts +250 -0
- package/dist/docs/index.mjs +1 -0
- package/dist/index.d.mts +355 -14
- package/dist/index.d.ts +355 -14
- package/dist/index.mjs +1 -2
- package/dist/packem_shared/AGENT_RUN_INPUT_SCHEMA-DRSY74ed.mjs +1 -0
- package/dist/packem_shared/DEFAULT_DOCS_BASE_URL-CZ3fVsSc.mjs +4 -0
- package/dist/packem_shared/DEFAULT_SEARCH_LIMIT-DWPt0hvR.mjs +3 -0
- package/dist/packem_shared/DOCS_SERVER_NAME-BWzPxJyZ.mjs +1 -0
- package/dist/packem_shared/DOCS_URI_SCHEME-CFANc3vr.mjs +3 -0
- package/dist/packem_shared/LOCAL_SERVER_NAME-0Jb4neqA.mjs +1 -0
- package/dist/packem_shared/OBSERVABILITY_TOOL_DEFINITIONS-KrCukPbu.mjs +1 -0
- package/dist/packem_shared/READ_ONLY_TOOL_DEFINITIONS-DGexf3Tn.mjs +1 -0
- package/dist/packem_shared/connectStdio-BCeI0Wqu.mjs +1 -0
- package/dist/packem_shared/createMcpFetchHandler-TKDnZTGs.mjs +1 -0
- package/dist/packem_shared/createPaidMcpServer-CQO-59WV.mjs +1 -0
- package/dist/packem_shared/createToolServer-BtGuPyMU.mjs +1 -0
- package/dist/packem_shared/observability-tools-Ce0YK58T.mjs +1 -0
- package/dist/packem_shared/serve-stateless.d-B_q8q39X.d.mts +133 -0
- package/dist/packem_shared/serve-stateless.d-B_q8q39X.d.ts +133 -0
- package/dist/packem_shared/serveStateless-Db7J3pAO.mjs +1 -0
- package/dist/packem_shared/toDocsSearchHits-CBLmtWXt.mjs +1 -0
- package/package.json +17 -3
- package/dist/packem_shared/TOOL_DEFINITIONS-Dpiu38ji.mjs +0 -112
- package/dist/packem_shared/connectStdio-C_mvQBs2.mjs +0 -64
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { HandleRequestOptions } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
3
|
+
/**
|
|
4
|
+
* The MCP wire shapes every tool surface in this package speaks — the
|
|
5
|
+
* deployment tools (`./tools`), the agent tools (`./agent-tools`), and the
|
|
6
|
+
* documentation tools (`./docs`).
|
|
7
|
+
*
|
|
8
|
+
* They live in their own module (rather than in `./tools`) so a consumer that
|
|
9
|
+
* only wants the docs surface can import the types without dragging
|
|
10
|
+
* `@lunora/client` into its bundle. `./tools` re-exports them, so the package's
|
|
11
|
+
* public API is unchanged.
|
|
12
|
+
*/
|
|
13
|
+
/** A JSON-Schema object describing a tool's arguments, per the MCP spec. */
|
|
14
|
+
interface ToolInputSchema {
|
|
15
|
+
properties: Record<string, unknown>;
|
|
16
|
+
required?: ReadonlyArray<string>;
|
|
17
|
+
type: "object";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* MCP tool annotations — hints a client may use to decide how to present a tool
|
|
21
|
+
* (badge it read-only, confirm before a destructive call).
|
|
22
|
+
*
|
|
23
|
+
* They are hints, not enforcement: this package's actual guarantees are made at
|
|
24
|
+
* dispatch, where a write tool is refused unless `allowWrites` is set. These
|
|
25
|
+
* exist so a client can *show* the user what the server already enforces,
|
|
26
|
+
* instead of every tool looking equally dangerous.
|
|
27
|
+
*/
|
|
28
|
+
interface ToolAnnotations {
|
|
29
|
+
/** The tool may perform irreversible changes. Only meaningful when `readOnlyHint` is false. */
|
|
30
|
+
destructiveHint?: boolean;
|
|
31
|
+
/** Repeating the call with the same arguments has no additional effect. */
|
|
32
|
+
idempotentHint?: boolean;
|
|
33
|
+
/** The tool reaches systems beyond this server (the network, external services). */
|
|
34
|
+
openWorldHint?: boolean;
|
|
35
|
+
/** The tool does not modify anything. */
|
|
36
|
+
readOnlyHint?: boolean;
|
|
37
|
+
/** Human-facing title, shown instead of the raw tool name. */
|
|
38
|
+
title?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ToolDefinition {
|
|
41
|
+
annotations?: ToolAnnotations;
|
|
42
|
+
description: string;
|
|
43
|
+
inputSchema: ToolInputSchema;
|
|
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;
|
|
51
|
+
}
|
|
52
|
+
/** The MCP `CallToolResult` shape this package's tools return. */
|
|
53
|
+
interface ToolResult {
|
|
54
|
+
content: {
|
|
55
|
+
text: string;
|
|
56
|
+
type: "text";
|
|
57
|
+
}[];
|
|
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>;
|
|
67
|
+
}
|
|
68
|
+
/** A tool: what to advertise in `ListTools`, and what to run on `CallTool`. */
|
|
69
|
+
interface McpTool {
|
|
70
|
+
definition: ToolDefinition;
|
|
71
|
+
handle: (input: Record<string, unknown>) => Promise<ToolResult>;
|
|
72
|
+
}
|
|
73
|
+
/** Name/version pair reported in the MCP `initialize` handshake. */
|
|
74
|
+
interface McpServerInfo {
|
|
75
|
+
name: string;
|
|
76
|
+
version: string;
|
|
77
|
+
}
|
|
78
|
+
/** One addressable document a client can list and read directly. */
|
|
79
|
+
interface McpResourceSummary {
|
|
80
|
+
description?: string;
|
|
81
|
+
mimeType?: string;
|
|
82
|
+
name: string;
|
|
83
|
+
uri: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A set of resources the server exposes alongside its tools.
|
|
87
|
+
*
|
|
88
|
+
* Tools are calls a model chooses to make; resources are documents a *client*
|
|
89
|
+
* can enumerate and attach on its own — the user picking a page to put in
|
|
90
|
+
* context, without the model having to guess a search query first. The same
|
|
91
|
+
* corpus is worth offering both ways.
|
|
92
|
+
*/
|
|
93
|
+
interface McpResourceProvider {
|
|
94
|
+
/** Every resource, for `resources/list`. */
|
|
95
|
+
list: () => Promise<ReadonlyArray<McpResourceSummary>>;
|
|
96
|
+
/** One resource's body, or `undefined` when the uri is unknown. */
|
|
97
|
+
read: (uri: string) => Promise<{
|
|
98
|
+
mimeType?: string;
|
|
99
|
+
text: string;
|
|
100
|
+
} | undefined>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build an MCP `Server` that advertises and dispatches `tools`.
|
|
104
|
+
*
|
|
105
|
+
* On duplicate names the FIRST wins, so a caller can layer surfaces in
|
|
106
|
+
* precedence order without the later list silently shadowing the earlier one.
|
|
107
|
+
* Thrown errors become `isError` results rather than rejections, per the MCP
|
|
108
|
+
* convention that a tool failure is output the model can read and react to,
|
|
109
|
+
* not a protocol-level fault.
|
|
110
|
+
*/
|
|
111
|
+
declare const createToolServer: (info: McpServerInfo, tools: ReadonlyArray<McpTool>, resources?: McpResourceProvider) => Server;
|
|
112
|
+
/** A Web-Standard fetch handler: takes a `Request`, returns the MCP `Response`. */
|
|
113
|
+
type McpFetchHandler = (request: Request) => Promise<Response>;
|
|
114
|
+
/**
|
|
115
|
+
* Drive one request through a fresh **stateless** Streamable-HTTP transport bound
|
|
116
|
+
* to `server`, then tear both down.
|
|
117
|
+
*
|
|
118
|
+
* `sessionIdGenerator: undefined` → stateless (no cross-request session store);
|
|
119
|
+
* `enableJsonResponse: true` → the whole JSON-RPC response is buffered into the
|
|
120
|
+
* returned `Response`, so closing the transport/server afterwards can't truncate
|
|
121
|
+
* an in-flight body. Cleanup is fire-and-forget with swallowed rejections (a
|
|
122
|
+
* `.catch()`-terminated chain) so it never delays or masks the resolved response.
|
|
123
|
+
*
|
|
124
|
+
* `options.parsedBody` lets a caller hand over a body it already read (e.g. the
|
|
125
|
+
* paid-tool gate, which peeks the JSON-RPC message to price the call) so the
|
|
126
|
+
* transport doesn't re-read a consumed stream.
|
|
127
|
+
*
|
|
128
|
+
* Teardown runs in a `finally`: a rejection from `connect` or `handleRequest`
|
|
129
|
+
* would otherwise skip it and leak a server + transport per failed request,
|
|
130
|
+
* which on a public endpoint is exactly the request an attacker can repeat.
|
|
131
|
+
*/
|
|
132
|
+
declare const serveStateless: (server: Server, request: Request, options?: HandleRequestOptions) => Promise<Response>;
|
|
133
|
+
export { McpResourceProvider as M, ToolDefinition as T, McpFetchHandler as a, McpTool as b, McpResourceSummary as c, McpServerInfo as d, ToolInputSchema as e, ToolResult as f, createToolServer as g, serveStateless as s };
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { HandleRequestOptions } from '@modelcontextprotocol/sdk/server/webStandardStreamableHttp.js';
|
|
3
|
+
/**
|
|
4
|
+
* The MCP wire shapes every tool surface in this package speaks — the
|
|
5
|
+
* deployment tools (`./tools`), the agent tools (`./agent-tools`), and the
|
|
6
|
+
* documentation tools (`./docs`).
|
|
7
|
+
*
|
|
8
|
+
* They live in their own module (rather than in `./tools`) so a consumer that
|
|
9
|
+
* only wants the docs surface can import the types without dragging
|
|
10
|
+
* `@lunora/client` into its bundle. `./tools` re-exports them, so the package's
|
|
11
|
+
* public API is unchanged.
|
|
12
|
+
*/
|
|
13
|
+
/** A JSON-Schema object describing a tool's arguments, per the MCP spec. */
|
|
14
|
+
interface ToolInputSchema {
|
|
15
|
+
properties: Record<string, unknown>;
|
|
16
|
+
required?: ReadonlyArray<string>;
|
|
17
|
+
type: "object";
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* MCP tool annotations — hints a client may use to decide how to present a tool
|
|
21
|
+
* (badge it read-only, confirm before a destructive call).
|
|
22
|
+
*
|
|
23
|
+
* They are hints, not enforcement: this package's actual guarantees are made at
|
|
24
|
+
* dispatch, where a write tool is refused unless `allowWrites` is set. These
|
|
25
|
+
* exist so a client can *show* the user what the server already enforces,
|
|
26
|
+
* instead of every tool looking equally dangerous.
|
|
27
|
+
*/
|
|
28
|
+
interface ToolAnnotations {
|
|
29
|
+
/** The tool may perform irreversible changes. Only meaningful when `readOnlyHint` is false. */
|
|
30
|
+
destructiveHint?: boolean;
|
|
31
|
+
/** Repeating the call with the same arguments has no additional effect. */
|
|
32
|
+
idempotentHint?: boolean;
|
|
33
|
+
/** The tool reaches systems beyond this server (the network, external services). */
|
|
34
|
+
openWorldHint?: boolean;
|
|
35
|
+
/** The tool does not modify anything. */
|
|
36
|
+
readOnlyHint?: boolean;
|
|
37
|
+
/** Human-facing title, shown instead of the raw tool name. */
|
|
38
|
+
title?: string;
|
|
39
|
+
}
|
|
40
|
+
interface ToolDefinition {
|
|
41
|
+
annotations?: ToolAnnotations;
|
|
42
|
+
description: string;
|
|
43
|
+
inputSchema: ToolInputSchema;
|
|
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;
|
|
51
|
+
}
|
|
52
|
+
/** The MCP `CallToolResult` shape this package's tools return. */
|
|
53
|
+
interface ToolResult {
|
|
54
|
+
content: {
|
|
55
|
+
text: string;
|
|
56
|
+
type: "text";
|
|
57
|
+
}[];
|
|
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>;
|
|
67
|
+
}
|
|
68
|
+
/** A tool: what to advertise in `ListTools`, and what to run on `CallTool`. */
|
|
69
|
+
interface McpTool {
|
|
70
|
+
definition: ToolDefinition;
|
|
71
|
+
handle: (input: Record<string, unknown>) => Promise<ToolResult>;
|
|
72
|
+
}
|
|
73
|
+
/** Name/version pair reported in the MCP `initialize` handshake. */
|
|
74
|
+
interface McpServerInfo {
|
|
75
|
+
name: string;
|
|
76
|
+
version: string;
|
|
77
|
+
}
|
|
78
|
+
/** One addressable document a client can list and read directly. */
|
|
79
|
+
interface McpResourceSummary {
|
|
80
|
+
description?: string;
|
|
81
|
+
mimeType?: string;
|
|
82
|
+
name: string;
|
|
83
|
+
uri: string;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A set of resources the server exposes alongside its tools.
|
|
87
|
+
*
|
|
88
|
+
* Tools are calls a model chooses to make; resources are documents a *client*
|
|
89
|
+
* can enumerate and attach on its own — the user picking a page to put in
|
|
90
|
+
* context, without the model having to guess a search query first. The same
|
|
91
|
+
* corpus is worth offering both ways.
|
|
92
|
+
*/
|
|
93
|
+
interface McpResourceProvider {
|
|
94
|
+
/** Every resource, for `resources/list`. */
|
|
95
|
+
list: () => Promise<ReadonlyArray<McpResourceSummary>>;
|
|
96
|
+
/** One resource's body, or `undefined` when the uri is unknown. */
|
|
97
|
+
read: (uri: string) => Promise<{
|
|
98
|
+
mimeType?: string;
|
|
99
|
+
text: string;
|
|
100
|
+
} | undefined>;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Build an MCP `Server` that advertises and dispatches `tools`.
|
|
104
|
+
*
|
|
105
|
+
* On duplicate names the FIRST wins, so a caller can layer surfaces in
|
|
106
|
+
* precedence order without the later list silently shadowing the earlier one.
|
|
107
|
+
* Thrown errors become `isError` results rather than rejections, per the MCP
|
|
108
|
+
* convention that a tool failure is output the model can read and react to,
|
|
109
|
+
* not a protocol-level fault.
|
|
110
|
+
*/
|
|
111
|
+
declare const createToolServer: (info: McpServerInfo, tools: ReadonlyArray<McpTool>, resources?: McpResourceProvider) => Server;
|
|
112
|
+
/** A Web-Standard fetch handler: takes a `Request`, returns the MCP `Response`. */
|
|
113
|
+
type McpFetchHandler = (request: Request) => Promise<Response>;
|
|
114
|
+
/**
|
|
115
|
+
* Drive one request through a fresh **stateless** Streamable-HTTP transport bound
|
|
116
|
+
* to `server`, then tear both down.
|
|
117
|
+
*
|
|
118
|
+
* `sessionIdGenerator: undefined` → stateless (no cross-request session store);
|
|
119
|
+
* `enableJsonResponse: true` → the whole JSON-RPC response is buffered into the
|
|
120
|
+
* returned `Response`, so closing the transport/server afterwards can't truncate
|
|
121
|
+
* an in-flight body. Cleanup is fire-and-forget with swallowed rejections (a
|
|
122
|
+
* `.catch()`-terminated chain) so it never delays or masks the resolved response.
|
|
123
|
+
*
|
|
124
|
+
* `options.parsedBody` lets a caller hand over a body it already read (e.g. the
|
|
125
|
+
* paid-tool gate, which peeks the JSON-RPC message to price the call) so the
|
|
126
|
+
* transport doesn't re-read a consumed stream.
|
|
127
|
+
*
|
|
128
|
+
* Teardown runs in a `finally`: a rejection from `connect` or `handleRequest`
|
|
129
|
+
* would otherwise skip it and leak a server + transport per failed request,
|
|
130
|
+
* which on a public endpoint is exactly the request an attacker can repeat.
|
|
131
|
+
*/
|
|
132
|
+
declare const serveStateless: (server: Server, request: Request, options?: HandleRequestOptions) => Promise<Response>;
|
|
133
|
+
export { McpResourceProvider as M, ToolDefinition as T, McpFetchHandler as a, McpTool as b, McpResourceSummary as c, McpServerInfo as d, ToolInputSchema as e, ToolResult as f, createToolServer as g, serveStateless as s };
|
|
@@ -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.
|
|
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",
|
|
@@ -43,14 +43,28 @@
|
|
|
43
43
|
"types": "./dist/index.d.ts",
|
|
44
44
|
"import": "./dist/index.mjs"
|
|
45
45
|
},
|
|
46
|
+
"./docs": {
|
|
47
|
+
"types": "./dist/docs/index.d.ts",
|
|
48
|
+
"import": "./dist/docs/index.mjs"
|
|
49
|
+
},
|
|
46
50
|
"./package.json": "./package.json"
|
|
47
51
|
},
|
|
48
52
|
"publishConfig": {
|
|
49
53
|
"access": "public"
|
|
50
54
|
},
|
|
51
55
|
"dependencies": {
|
|
52
|
-
"@lunora/client": "1.0.0-alpha.
|
|
53
|
-
"@
|
|
56
|
+
"@lunora/client": "1.0.0-alpha.50",
|
|
57
|
+
"@lunora/errors": "1.0.0-alpha.21",
|
|
58
|
+
"@lunora/shard-engine": "1.0.0-alpha.27",
|
|
59
|
+
"@modelcontextprotocol/sdk": "^1.30.0"
|
|
60
|
+
},
|
|
61
|
+
"peerDependencies": {
|
|
62
|
+
"@lunora/x402": ">=1.0.0-alpha.21 <2.0.0-0"
|
|
63
|
+
},
|
|
64
|
+
"peerDependenciesMeta": {
|
|
65
|
+
"@lunora/x402": {
|
|
66
|
+
"optional": true
|
|
67
|
+
}
|
|
54
68
|
},
|
|
55
69
|
"engines": {
|
|
56
70
|
"node": "^22.15.0 || >=24.11.0"
|
|
@@ -1,112 +0,0 @@
|
|
|
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 };
|
|
@@ -1,64 +0,0 @@
|
|
|
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 };
|