@node-in-layers/mcp-server 2.3.1 → 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 +311 -109
- package/docs/node-in-layers-system.json +11 -5
- package/internal-libs.d.ts +29 -0
- package/internal-libs.js +184 -0
- package/internal-libs.js.map +1 -0
- package/libs.d.ts +8 -42
- 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 +99 -79
- package/models.js +2 -2
- package/models.js.map +1 -1
- package/nil.d.ts +96 -76
- package/nil.js +119 -44
- package/nil.js.map +1 -1
- package/package.json +14 -7
- package/types.d.ts +522 -51
- 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/README.md
CHANGED
|
@@ -1,149 +1,351 @@
|
|
|
1
1
|
# MCP Server - A Node In Layers Package for building MCP Servers
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A Node In Layers package for building MCP servers. It exposes your domains, features, and model CRUDs as MCP tools so an AI can discover and call them. Companion library: `@node-in-layers/mcp-client` (shared protocols for features, models, and tools).
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
This system is `self-describing` and automatically organizes tools into an optimized and efficient system, that reduces the total number of tools. This system also automatically includes prompting and examples that greatly increase AI tool selection and formatting accuracy in systems, to include in systems with hundreds, if not thousands of tools.
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
[API Docs](https://node-in-layers.github.io/mcp-server/)
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
---
|
|
10
10
|
|
|
11
|
-
##
|
|
11
|
+
## How To Use This
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
### 1. Install
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
```bash
|
|
16
|
+
npm install @node-in-layers/mcp-server
|
|
17
|
+
```
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
### 2. Configure
|
|
20
20
|
|
|
21
21
|
```typescript
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
// /config.base.mts
|
|
23
|
+
import { CoreNamespace } from '@node-in-layers/core'
|
|
24
|
+
import { McpNamespace, HttpConnection } from '@node-in-layers/mcp-server'
|
|
25
|
+
|
|
26
|
+
export default () => ({
|
|
27
|
+
systemName: 'your-system-name',
|
|
28
|
+
[CoreNamespace.root]: {
|
|
29
|
+
/* 1. Add to the Apps List */
|
|
30
|
+
apps: await Promise.all([
|
|
31
|
+
// Other Very Early Modules
|
|
32
|
+
//import('@node-in-layers/data/index.js'),
|
|
33
|
+
|
|
34
|
+
// Insert Here
|
|
35
|
+
import('@node-in-layers/mcp-server/index.js'),
|
|
36
|
+
|
|
37
|
+
// Insert Your Domains Here
|
|
38
|
+
]),
|
|
39
|
+
/* 2. Add mcp layer. NOTE: You must have entries between features and mcp */
|
|
40
|
+
layerOrder: ['services', 'features', ['entries', 'mcp']], // can also be ['entries', 'express', 'mcp']
|
|
34
41
|
},
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
/* 3. Add Mcp Server Configurations */
|
|
43
|
+
[McpNamespace]: {
|
|
44
|
+
// Required: The configuration of the server itself.
|
|
45
|
+
server: {
|
|
46
|
+
connection: {
|
|
47
|
+
type: 'http',
|
|
48
|
+
url: 'http://localhost',
|
|
49
|
+
port: 4000,
|
|
50
|
+
} as HttpConnection,
|
|
51
|
+
},
|
|
52
|
+
// Optional arguments go here.
|
|
41
53
|
},
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const config = {
|
|
45
|
-
['@node-in-layers/mcp-server']: mcpConfig,
|
|
46
|
-
}
|
|
54
|
+
})
|
|
47
55
|
```
|
|
48
56
|
|
|
49
|
-
###
|
|
57
|
+
### 3. What's Now Available
|
|
58
|
+
|
|
59
|
+
1. Features are automatically exposed (unless specifically hidden)
|
|
60
|
+
2. Model CRUDS are automatically exposed (unless specifically hidden)
|
|
61
|
+
3. An `mcp` layer is now available to features, and includes additional capabilities in the namespace: `McpNamespace`. (Explained later)
|
|
62
|
+
|
|
63
|
+
### 4. Run The Server
|
|
50
64
|
|
|
51
|
-
You can
|
|
65
|
+
You can very easily run the server in a simple script by doing the following:
|
|
52
66
|
|
|
53
67
|
```typescript
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
69
|
+
const system: System = (await core.loadSystem<SystemConfig>({
|
|
70
|
+
environment,
|
|
71
|
+
})) as any // "System" is your typed System object.
|
|
72
|
+
await system.mcp[McpNamespace].start(context)
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### Example with ./bin/mcp_server.mts file (feel free to copy paste)
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
#!/usr/bin/env tsx
|
|
79
|
+
|
|
80
|
+
import esMain from 'es-main'
|
|
81
|
+
import { ArgumentParser } from 'argparse'
|
|
82
|
+
import * as core from '@node-in-layers/core'
|
|
83
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
84
|
+
import { SystemConfig } from '../src/types.js'
|
|
85
|
+
import { System } from '../src/system/types.js'
|
|
86
|
+
|
|
87
|
+
const _parseArguments = () => {
|
|
88
|
+
const parser = new ArgumentParser({
|
|
89
|
+
description: 'Starts the MCP server.',
|
|
67
90
|
})
|
|
91
|
+
parser.add_argument('environment', {
|
|
92
|
+
help: 'The environment for the service.',
|
|
93
|
+
})
|
|
94
|
+
return parser.parse_args()
|
|
95
|
+
}
|
|
68
96
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
},
|
|
82
|
-
execute: (input: any) => {
|
|
83
|
-
// You get an object, pass it back to your feature. Handles async for you.
|
|
84
|
-
return context.features.yourDomain.yourFeature(input)
|
|
85
|
-
},
|
|
97
|
+
const startServer = async (environment: string) => {
|
|
98
|
+
const system = (await core.loadSystem<SystemConfig>({
|
|
99
|
+
environment,
|
|
100
|
+
})) as unknown as System
|
|
101
|
+
if (system.config[McpNamespace].server.connection.type === 'http') {
|
|
102
|
+
console.info(
|
|
103
|
+
`Starting MCP server on ${system.config[McpNamespace].server.connection.port}...`
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
process.on('SIGINT', async function () {
|
|
107
|
+
await system.services['@node-in-layers/data'].cleanup()
|
|
108
|
+
process.exit()
|
|
86
109
|
})
|
|
87
110
|
|
|
88
|
-
|
|
111
|
+
await system.mcp[McpNamespace].start(system)
|
|
89
112
|
}
|
|
90
113
|
|
|
91
|
-
|
|
114
|
+
if (esMain(import.meta)) {
|
|
115
|
+
const args = _parseArguments()
|
|
116
|
+
startServer(args.environment).catch((error: any) => {
|
|
117
|
+
console.error('Failed to start the server:', error)
|
|
118
|
+
process.exit(1)
|
|
119
|
+
})
|
|
120
|
+
}
|
|
92
121
|
```
|
|
93
122
|
|
|
94
|
-
|
|
123
|
+
## Background and How This Works
|
|
124
|
+
|
|
125
|
+
### MCP interface (domains, features, models)
|
|
126
|
+
|
|
127
|
+
The MCP tool surface is **organized by domain, then features and models**:
|
|
128
|
+
|
|
129
|
+
- **Domains** — The AI can list domains (`list_domains`), then for each domain list features (`list_features`) and (if present) list models. Only domains that have features or models exposed will be shown.
|
|
130
|
+
- **Features** — For a given domain/feature, the AI can get the schema (`describe_feature`) and run it (`execute_feature`).
|
|
131
|
+
- **Models** — For a given domain/model, the AI can get the schema and run save, retrieve, delete, search, bulkInsert, bulkDelete.
|
|
132
|
+
|
|
133
|
+
The **documentation returned to the AI** (including what START_HERE returns) is **configurable**. By default the server provides instructions so the AI will:
|
|
134
|
+
|
|
135
|
+
1. List domains.
|
|
136
|
+
2. List features (and models) within a domain.
|
|
137
|
+
3. Describe a feature or model when it needs the schema.
|
|
138
|
+
4. Execute features and model CRUD operations with the right arguments.
|
|
139
|
+
|
|
140
|
+
So the AI learns the shape of the system from the configurable “start here” and default system entries, then uses the tools to list/describe/execute as needed.
|
|
95
141
|
|
|
96
|
-
|
|
97
|
-
NOTE: In order for this to work your layer must have both a services and a features layer. (In addition to your models.) Node in layers will automatically create a cruds property for you with your models, and you can add them.
|
|
142
|
+
### Hiding components
|
|
98
143
|
|
|
99
|
-
|
|
144
|
+
You can restrict what is visible (as well as executable) to callers (e.g. certain domains, features, or all model CRUDs) so only the intended surface is exposed.
|
|
145
|
+
|
|
146
|
+
Configure `hideComponents` under the MCP config:
|
|
147
|
+
|
|
148
|
+
- **paths** — Dot-separated paths to hide, e.g. `myDomain`, `myDomain.myFeature`, `myDomain.cruds`, `myDomain.cruds.MyModel`.
|
|
149
|
+
- **domains** — Domain names to hide entirely (they won’t appear in `list_domains`).
|
|
150
|
+
- **allModels** — If `true`, no model CRUD tools are exposed.
|
|
151
|
+
|
|
152
|
+
Everything not hidden remains available. See [Configuration details](#configuration-details) for the full shape.
|
|
153
|
+
|
|
154
|
+
Example (partial config):
|
|
100
155
|
|
|
101
156
|
```typescript
|
|
102
|
-
// /
|
|
103
|
-
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
157
|
+
// /config.base.mts
|
|
158
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
159
|
+
|
|
160
|
+
export default () => ({
|
|
161
|
+
// ...
|
|
162
|
+
[McpNamespace]: {
|
|
163
|
+
// ...
|
|
164
|
+
hideComponents: {
|
|
165
|
+
// Completely hide these domains from the MCP surface
|
|
166
|
+
domains: ['internalAdmin', 'experimental'],
|
|
167
|
+
|
|
168
|
+
// Hide specific paths (domains, features, or models)
|
|
169
|
+
paths: [
|
|
170
|
+
'billing.cruds', // hide all models in the billing domain
|
|
171
|
+
'users.cruds.ApiKeys', // hide a single model. (The ApiKeys table located in the users domain)
|
|
172
|
+
'debug.internalFeature', // hide a specific feature
|
|
173
|
+
],
|
|
174
|
+
|
|
175
|
+
// Or hide all models everywhere. Good for "feature" oriented systems.
|
|
176
|
+
allModels: false, // set true to hide all model CRUD tools
|
|
177
|
+
},
|
|
178
|
+
},
|
|
179
|
+
})
|
|
115
180
|
```
|
|
116
181
|
|
|
117
|
-
|
|
182
|
+
---
|
|
118
183
|
|
|
119
|
-
|
|
120
|
-
// /src/yourDomain/mcp.ts
|
|
121
|
-
import { McpContext, McpNamespace, mcpModels } from '@node-in-layers/mcp-server'
|
|
122
|
-
import { Config } from '@node-in-layers/core'
|
|
123
|
-
import { YourFeaturesLayer } from './features.js'
|
|
184
|
+
## System description
|
|
124
185
|
|
|
125
|
-
|
|
126
|
-
// This automatically adds ALL of your models from features.
|
|
127
|
-
mcpModels('yourDomain')(context)
|
|
186
|
+
Under `systemDescription` you set **static metadata** for your system that is included in the start-here response:
|
|
128
187
|
|
|
129
|
-
|
|
130
|
-
|
|
188
|
+
- **description** — Short system description for the AI.
|
|
189
|
+
- **version** — System version string.
|
|
190
|
+
|
|
191
|
+
This is the right place for “what this system is” and version; it does not control which tools exist or what the START_HERE tool includes (that is under `startHere`).
|
|
192
|
+
|
|
193
|
+
Example (partial config):
|
|
194
|
+
|
|
195
|
+
```typescript
|
|
196
|
+
// /config.base.mts
|
|
197
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
198
|
+
|
|
199
|
+
export default () => ({
|
|
200
|
+
// ...
|
|
201
|
+
[McpNamespace]: {
|
|
202
|
+
// ...
|
|
203
|
+
systemDescription: {
|
|
204
|
+
description: 'Order management and billing system for ACME Corp.',
|
|
205
|
+
version: '2.3.0',
|
|
206
|
+
},
|
|
207
|
+
},
|
|
208
|
+
})
|
|
131
209
|
```
|
|
132
210
|
|
|
133
|
-
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Start here
|
|
214
|
+
|
|
215
|
+
The **START_HERE** tool is what makes the system navigable: the AI is instructed to call it first (or when the user asks for help). Its response is built from:
|
|
216
|
+
|
|
217
|
+
1. **System metadata** — `systemName`, `systemDescription`, `systemVersion` from config.
|
|
218
|
+
2. **Default system entries** — Built-in docs (e.g. “this is a domain-layered system”, “MCP navigation workflow”, “cross-layer props”). You can turn these off with `startHere.hideDefaultSystemEntries`.
|
|
219
|
+
3. **Optional: include domains / include features** — If `startHere.includeDomains` is true, the response includes the current list of domains (as if `list_domains` had been called). If `startHere.includeFeatures` is true, it also includes the list of features per domain (as if `list_features` had been called for each). So the AI gets domains and/or features **without** making extra tool calls.
|
|
220
|
+
4. **Examples of use** — Custom entries you add under `startHere.examplesOfUse`. These are where you document **higher-level flows** (e.g. “run feature A, then B, then C”). The built-in docs explain domains, features, and models; they do **not** explain your app-specific sequences. Put those in `examplesOfUse`, as **JSON object examples with minimal prose** so the AI can apply them directly.
|
|
221
|
+
|
|
222
|
+
**Include domains / include features**
|
|
223
|
+
Enabling these is like pre-running `list_domains` and/or `list_features` and embedding the result in START_HERE. The downside is **context size**: for large systems (many tools), that can consume a lot of context and add noise. For **small systems (on the order of 1–10 tools)** it’s usually fine. For larger systems, prefer **examples of use** and let the AI call `list_domains` / `list_features` when needed.
|
|
224
|
+
|
|
225
|
+
Example (partial config):
|
|
226
|
+
|
|
227
|
+
````typescript
|
|
228
|
+
// /config.base.mts
|
|
229
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
230
|
+
|
|
231
|
+
export default () => ({
|
|
232
|
+
// ...
|
|
233
|
+
[McpNamespace]: {
|
|
234
|
+
// ...
|
|
235
|
+
startHere: {
|
|
236
|
+
// Optional: override tool identity
|
|
237
|
+
name: 'START_HERE',
|
|
238
|
+
description:
|
|
239
|
+
'BEFORE YOU DO ANYTHING, call this first to learn how to navigate the system.',
|
|
240
|
+
|
|
241
|
+
// What to include in the start-here response
|
|
242
|
+
hideDefaultSystemEntries: false, // do we want the ones that come by default? Usually this is yes.
|
|
243
|
+
includeDomains: true, // Should we go ahead and tell it the domains? Commonly this should be true.
|
|
244
|
+
includeFeatures: false, // Should we tell them all the features on the first go? In most cases this should be FALSE. Unless its a small system with few functions.
|
|
245
|
+
|
|
246
|
+
// Higher-level flows through your system
|
|
247
|
+
examplesOfUse: [
|
|
248
|
+
{
|
|
249
|
+
name: 'Create order then fetch it',
|
|
250
|
+
description: 'Typical flow that creates an order and then retrieves it.',
|
|
251
|
+
// Giving ACTUAL examples (json data, + small annotations) works amazingly.
|
|
252
|
+
example: `
|
|
253
|
+
```markdown
|
|
254
|
+
// 1. Create an order
|
|
255
|
+
{ "tool": "execute_feature", "args": { "domain": "orders", "featureName": "createOrder" } }
|
|
256
|
+
// 2. Get the order by id (using the id from step 1)
|
|
257
|
+
{ "tool": "execute_feature", "args": { "domain": "orders", "featureName": "getOrderById" } }
|
|
258
|
+
````
|
|
259
|
+
|
|
260
|
+
`,
|
|
261
|
+
tags: ['orders', 'flow'],
|
|
262
|
+
},
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
},
|
|
267
|
+
})
|
|
268
|
+
|
|
269
|
+
````
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Extending with custom tools
|
|
274
|
+
|
|
275
|
+
You can add your own MCP tools via the MCP layer using `addTool`. Use this from a layer that has access to `mcp[McpNamespace]` (e.g. after the MCP layer in the stack).
|
|
276
|
+
|
|
277
|
+
Example (conceptual):
|
|
134
278
|
|
|
135
279
|
```typescript
|
|
136
|
-
//
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
280
|
+
// In a layer that runs after the MCP layer and has context.mcp[McpNamespace]
|
|
281
|
+
const mcp = context.mcp[McpNamespace]
|
|
282
|
+
mcp.addTool({
|
|
283
|
+
name: 'my_custom_tool',
|
|
284
|
+
description: 'Does something custom',
|
|
285
|
+
inputSchema: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] },
|
|
286
|
+
outputSchema: { type: 'object' },
|
|
287
|
+
execute: async (input) => ({ result: input.id }),
|
|
288
|
+
})
|
|
289
|
+
````
|
|
290
|
+
|
|
291
|
+
Your tool is then exposed alongside the built-in domain/feature/model tools.
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
## How to run the server
|
|
296
|
+
|
|
297
|
+
- **start** — Start the MCP server (listens on the connection defined in config).
|
|
298
|
+
`mcp[McpNamespace].start(systemContext, options?)`
|
|
299
|
+
- **getApp** — Get the Express app (for HTTP/SSE) so you can mount it in your own server.
|
|
300
|
+
`mcp[McpNamespace].getApp(options?)`
|
|
301
|
+
|
|
302
|
+
Use **start** when the MCP server is the main process. Use **getApp** when you compose with an existing Express app (e.g. mount the MCP app at a path).
|
|
303
|
+
|
|
304
|
+
---
|
|
305
|
+
|
|
306
|
+
## Middleware and routes
|
|
307
|
+
|
|
308
|
+
- **addPreRouteMiddleware(middleware)** — Add Express middleware that runs before MCP route handling.
|
|
309
|
+
- **addAdditionalRoute(route)** — Register an extra Express route (e.g. health or admin) on the same app.
|
|
310
|
+
|
|
311
|
+
Call these during setup (e.g. from a layer that has access to `mcp[McpNamespace]`) before the server is started or the app is used.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
## Changing logging configuration
|
|
316
|
+
|
|
317
|
+
Logging is configured under the `logging` section of the MCP config. You can control log levels and optionally add structured data to each request/response log entry.
|
|
318
|
+
|
|
319
|
+
- **requestLogLevel** / **responseLogLevel**: Override the default log level (`info`) for incoming requests and outgoing responses.
|
|
320
|
+
- **requestLogGetData(input)**: Function that maps the raw request input into extra data to log.
|
|
321
|
+
- **responseLogGetData(result)**: Function that maps the raw tool result into extra data to log.
|
|
322
|
+
|
|
323
|
+
Example (partial config):
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
// /config.base.mts
|
|
327
|
+
import { McpNamespace } from '@node-in-layers/mcp-server'
|
|
328
|
+
|
|
329
|
+
export default () => ({
|
|
330
|
+
// ...
|
|
331
|
+
[McpNamespace]: {
|
|
332
|
+
// ...
|
|
333
|
+
logging: {
|
|
334
|
+
// Adjust verbosity
|
|
335
|
+
requestLogLevel: 'debug',
|
|
336
|
+
responseLogLevel: 'info',
|
|
337
|
+
|
|
338
|
+
// Attach additional request information to the log.
|
|
339
|
+
requestLogGetData: (input: Request) => ({
|
|
340
|
+
something: input.something,
|
|
341
|
+
}),
|
|
342
|
+
responseLogGetData: (input: Request) => ({
|
|
343
|
+
// Shape this to your needs; example:
|
|
344
|
+
truncated: true,
|
|
345
|
+
}),
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
})
|
|
149
349
|
```
|
|
350
|
+
|
|
351
|
+
---
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
3
|
"id": "2e19b8bf-2a4f-4f3c-9b7e-0f10c9e55c01",
|
|
4
|
-
"name": "
|
|
4
|
+
"name": "This is a domain layered system.",
|
|
5
5
|
"tags": ["intro", "layers", "models"],
|
|
6
|
-
"details": "
|
|
6
|
+
"details": "This system is a series of features that are organized into cohesive domains. Each domain can also export CRUDS access to models, if it chooses to. Domains can be listed, features can be listed, described and called, and so can models."
|
|
7
7
|
},
|
|
8
8
|
{
|
|
9
9
|
"id": "7c0c9643-92f4-4603-984d-3a25b9bd3a28",
|
|
@@ -80,7 +80,7 @@
|
|
|
80
80
|
"id": "a0a1c3cf-7f3f-4e4b-9f1e-2b1a9a7b11aa",
|
|
81
81
|
"name": "list_domains",
|
|
82
82
|
"tags": ["mcp", "nil", "discovery"],
|
|
83
|
-
"details": "Lists domains
|
|
83
|
+
"details": "Lists domains shows the domains available for access.",
|
|
84
84
|
"example": {
|
|
85
85
|
"request": {
|
|
86
86
|
"tool": "list_domains",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"id": "f3b7b0d1-0d4e-4a25-9c76-8a7ef0f2d3c2",
|
|
100
100
|
"name": "list_features",
|
|
101
101
|
"tags": ["mcp", "nil", "discovery", "features"],
|
|
102
|
-
"details": "Lists callable business features for a domain. Use before execute_feature to
|
|
102
|
+
"details": "Lists callable business features for a domain. Use before execute_feature to get the exact input schema for a feature.",
|
|
103
103
|
"example": {
|
|
104
104
|
"request": {
|
|
105
105
|
"tool": "list_features",
|
|
@@ -121,7 +121,7 @@
|
|
|
121
121
|
"id": "3f2f4a9a-4d75-41f0-b1a9-3b7f5a223c17",
|
|
122
122
|
"name": "describe_feature",
|
|
123
123
|
"tags": ["mcp", "nil", "schema", "features"],
|
|
124
|
-
"details": "Returns an OpenAPI-like schema for a feature.
|
|
124
|
+
"details": "Returns an OpenAPI-like schema for a feature.",
|
|
125
125
|
"example": {
|
|
126
126
|
"request": {
|
|
127
127
|
"tool": "describe_feature",
|
|
@@ -311,5 +311,11 @@
|
|
|
311
311
|
"example": {
|
|
312
312
|
"markdown": "User asks: \"Reserve 1 unit of ABC-123 if available.\"\n\n1. list_domains {}\n - Choose domain = inventory.\n2. list_features { domain: \"inventory\" } and list_models { domain: \"inventory\" }\n - See feature reserveItem and model Inventories.\n3. describe_feature { domain: \"inventory\", featureName: \"checkItemAvailability\" }\n - Confirm args: { sku: string, quantity: number }.\n4. execute_feature { domain: \"inventory\", featureName: \"checkItemAvailability\", args: { sku: \"ABC-123\", quantity: 1 }, crossLayerProps: { logging: { ids: [{ aiSessionId: \"8c2ab...\" }, { aiRequestId: \"f4c7a...\" }] } } }\n - If available: true -> proceed.\n5. execute_feature { domain: \"inventory\", featureName: \"reserveItem\", args: { sku: \"ABC-123\", quantity: 1, userId: \"u-42\" }, crossLayerProps: { logging: { ids: [{ aiSessionId: \"8c2ab...\" }, { aiRequestId: \"f4c7a...\" }] } } }\n - Returns reservationId.\n"
|
|
313
313
|
}
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
"id": "0a1b2c3d-4e5f-4607-8a90-b1c2d3e4f507",
|
|
317
|
+
"name": "Working with the user",
|
|
318
|
+
"tags": ["user", "interaction"],
|
|
319
|
+
"details": "Unless the user asks for it don't explain Domain/Models of the system to the user. The features are the primary thing the user cares about, and only to the extent that YOU the AI call them. The details about what goes in them, only matters for them to run other features first. Knowing how to call and navigate this interface is YOUR (the AI)'s job."
|
|
314
320
|
}
|
|
315
321
|
]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Logger } from '@node-in-layers/core';
|
|
2
|
+
import { z, ZodType } from 'zod';
|
|
3
|
+
import { AuthInfo, RequestInfo } from './types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Converts the MCP SDK's RequestHandlerExtra into our local RequestInfo.
|
|
6
|
+
* The SDK only provides HTTP headers; all other fields default to empty values
|
|
7
|
+
* since they are not available through the SDK transport layer.
|
|
8
|
+
*/
|
|
9
|
+
export declare const buildRequestInfoFromSdkExtra: (extra?: any) => RequestInfo;
|
|
10
|
+
/**
|
|
11
|
+
* Extracts AuthInfo from the MCP SDK's RequestHandlerExtra.authInfo, if present.
|
|
12
|
+
*/
|
|
13
|
+
export declare const buildAuthInfoFromSdkExtra: (extra?: any) => AuthInfo | undefined;
|
|
14
|
+
/**
|
|
15
|
+
* Merges crossLayerProps from all sources and returns a cleaned input object
|
|
16
|
+
* with a canonical mergedCrossLayerProps.
|
|
17
|
+
*
|
|
18
|
+
* Sources merged (in order):
|
|
19
|
+
* 1. input.crossLayerProps — client-provided CLP at the top level of tool args
|
|
20
|
+
* 2. input.args.crossLayerProps — CLP nested inside args (used by features)
|
|
21
|
+
* 3. { requestInfo, authInfo } — from the MCP SDK transport's extra
|
|
22
|
+
* 4. logger IDs — appended via createCrossLayerProps
|
|
23
|
+
*/
|
|
24
|
+
export declare const buildMergedToolInput: (input: any, extra: any, logger: Logger) => {
|
|
25
|
+
mergedInput: any;
|
|
26
|
+
mergedCrossLayerProps: any;
|
|
27
|
+
};
|
|
28
|
+
export declare const openApiToZodSchema: (parameters: any) => Record<string, ZodType>;
|
|
29
|
+
export declare const isZodSchema: (schema: any) => schema is z.ZodType<unknown, unknown, z.core.$ZodTypeInternals<unknown, unknown>>;
|