@node-in-layers/mcp-server 2.4.0 → 2.5.0
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 +3 -1
- package/internal-libs.d.ts +29 -0
- package/internal-libs.js +184 -0
- package/internal-libs.js.map +1 -0
- package/libs.d.ts +3 -1
- package/libs.js +52 -2
- package/libs.js.map +1 -1
- package/mcp.d.ts +0 -6
- package/mcp.js +209 -92
- package/mcp.js.map +1 -1
- package/models.d.ts +86 -22
- package/models.js +2 -2
- package/models.js.map +1 -1
- package/nil.d.ts +83 -19
- package/nil.js +2 -2
- package/nil.js.map +1 -1
- package/package.json +14 -7
- package/types.d.ts +508 -54
- package/types.js +14 -0
- package/types.js.map +1 -1
- package/utils.d.ts +21 -0
- package/utils.js +33 -0
- package/utils.js.map +1 -0
package/types.d.ts
CHANGED
|
@@ -1,161 +1,615 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { Config, LogLevelNames, LayerContext } from '@node-in-layers/core';
|
|
5
|
-
import { Express } from 'express';
|
|
1
|
+
import { CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
import { Config, LogLevelNames, LayerContext, XOR, CrossLayerProps } from '@node-in-layers/core';
|
|
3
|
+
import express from 'express';
|
|
6
4
|
import { JsonAble } from 'functional-models';
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The namespace key used to scope all `@node-in-layers/mcp-server` configuration
|
|
7
|
+
* inside the system config object.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* const config = {
|
|
12
|
+
* [McpNamespace]: {
|
|
13
|
+
* version: '1.0.0',
|
|
14
|
+
* server: { connection: { type: 'http', url: 'http://localhost:3000' } },
|
|
15
|
+
* },
|
|
16
|
+
* }
|
|
17
|
+
* ```
|
|
18
|
+
*/
|
|
19
|
+
export declare const McpNamespace = "@node-in-layers/mcp-server";
|
|
20
|
+
/**
|
|
21
|
+
* @interface
|
|
22
|
+
* CLI (stdio) connection configuration. Use this when the MCP server is
|
|
23
|
+
* launched as a subprocess and communicates over stdin/stdout.
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const connection: CliConnection = { type: 'cli' }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export type CliConnection = Readonly<{
|
|
31
|
+
type: 'cli';
|
|
32
|
+
}>;
|
|
33
|
+
/**
|
|
34
|
+
* @interface
|
|
35
|
+
* HTTP connection configuration. Use this when the MCP server is exposed over
|
|
36
|
+
* a network via the Streamable HTTP transport.
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* const connection: HttpConnection = {
|
|
41
|
+
* type: 'http',
|
|
42
|
+
* url: 'http://localhost:3000/mcp',
|
|
43
|
+
* headers: { 'x-api-key': 'secret' },
|
|
44
|
+
* timeout: 5000,
|
|
45
|
+
* retry: { attempts: 3, backoff: 500 },
|
|
46
|
+
* }
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export type HttpConnection = Readonly<{
|
|
50
|
+
type: 'http';
|
|
51
|
+
/** Base URL of the MCP HTTP endpoint (e.g. `http://localhost:3000/mcp`). */
|
|
52
|
+
url: string;
|
|
53
|
+
/** Static headers sent with every request to the server. */
|
|
54
|
+
headers?: Readonly<Record<string, string>>;
|
|
55
|
+
/** Request timeout in milliseconds. */
|
|
56
|
+
timeout?: number;
|
|
57
|
+
/** Retry policy for failed requests. */
|
|
58
|
+
retry?: Readonly<{
|
|
59
|
+
/** Number of retry attempts before giving up. */
|
|
60
|
+
attempts: number;
|
|
61
|
+
/** Base backoff interval in milliseconds between retries. */
|
|
62
|
+
backoff: number;
|
|
63
|
+
}>;
|
|
64
|
+
}>;
|
|
65
|
+
/**
|
|
66
|
+
* A discriminated union of the supported MCP transport connections.
|
|
67
|
+
* Exactly one of `CliConnection` or `HttpConnection` must be provided.
|
|
68
|
+
*
|
|
69
|
+
* @see {@link CliConnection}
|
|
70
|
+
* @see {@link HttpConnection}
|
|
71
|
+
*/
|
|
72
|
+
export type Connection = XOR<CliConnection, HttpConnection>;
|
|
73
|
+
/**
|
|
74
|
+
* @interface
|
|
75
|
+
* A named example of system usage, shown in the `START_HERE` tool response to
|
|
76
|
+
* give AI clients concrete guidance on how to use the system.
|
|
77
|
+
*/
|
|
12
78
|
export type SystemUseExample = Readonly<{
|
|
79
|
+
/** Short label for the example (e.g. `"Create a user"`). */
|
|
13
80
|
name: string;
|
|
81
|
+
/** One-sentence description of what the example demonstrates. */
|
|
14
82
|
description?: string;
|
|
83
|
+
/** A representative value or input to show. */
|
|
15
84
|
value?: string;
|
|
85
|
+
/** Optional tags for categorisation. */
|
|
16
86
|
tags?: string[];
|
|
87
|
+
/** Longer free-form explanation. */
|
|
17
88
|
details?: string;
|
|
89
|
+
/** Concrete example payload or invocation. */
|
|
18
90
|
example?: string;
|
|
19
91
|
}>;
|
|
20
92
|
/**
|
|
21
|
-
* Configuration for the MCP server.
|
|
22
93
|
* @interface
|
|
94
|
+
* Top-level configuration for the `@node-in-layers/mcp-server` package.
|
|
95
|
+
* Placed under the `McpNamespace` key inside the system config.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```ts
|
|
99
|
+
* const config: McpServerConfig = {
|
|
100
|
+
* [McpNamespace]: {
|
|
101
|
+
* version: '1.0.0',
|
|
102
|
+
* stateful: false,
|
|
103
|
+
* server: {
|
|
104
|
+
* connection: { type: 'http', url: 'http://localhost:3000' },
|
|
105
|
+
* },
|
|
106
|
+
* },
|
|
107
|
+
* }
|
|
108
|
+
* ```
|
|
23
109
|
*/
|
|
24
110
|
export type McpServerConfig = Readonly<{
|
|
25
111
|
[McpNamespace]: {
|
|
26
112
|
/**
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
name?: string;
|
|
30
|
-
/**
|
|
31
|
-
* The version of the MCP server.
|
|
113
|
+
* Semver string reported by the MCP server during the initialize handshake.
|
|
114
|
+
* Defaults to `'1.0.0'` if omitted.
|
|
32
115
|
*/
|
|
33
116
|
version?: string;
|
|
34
117
|
/**
|
|
35
|
-
*
|
|
118
|
+
* When `true` the HTTP transport manages persistent sessions (one
|
|
119
|
+
* `McpServer` instance per session). When `false` (the default) each
|
|
120
|
+
* HTTP request spins up a fresh server instance (stateless mode).
|
|
121
|
+
*
|
|
122
|
+
* Stateful mode is required when you need server-sent events or long-lived
|
|
123
|
+
* session state. Stateless mode is simpler and works well for most REST-style
|
|
124
|
+
* AI tool calls.
|
|
36
125
|
*/
|
|
37
|
-
|
|
126
|
+
stateful?: boolean;
|
|
38
127
|
/**
|
|
39
|
-
*
|
|
128
|
+
* Transport configuration. Must specify a `connection` that selects either
|
|
129
|
+
* CLI (stdio) or HTTP transport.
|
|
40
130
|
*/
|
|
41
131
|
server: {
|
|
42
132
|
/**
|
|
43
|
-
*
|
|
133
|
+
* Transport connection — either `{ type: 'cli' }` or
|
|
134
|
+
* `{ type: 'http', url: '...', ... }`.
|
|
135
|
+
*
|
|
136
|
+
* @see {@link Connection}
|
|
44
137
|
*/
|
|
45
138
|
connection: Connection;
|
|
46
139
|
};
|
|
47
140
|
/**
|
|
48
|
-
* Configuration for the
|
|
141
|
+
* Configuration for the built-in `START_HERE` tool.
|
|
142
|
+
* This tool is always registered and is the recommended first call for any
|
|
143
|
+
* AI client — it returns a system overview that helps the client navigate
|
|
144
|
+
* the available domains, features, and models.
|
|
49
145
|
*/
|
|
50
146
|
startHere?: {
|
|
51
147
|
/**
|
|
52
|
-
*
|
|
148
|
+
* Override the tool name. Default: `'START_HERE'`.
|
|
53
149
|
*/
|
|
54
150
|
name?: string;
|
|
55
151
|
/**
|
|
56
|
-
*
|
|
152
|
+
* Override the tool description shown to the AI client.
|
|
57
153
|
*/
|
|
58
154
|
description?: string;
|
|
59
155
|
/**
|
|
60
|
-
*
|
|
156
|
+
* When `true`, suppresses the built-in Node-in-Layers navigation
|
|
157
|
+
* documentation from the response. Generally not recommended unless you
|
|
158
|
+
* are providing a completely custom system description.
|
|
61
159
|
*/
|
|
62
160
|
hideDefaultSystemEntries?: boolean;
|
|
63
161
|
/**
|
|
64
|
-
* When true
|
|
162
|
+
* When `true`, the response includes the domain list (equivalent to
|
|
163
|
+
* calling `list_domains` first).
|
|
65
164
|
*/
|
|
66
165
|
includeDomains?: boolean;
|
|
67
166
|
/**
|
|
68
|
-
* When true
|
|
167
|
+
* When `true`, the response includes the full feature list per domain
|
|
168
|
+
* (equivalent to calling `list_features` for every domain). Implies
|
|
169
|
+
* `includeDomains: true`.
|
|
69
170
|
*/
|
|
70
171
|
includeFeatures?: boolean;
|
|
71
172
|
/**
|
|
72
|
-
*
|
|
173
|
+
* Optional worked examples of end-to-end usage flows to include in the
|
|
174
|
+
* `START_HERE` response. Prefer JSON object examples with minimal prose.
|
|
175
|
+
*
|
|
176
|
+
* @see {@link SystemUseExample}
|
|
73
177
|
*/
|
|
74
178
|
examplesOfUse?: ReadonlyArray<SystemUseExample>;
|
|
75
179
|
};
|
|
76
180
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
181
|
+
* @deprecated Use `hideComponents` instead.
|
|
182
|
+
* Dot-path strings of tools/domains to suppress.
|
|
79
183
|
*/
|
|
80
184
|
hiddenPaths?: string[];
|
|
81
185
|
/**
|
|
82
|
-
*
|
|
186
|
+
* Fine-grained control over which tools are exposed to AI clients.
|
|
187
|
+
* All suppressed items are completely omitted — they will not appear in
|
|
188
|
+
* tool listings or `START_HERE` output.
|
|
189
|
+
*
|
|
190
|
+
* Dot-path format for `paths`:
|
|
191
|
+
* - `'myDomain'` — hides the entire domain and all its features/models.
|
|
192
|
+
* - `'myDomain.myFeature'` — hides one specific feature.
|
|
193
|
+
* - `'myDomain.cruds'` — hides all model CRUD tools for a domain.
|
|
194
|
+
* - `'myDomain.cruds.MyModel'` — hides CRUD tools for one specific model.
|
|
83
195
|
*/
|
|
84
196
|
hideComponents?: {
|
|
85
197
|
/**
|
|
86
|
-
* Dot
|
|
87
|
-
*
|
|
88
|
-
* myDomain - hides an entire domain.
|
|
89
|
-
* myDomain.myFeature - hides a feature.
|
|
90
|
-
* myDomain.cruds - hides ALL models of the domain
|
|
91
|
-
* myDomain.cruds.MyModel - hides a specific model
|
|
198
|
+
* Dot-path strings identifying individual tools, features, or model CRUD
|
|
199
|
+
* groups to suppress.
|
|
92
200
|
*/
|
|
93
201
|
paths?: ReadonlyArray<string>;
|
|
94
202
|
/**
|
|
95
|
-
*
|
|
203
|
+
* Domain names to hide entirely (domain will not appear in `list_domains`).
|
|
96
204
|
*/
|
|
97
205
|
domains?: string[];
|
|
98
206
|
/**
|
|
99
|
-
*
|
|
100
|
-
* This will not show any tools related to models.
|
|
207
|
+
* When `true`, suppresses ALL model CRUD tools across every domain.
|
|
101
208
|
*/
|
|
102
209
|
allModels?: boolean;
|
|
103
210
|
};
|
|
104
211
|
/**
|
|
105
|
-
* Static
|
|
212
|
+
* Static metadata injected into the `START_HERE` response.
|
|
106
213
|
*/
|
|
107
214
|
systemDescription?: {
|
|
215
|
+
/** Human-readable description of the system shown to the AI client. */
|
|
108
216
|
description?: string;
|
|
217
|
+
/** System version string shown to the AI client. */
|
|
109
218
|
version?: string;
|
|
110
219
|
};
|
|
111
220
|
/**
|
|
112
|
-
* Logging configuration.
|
|
221
|
+
* Logging configuration for inbound tool calls and their responses.
|
|
222
|
+
* All logging uses the Node-in-Layers logger already present in the context.
|
|
113
223
|
*/
|
|
114
224
|
logging?: {
|
|
115
225
|
/**
|
|
116
|
-
*
|
|
226
|
+
* Log level used when logging the incoming tool request.
|
|
227
|
+
* Defaults to `'info'`.
|
|
228
|
+
* One of the `LogLevelNames` string literals from `@node-in-layers/core`
|
|
229
|
+
* (e.g. `'info'`, `'warn'`, `'error'`, `'debug'`).
|
|
117
230
|
*/
|
|
118
231
|
requestLogLevel?: LogLevelNames;
|
|
119
232
|
/**
|
|
120
|
-
*
|
|
233
|
+
* Log level used when logging the tool response.
|
|
234
|
+
* Defaults to `'info'`.
|
|
235
|
+
* One of the `LogLevelNames` string literals from `@node-in-layers/core`
|
|
236
|
+
* (e.g. `'info'`, `'warn'`, `'error'`, `'debug'`).
|
|
121
237
|
*/
|
|
122
238
|
responseLogLevel?: LogLevelNames;
|
|
123
239
|
/**
|
|
124
|
-
*
|
|
240
|
+
* Optional callback that extracts additional structured fields to merge
|
|
241
|
+
* into the request log entry. Return a plain object of key/value pairs.
|
|
125
242
|
*/
|
|
126
243
|
requestLogGetData?: (req: Request) => Record<string, any>;
|
|
127
244
|
/**
|
|
128
|
-
*
|
|
245
|
+
* Optional callback that extracts additional structured fields to merge
|
|
246
|
+
* into the response log entry. Return a plain object of key/value pairs.
|
|
129
247
|
*/
|
|
130
248
|
responseLogGetData?: (req: Request) => Record<string, any>;
|
|
131
249
|
};
|
|
132
250
|
};
|
|
133
251
|
}>;
|
|
134
|
-
|
|
252
|
+
/**
|
|
253
|
+
* @interface
|
|
254
|
+
* Schema-only metadata for an MCP tool — everything except the `execute`
|
|
255
|
+
* handler. Used when building tool definitions before the execute function is
|
|
256
|
+
* attached (e.g. in `nil.ts` / `models.ts` helper factories).
|
|
257
|
+
*
|
|
258
|
+
* @see {@link McpTool}
|
|
259
|
+
*/
|
|
260
|
+
export type McpToolSchema = Readonly<{
|
|
261
|
+
/** Unique tool name as it appears in the MCP tool listing. */
|
|
262
|
+
name: string;
|
|
263
|
+
/** Description shown to the AI client to explain what this tool does. */
|
|
264
|
+
description?: string;
|
|
265
|
+
/**
|
|
266
|
+
* JSON Schema (or Zod schema) describing the tool's input object.
|
|
267
|
+
* The SDK validates incoming tool calls against this schema before invoking
|
|
268
|
+
* the execute handler.
|
|
269
|
+
*/
|
|
270
|
+
inputSchema: any;
|
|
271
|
+
/**
|
|
272
|
+
* Optional JSON Schema describing the tool's output object.
|
|
273
|
+
* Provided for documentation/type-generation purposes; the MCP SDK does not
|
|
274
|
+
* currently enforce it at runtime.
|
|
275
|
+
*/
|
|
276
|
+
outputSchema?: any;
|
|
277
|
+
}>;
|
|
278
|
+
/**
|
|
279
|
+
* @interface
|
|
280
|
+
* A fully-defined MCP tool: schema metadata plus an execute handler.
|
|
281
|
+
*
|
|
282
|
+
* The `execute` function is called by the server for every matching tool
|
|
283
|
+
* invocation. The second argument (`crossLayerProps`) carries the merged
|
|
284
|
+
* {@link RequestCrossLayerProps} for the request, including `requestInfo`,
|
|
285
|
+
* `authInfo`, and logger correlation IDs.
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```ts
|
|
289
|
+
* const myTool: McpTool = {
|
|
290
|
+
* name: 'greet',
|
|
291
|
+
* description: 'Returns a greeting.',
|
|
292
|
+
* inputSchema: { type: 'object', properties: { name: { type: 'string' } } },
|
|
293
|
+
* execute: async (input, crossLayerProps) => createMcpResponse({ hello: input.name }),
|
|
294
|
+
* }
|
|
295
|
+
* ```
|
|
296
|
+
*
|
|
297
|
+
* @see {@link McpToolSchema}
|
|
298
|
+
* @see {@link RequestCrossLayerProps}
|
|
299
|
+
*/
|
|
300
|
+
export type McpTool = McpToolSchema & Readonly<{
|
|
301
|
+
/**
|
|
302
|
+
* Async handler invoked for each tool call.
|
|
303
|
+
*
|
|
304
|
+
* @param input - The validated tool arguments as received from the AI client.
|
|
305
|
+
* Will always contain a `crossLayerProps` field injected by the server
|
|
306
|
+
* (merged from the client-supplied value, the HTTP transport headers, and
|
|
307
|
+
* auth info).
|
|
308
|
+
* @param crossLayerProps - The fully-merged {@link RequestCrossLayerProps} for
|
|
309
|
+
* this request. Passed as a convenience — identical to `input.crossLayerProps`.
|
|
310
|
+
*/
|
|
311
|
+
execute: (input: any, crossLayerProps?: any) => Promise<CallToolResult>;
|
|
312
|
+
}>;
|
|
313
|
+
/**
|
|
314
|
+
* @interface
|
|
315
|
+
* An additional Express route to mount on the HTTP server alongside the MCP
|
|
316
|
+
* endpoint. Useful for health checks, webhooks, or any non-MCP HTTP traffic
|
|
317
|
+
* that should share the same process.
|
|
318
|
+
*
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* const healthRoute: ExpressRoute = {
|
|
322
|
+
* path: '/health',
|
|
323
|
+
* method: 'GET',
|
|
324
|
+
* handler: async (_req, res) => { res.json({ ok: true }) },
|
|
325
|
+
* }
|
|
326
|
+
* ```
|
|
327
|
+
*/
|
|
328
|
+
export type ExpressRoute = Readonly<{
|
|
329
|
+
/** URL path for the route (e.g. `'/health'`). */
|
|
330
|
+
path: string;
|
|
331
|
+
/** HTTP method for the route. */
|
|
332
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
333
|
+
/** Async Express request handler. */
|
|
334
|
+
handler: (req: express.Request, res: express.Response) => Promise<void>;
|
|
335
|
+
}>;
|
|
336
|
+
/**
|
|
337
|
+
* An Express middleware function to mount before the MCP route handler.
|
|
338
|
+
* Standard use-cases include authentication, request logging, and rate limiting.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* const authMiddleware: ExpressMiddleware = async (req, res, next) => {
|
|
343
|
+
* if (!req.headers.authorization) {
|
|
344
|
+
* res.status(401).json({ error: 'Unauthorized' })
|
|
345
|
+
* return
|
|
346
|
+
* }
|
|
347
|
+
* await next()
|
|
348
|
+
* }
|
|
349
|
+
* ```
|
|
350
|
+
*/
|
|
351
|
+
export type ExpressMiddleware = (req: express.Request, res: express.Response, next: express.NextFunction) => Promise<void>;
|
|
352
|
+
/**
|
|
353
|
+
* @interface
|
|
354
|
+
* Full Express configuration accepted when building the HTTP app via
|
|
355
|
+
* `getApp()` or `start()`.
|
|
356
|
+
*
|
|
357
|
+
* @see {@link McpServerMcp.getApp}
|
|
358
|
+
*/
|
|
359
|
+
export type ExpressOptions = Readonly<{
|
|
360
|
+
/** Additional routes to mount on the Express app. @see {@link ExpressRoute} */
|
|
361
|
+
additionalRoutes?: ExpressRoute[];
|
|
362
|
+
/** Middleware to run before the MCP route handler. @see {@link ExpressMiddleware} */
|
|
363
|
+
preRouteMiddleware?: ExpressMiddleware[];
|
|
364
|
+
/**
|
|
365
|
+
* Optional callback invoked after every route handler completes.
|
|
366
|
+
* Useful for post-request instrumentation or cleanup.
|
|
367
|
+
*/
|
|
368
|
+
afterRouteCallback?: (req: express.Request, res: express.Response) => Promise<void> | void;
|
|
369
|
+
/** Body-size limit forwarded to `body-parser` (e.g. `'10mb'`). */
|
|
370
|
+
limit?: string;
|
|
371
|
+
/** Fine-grained options passed directly to `bodyParser.json()`. */
|
|
372
|
+
jsonBodyParser?: {
|
|
373
|
+
/** Maximum request body size (e.g. `'1mb'`). */
|
|
374
|
+
limit?: string;
|
|
375
|
+
/** When `false`, allows non-object/array JSON at the top level. */
|
|
376
|
+
strict?: boolean;
|
|
377
|
+
};
|
|
378
|
+
}>;
|
|
379
|
+
/**
|
|
380
|
+
* @interface
|
|
381
|
+
* Subset of {@link ExpressOptions} accepted by `start()` and `getApp()` on the
|
|
382
|
+
* public API. Currently covers only the `jsonBodyParser` settings; additional
|
|
383
|
+
* options (routes, middleware) are registered via dedicated methods instead.
|
|
384
|
+
*
|
|
385
|
+
* @see {@link McpServerMcp.start}
|
|
386
|
+
* @see {@link McpServerMcp.getApp}
|
|
387
|
+
*/
|
|
388
|
+
export type AppOptions = Readonly<{
|
|
389
|
+
/** Fine-grained options passed directly to `bodyParser.json()`. */
|
|
390
|
+
jsonBodyParser?: {
|
|
391
|
+
/** Maximum request body size (e.g. `'1mb'`). */
|
|
392
|
+
limit?: string;
|
|
393
|
+
/** When `false`, allows non-object/array JSON at the top level. */
|
|
394
|
+
strict?: boolean;
|
|
395
|
+
};
|
|
396
|
+
}>;
|
|
397
|
+
/**
|
|
398
|
+
* @interface
|
|
399
|
+
* HTTP request metadata extracted from the MCP transport layer and made
|
|
400
|
+
* available to every tool call via {@link RequestCrossLayerProps}.
|
|
401
|
+
*
|
|
402
|
+
* For HTTP connections, `headers` is populated from the live HTTP request
|
|
403
|
+
* (via the MCP SDK's `RequestHandlerExtra.requestInfo`). The remaining fields
|
|
404
|
+
* (`body`, `query`, `params`, `path`, `method`, `url`, `protocol`) are
|
|
405
|
+
* populated when an Express request is available; for CLI (stdio) connections
|
|
406
|
+
* they default to empty strings / empty objects.
|
|
407
|
+
*/
|
|
408
|
+
export type RequestInfo = Readonly<{
|
|
409
|
+
/** Normalised HTTP request headers (all values coerced to strings). */
|
|
410
|
+
headers: Record<string, string>;
|
|
411
|
+
/** Parsed request body (JSON object). Empty object for CLI connections. */
|
|
412
|
+
body: Record<string, any>;
|
|
413
|
+
/** Parsed query-string parameters. Empty object for CLI connections. */
|
|
414
|
+
query: Record<string, string>;
|
|
415
|
+
/** URL path parameters (e.g. from `/users/:id`). Empty object for CLI connections. */
|
|
416
|
+
params: Record<string, string>;
|
|
417
|
+
/** URL path component (e.g. `'/mcp'`). Empty string for CLI connections. */
|
|
418
|
+
path: string;
|
|
419
|
+
/** HTTP method in upper-case (e.g. `'POST'`). Empty string for CLI connections. */
|
|
420
|
+
method: string;
|
|
421
|
+
/** Full request URL including query string. Empty string for CLI connections. */
|
|
422
|
+
url: string;
|
|
423
|
+
/** Protocol (e.g. `'http'` or `'https'`). Empty string for CLI connections. */
|
|
424
|
+
protocol: string;
|
|
425
|
+
}>;
|
|
426
|
+
/**
|
|
427
|
+
* @interface
|
|
428
|
+
* OAuth / token auth information for the current request, sourced from the
|
|
429
|
+
* MCP SDK's `RequestHandlerExtra.authInfo`. Only present when the MCP server
|
|
430
|
+
* is configured with an OAuth provider and the client has authenticated.
|
|
431
|
+
*
|
|
432
|
+
* @see {@link RequestCrossLayerProps}
|
|
433
|
+
*/
|
|
434
|
+
export type AuthInfo = Readonly<{
|
|
435
|
+
/** The raw bearer access token string. */
|
|
436
|
+
token: string;
|
|
437
|
+
/** The OAuth client ID that obtained this token. */
|
|
438
|
+
clientId: string;
|
|
439
|
+
/** Scopes granted to this token (e.g. `['read', 'write']`). */
|
|
440
|
+
scopes: string[];
|
|
441
|
+
/**
|
|
442
|
+
* Unix timestamp (seconds since epoch) at which the token expires.
|
|
443
|
+
* Omitted if the token has no expiry.
|
|
444
|
+
*/
|
|
445
|
+
expiresAt?: number;
|
|
446
|
+
/**
|
|
447
|
+
* The RFC 8707 resource server identifier for which this token is valid.
|
|
448
|
+
* When set, must match the MCP server's own resource identifier.
|
|
449
|
+
*/
|
|
450
|
+
resource?: URL;
|
|
451
|
+
/** Any additional provider-specific data attached to the token. */
|
|
452
|
+
extra?: Record<string, unknown>;
|
|
453
|
+
}>;
|
|
454
|
+
/**
|
|
455
|
+
* @interface
|
|
456
|
+
* The cross-layer props shape used throughout `@node-in-layers/mcp-server`.
|
|
457
|
+
* Extends the base `CrossLayerProps` from `@node-in-layers/core` with MCP-specific request context.
|
|
458
|
+
*
|
|
459
|
+
* This object is automatically built and merged by the server on every tool
|
|
460
|
+
* call — you should never construct it manually. Use `combineCrossLayerProps`
|
|
461
|
+
* or `createCrossLayerProps` from `@node-in-layers/core` if you need to merge
|
|
462
|
+
* additional data into an existing instance.
|
|
463
|
+
*
|
|
464
|
+
* Sources merged into every tool call (in order):
|
|
465
|
+
* 1. `crossLayerProps` supplied by the AI client in the tool arguments
|
|
466
|
+
* 2. `crossLayerProps` nested inside `args` (used by feature-executor tools)
|
|
467
|
+
* 3. `requestInfo` from the HTTP transport (headers) and `authInfo` if present
|
|
468
|
+
* 4. Logger correlation IDs from the per-request logger
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```ts
|
|
472
|
+
* // Accessing in a feature function:
|
|
473
|
+
* const myFeature = async (args: MyArgs, crossLayerProps: McpCrossLayerProps) => {
|
|
474
|
+
* const { headers } = crossLayerProps.requestInfo
|
|
475
|
+
* const token = crossLayerProps.authInfo?.token
|
|
476
|
+
* // ...
|
|
477
|
+
* }
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* @see {@link RequestInfo}
|
|
481
|
+
* @see {@link AuthInfo}
|
|
482
|
+
*/
|
|
483
|
+
export type RequestCrossLayerProps = Readonly<{
|
|
484
|
+
/** HTTP request metadata for the current tool call. @see {@link RequestInfo} */
|
|
485
|
+
requestInfo: RequestInfo;
|
|
486
|
+
/**
|
|
487
|
+
* OAuth auth info for the current request, if the server is configured with
|
|
488
|
+
* an OAuth provider and the client has authenticated.
|
|
489
|
+
* @see {@link AuthInfo}
|
|
490
|
+
*/
|
|
491
|
+
authInfo?: AuthInfo;
|
|
492
|
+
}> & CrossLayerProps;
|
|
493
|
+
/**
|
|
494
|
+
* @interface
|
|
495
|
+
* The public interface returned by `create()` in `mcp.ts` and stored in the
|
|
496
|
+
* MCP layer of the Node-in-Layers system context.
|
|
497
|
+
*
|
|
498
|
+
* Typical usage:
|
|
499
|
+
* ```ts
|
|
500
|
+
* const mcpServer = mcp.create(context)
|
|
501
|
+
* mcpServer.addTool(myTool)
|
|
502
|
+
* await mcpServer.start(systemContext)
|
|
503
|
+
* ```
|
|
504
|
+
*/
|
|
135
505
|
export type McpServerMcp = Readonly<{
|
|
506
|
+
/**
|
|
507
|
+
* Starts the MCP server. For HTTP connections, binds an Express app to the
|
|
508
|
+
* configured port. For CLI connections, connects the stdio transport.
|
|
509
|
+
*
|
|
510
|
+
* @param systemContext - The fully-initialised Node-in-Layers system context,
|
|
511
|
+
* used to resolve features and models at runtime.
|
|
512
|
+
* @param options - Optional Express body-parser settings.
|
|
513
|
+
*/
|
|
136
514
|
start: <T extends McpServerConfig & Config>(systemContext: LayerContext<T, any>, options?: AppOptions) => Promise<void>;
|
|
137
|
-
|
|
138
|
-
|
|
515
|
+
/**
|
|
516
|
+
* Registers a custom {@link McpTool} with the server. Call this before
|
|
517
|
+
* `start()` or `getApp()`.
|
|
518
|
+
*
|
|
519
|
+
* @param tool - The tool definition to register.
|
|
520
|
+
*/
|
|
521
|
+
addTool: (tool: McpTool) => void;
|
|
522
|
+
/**
|
|
523
|
+
* Builds and returns the configured Express app without starting the HTTP
|
|
524
|
+
* listener. Useful when you want to integrate the MCP server into an existing
|
|
525
|
+
* Express application or test the app directly.
|
|
526
|
+
*
|
|
527
|
+
* Throws if the connection type is not `'http'`.
|
|
528
|
+
*
|
|
529
|
+
* @param systemContext - The fully-initialised Node-in-Layers system context.
|
|
530
|
+
* @param options - Optional Express body-parser settings.
|
|
531
|
+
*/
|
|
532
|
+
getApp: <T extends McpServerConfig & Config>(systemContext: LayerContext<T, any>, options?: AppOptions) => Promise<express.Express>;
|
|
533
|
+
/**
|
|
534
|
+
* Calls `app.set(key, value)` on the underlying Express app. Must be called
|
|
535
|
+
* before `start()` or `getApp()`.
|
|
536
|
+
*
|
|
537
|
+
* @param key - Express setting name (e.g. `'trust proxy'`).
|
|
538
|
+
* @param value - Value to assign.
|
|
539
|
+
*/
|
|
139
540
|
set: (key: string, value: any) => void;
|
|
541
|
+
/**
|
|
542
|
+
* Registers an Express middleware to run before the MCP route handler.
|
|
543
|
+
* Useful for auth, logging, or rate-limiting. Must be called before
|
|
544
|
+
* `start()` or `getApp()`.
|
|
545
|
+
*
|
|
546
|
+
* @param middleware - An {@link ExpressMiddleware} function.
|
|
547
|
+
*/
|
|
140
548
|
addPreRouteMiddleware: (middleware: ExpressMiddleware) => void;
|
|
549
|
+
/**
|
|
550
|
+
* Registers an additional Express route alongside the MCP endpoint. Must be
|
|
551
|
+
* called before `start()` or `getApp()`.
|
|
552
|
+
*
|
|
553
|
+
* @param route - An {@link ExpressRoute} definition.
|
|
554
|
+
*/
|
|
141
555
|
addAdditionalRoute: (route: ExpressRoute) => void;
|
|
142
556
|
}>;
|
|
557
|
+
/**
|
|
558
|
+
* @interface
|
|
559
|
+
* The MCP layer slice of the Node-in-Layers system context, keyed by
|
|
560
|
+
* {@link McpNamespace}.
|
|
561
|
+
*/
|
|
143
562
|
export type McpServerMcpLayer = Readonly<{
|
|
144
563
|
[McpNamespace]: McpServerMcp;
|
|
145
564
|
}>;
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
565
|
+
/**
|
|
566
|
+
* The full Node-in-Layers `LayerContext` shape expected by MCP server
|
|
567
|
+
* internals. Parameterised over config, features, and any additional MCP-layer
|
|
568
|
+
* services the consuming application adds.
|
|
569
|
+
*
|
|
570
|
+
* @template TConfig - System config type (must extend `Config`).
|
|
571
|
+
* @template TFeatures - Features layer shape (domain → feature functions).
|
|
572
|
+
* @template TMcpLayer - Any additional entries in the MCP layer beyond the
|
|
573
|
+
* built-in `McpServerMcpLayer`.
|
|
574
|
+
*/
|
|
152
575
|
export type McpContext<TConfig extends Config = Config, TFeatures extends object = object, TMcpLayer extends object = object> = LayerContext<TConfig, {
|
|
153
576
|
features: TFeatures;
|
|
154
577
|
mcp: McpServerMcpLayer & TMcpLayer;
|
|
155
578
|
}>;
|
|
579
|
+
/**
|
|
580
|
+
* @interface
|
|
581
|
+
* A simplified OpenAPI-style description of a single function, used to
|
|
582
|
+
* generate tool input/output schemas for non-NIL-annotated features.
|
|
583
|
+
*/
|
|
156
584
|
export type OpenApiFunctionDescription = Readonly<{
|
|
585
|
+
/** Function name as it appears in the tool listing. */
|
|
157
586
|
name: string;
|
|
587
|
+
/** Optional description shown to the AI client. */
|
|
158
588
|
description?: string;
|
|
589
|
+
/** JSON Schema object describing the function's input. */
|
|
159
590
|
input: Record<string, JsonAble>;
|
|
591
|
+
/** JSON Schema object describing the function's output. */
|
|
160
592
|
output: Record<string, JsonAble>;
|
|
161
593
|
}>;
|
|
594
|
+
/**
|
|
595
|
+
* @interface
|
|
596
|
+
* A lightweight optional-value container (similar to `Option<T>` in functional
|
|
597
|
+
* languages). Avoids returning `null` / `undefined` directly from functions
|
|
598
|
+
* that may not produce a value.
|
|
599
|
+
*
|
|
600
|
+
* @template T - The type of the wrapped value.
|
|
601
|
+
*
|
|
602
|
+
* @example
|
|
603
|
+
* ```ts
|
|
604
|
+
* const maybeUser: Maybe<User> = findUser(id)
|
|
605
|
+
* if (maybeUser.hasValue()) {
|
|
606
|
+
* const user = maybeUser.instance()
|
|
607
|
+
* }
|
|
608
|
+
* ```
|
|
609
|
+
*/
|
|
610
|
+
export type Maybe<T> = Readonly<{
|
|
611
|
+
/** Returns the wrapped value, or `undefined` if absent. */
|
|
612
|
+
instance: () => T | undefined;
|
|
613
|
+
/** Returns `true` if a value is present. */
|
|
614
|
+
hasValue: () => boolean;
|
|
615
|
+
}>;
|
package/types.js
CHANGED
|
@@ -1,2 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The namespace key used to scope all `@node-in-layers/mcp-server` configuration
|
|
3
|
+
* inside the system config object.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```ts
|
|
7
|
+
* const config = {
|
|
8
|
+
* [McpNamespace]: {
|
|
9
|
+
* version: '1.0.0',
|
|
10
|
+
* server: { connection: { type: 'http', url: 'http://localhost:3000' } },
|
|
11
|
+
* },
|
|
12
|
+
* }
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
1
15
|
export const McpNamespace = '@node-in-layers/mcp-server';
|
|
2
16
|
//# sourceMappingURL=types.js.map
|