@mcp-layer/schema 1.0.0 → 1.0.1
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 +1 -0
- package/package.json +2 -2
- package/src/index.js +56 -32
package/README.md
CHANGED
|
@@ -138,6 +138,7 @@ Suggested uses for the unified schema:
|
|
|
138
138
|
|
|
139
139
|
- Schema compilation uses Ajv under the hood. If a tool exposes an invalid JSON Schema, extraction still succeeds but `detail.input.error` or `detail.output.error` will be populated for that item.
|
|
140
140
|
- Servers that return empty lists produce an empty `items` array (not an error).
|
|
141
|
+
- Servers that support resources but not resource templates are treated as having zero templates.
|
|
141
142
|
|
|
142
143
|
## JSON Schema vs Zod
|
|
143
144
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-layer/schema",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Extract and normalize MCP schemas into a unified Zod-based format.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"zod": "^3.25.76"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@mcp-layer/attach": "1.
|
|
38
|
+
"@mcp-layer/attach": "1.1.0",
|
|
39
39
|
"@mcp-layer/config": "1.0.0",
|
|
40
40
|
"@mcp-layer/connect": "1.0.0",
|
|
41
41
|
"@mcp-layer/test-server": "1.0.0"
|
package/src/index.js
CHANGED
|
@@ -5,24 +5,41 @@ const ajv = new Ajv({ allErrors: true, strict: false });
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Test if a value is a plain object.
|
|
8
|
-
* @param {unknown} value
|
|
8
|
+
* @param {unknown} value - Value to test for plain object shape.
|
|
9
9
|
* @returns {value is Record<string, unknown>}
|
|
10
10
|
*/
|
|
11
11
|
function isrecord(value) {
|
|
12
12
|
return Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
+
/**
|
|
16
|
+
* Determine whether an MCP error indicates a missing method.
|
|
17
|
+
* @param {unknown} error - Error value to inspect.
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function ismissing(error) {
|
|
21
|
+
if (!error || typeof error !== 'object') {
|
|
22
|
+
return false;
|
|
23
|
+
}
|
|
24
|
+
const code = 'code' in error ? error.code : undefined;
|
|
25
|
+
if (code === -32601) {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const message = 'message' in error ? String(error.message) : '';
|
|
29
|
+
return message.includes('Method') && message.includes('not found');
|
|
30
|
+
}
|
|
31
|
+
|
|
15
32
|
/**
|
|
16
33
|
* Build a Zod refinement function backed by Ajv.
|
|
17
|
-
* @param {import('ajv').Ajv} validator
|
|
18
|
-
* @param {import('ajv').ValidateFunction} check
|
|
34
|
+
* @param {import('ajv').Ajv} validator - Ajv instance used to format errors.
|
|
35
|
+
* @param {import('ajv').ValidateFunction} check - Compiled Ajv validation function.
|
|
19
36
|
* @returns {(value: unknown, ctx: import('zod').RefinementCtx) => void}
|
|
20
37
|
*/
|
|
21
38
|
function refiners(validator, check) {
|
|
22
39
|
/**
|
|
23
40
|
* Validate the value and emit Zod issues for Ajv failures.
|
|
24
|
-
* @param {unknown} value
|
|
25
|
-
* @param {import('zod').RefinementCtx} ctx
|
|
41
|
+
* @param {unknown} value - Value to validate.
|
|
42
|
+
* @param {import('zod').RefinementCtx} ctx - Zod refinement context for reporting issues.
|
|
26
43
|
* @returns {void}
|
|
27
44
|
*/
|
|
28
45
|
function apply(value, ctx) {
|
|
@@ -39,7 +56,7 @@ function refiners(validator, check) {
|
|
|
39
56
|
|
|
40
57
|
/**
|
|
41
58
|
* Wrap a JSON Schema into a Zod schema that delegates validation to Ajv.
|
|
42
|
-
* @param {unknown} json
|
|
59
|
+
* @param {unknown} json - JSON Schema definition to wrap.
|
|
43
60
|
* @returns {{ schema: import('zod').ZodTypeAny, json: Record<string, unknown> | undefined, error?: string }}
|
|
44
61
|
*/
|
|
45
62
|
function wrapschema(json) {
|
|
@@ -60,8 +77,8 @@ function wrapschema(json) {
|
|
|
60
77
|
/**
|
|
61
78
|
* Read all pages for a list request until pagination completes.
|
|
62
79
|
* @template T
|
|
63
|
-
* @param {(cursor?: string) => Promise<T & { nextCursor?: string }>} call
|
|
64
|
-
* @param {(result: T) => Array<unknown>} pull
|
|
80
|
+
* @param {(cursor?: string) => Promise<T & { nextCursor?: string }>} call - Function that requests a page by cursor.
|
|
81
|
+
* @param {(result: T) => Array<unknown>} pull - Function that extracts items from each page result.
|
|
65
82
|
* @returns {Promise<Array<unknown>>}
|
|
66
83
|
*/
|
|
67
84
|
async function page(call, pull) {
|
|
@@ -85,13 +102,13 @@ async function page(call, pull) {
|
|
|
85
102
|
|
|
86
103
|
/**
|
|
87
104
|
* Extract tool entries from a client.
|
|
88
|
-
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client
|
|
105
|
+
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client - MCP client instance.
|
|
89
106
|
* @returns {Promise<Array<Record<string, unknown>>>}
|
|
90
107
|
*/
|
|
91
108
|
async function tools(client) {
|
|
92
109
|
/**
|
|
93
110
|
* Fetch a page of tools.
|
|
94
|
-
* @param {string | undefined} cursor
|
|
111
|
+
* @param {string | undefined} cursor - Pagination cursor from the previous page.
|
|
95
112
|
* @returns {Promise<{ tools: Array<Record<string, unknown>>, nextCursor?: string }>}
|
|
96
113
|
*/
|
|
97
114
|
async function call(cursor) {
|
|
@@ -103,7 +120,7 @@ async function tools(client) {
|
|
|
103
120
|
|
|
104
121
|
/**
|
|
105
122
|
* Pluck tool definitions from a list response.
|
|
106
|
-
* @param {{ tools?: Array<Record<string, unknown>> }} result
|
|
123
|
+
* @param {{ tools?: Array<Record<string, unknown>> }} result - listTools response payload.
|
|
107
124
|
* @returns {Array<Record<string, unknown>>}
|
|
108
125
|
*/
|
|
109
126
|
function pull(result) {
|
|
@@ -115,13 +132,13 @@ async function tools(client) {
|
|
|
115
132
|
|
|
116
133
|
/**
|
|
117
134
|
* Extract resource entries from a client.
|
|
118
|
-
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client
|
|
135
|
+
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client - MCP client instance.
|
|
119
136
|
* @returns {Promise<Array<Record<string, unknown>>>}
|
|
120
137
|
*/
|
|
121
138
|
async function resources(client) {
|
|
122
139
|
/**
|
|
123
140
|
* Fetch a page of resources.
|
|
124
|
-
* @param {string | undefined} cursor
|
|
141
|
+
* @param {string | undefined} cursor - Pagination cursor from the previous page.
|
|
125
142
|
* @returns {Promise<{ resources: Array<Record<string, unknown>>, nextCursor?: string }>}
|
|
126
143
|
*/
|
|
127
144
|
async function call(cursor) {
|
|
@@ -133,7 +150,7 @@ async function resources(client) {
|
|
|
133
150
|
|
|
134
151
|
/**
|
|
135
152
|
* Pluck resource definitions from a list response.
|
|
136
|
-
* @param {{ resources?: Array<Record<string, unknown>> }} result
|
|
153
|
+
* @param {{ resources?: Array<Record<string, unknown>> }} result - listResources response payload.
|
|
137
154
|
* @returns {Array<Record<string, unknown>>}
|
|
138
155
|
*/
|
|
139
156
|
function pull(result) {
|
|
@@ -145,13 +162,13 @@ async function resources(client) {
|
|
|
145
162
|
|
|
146
163
|
/**
|
|
147
164
|
* Extract resource template entries from a client.
|
|
148
|
-
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client
|
|
165
|
+
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client - MCP client instance.
|
|
149
166
|
* @returns {Promise<Array<Record<string, unknown>>>}
|
|
150
167
|
*/
|
|
151
168
|
async function templates(client) {
|
|
152
169
|
/**
|
|
153
170
|
* Fetch a page of resource templates.
|
|
154
|
-
* @param {string | undefined} cursor
|
|
171
|
+
* @param {string | undefined} cursor - Pagination cursor from the previous page.
|
|
155
172
|
* @returns {Promise<{ resourceTemplates: Array<Record<string, unknown>>, nextCursor?: string }>}
|
|
156
173
|
*/
|
|
157
174
|
async function call(cursor) {
|
|
@@ -163,25 +180,32 @@ async function templates(client) {
|
|
|
163
180
|
|
|
164
181
|
/**
|
|
165
182
|
* Pluck resource template definitions from a list response.
|
|
166
|
-
* @param {{ resourceTemplates?: Array<Record<string, unknown>> }} result
|
|
183
|
+
* @param {{ resourceTemplates?: Array<Record<string, unknown>> }} result - listResourceTemplates response payload.
|
|
167
184
|
* @returns {Array<Record<string, unknown>>}
|
|
168
185
|
*/
|
|
169
186
|
function pull(result) {
|
|
170
187
|
return Array.isArray(result.resourceTemplates) ? result.resourceTemplates : [];
|
|
171
188
|
}
|
|
172
189
|
|
|
173
|
-
|
|
190
|
+
try {
|
|
191
|
+
return await page(call, pull);
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (ismissing(error)) {
|
|
194
|
+
return [];
|
|
195
|
+
}
|
|
196
|
+
throw error;
|
|
197
|
+
}
|
|
174
198
|
}
|
|
175
199
|
|
|
176
200
|
/**
|
|
177
201
|
* Extract prompt entries from a client.
|
|
178
|
-
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client
|
|
202
|
+
* @param {import('@modelcontextprotocol/sdk/client/index.js').Client} client - MCP client instance.
|
|
179
203
|
* @returns {Promise<Array<Record<string, unknown>>>}
|
|
180
204
|
*/
|
|
181
205
|
async function prompts(client) {
|
|
182
206
|
/**
|
|
183
207
|
* Fetch a page of prompts.
|
|
184
|
-
* @param {string | undefined} cursor
|
|
208
|
+
* @param {string | undefined} cursor - Pagination cursor from the previous page.
|
|
185
209
|
* @returns {Promise<{ prompts: Array<Record<string, unknown>>, nextCursor?: string }>}
|
|
186
210
|
*/
|
|
187
211
|
async function call(cursor) {
|
|
@@ -193,7 +217,7 @@ async function prompts(client) {
|
|
|
193
217
|
|
|
194
218
|
/**
|
|
195
219
|
* Pluck prompt definitions from a list response.
|
|
196
|
-
* @param {{ prompts?: Array<Record<string, unknown>> }} result
|
|
220
|
+
* @param {{ prompts?: Array<Record<string, unknown>> }} result - listPrompts response payload.
|
|
197
221
|
* @returns {Array<Record<string, unknown>>}
|
|
198
222
|
*/
|
|
199
223
|
function pull(result) {
|
|
@@ -205,7 +229,7 @@ async function prompts(client) {
|
|
|
205
229
|
|
|
206
230
|
/**
|
|
207
231
|
* Build shared metadata from an MCP item.
|
|
208
|
-
* @param {Record<string, unknown>} item
|
|
232
|
+
* @param {Record<string, unknown>} item - MCP definition object.
|
|
209
233
|
* @returns {Record<string, unknown>}
|
|
210
234
|
*/
|
|
211
235
|
function meta(item) {
|
|
@@ -221,7 +245,7 @@ function meta(item) {
|
|
|
221
245
|
|
|
222
246
|
/**
|
|
223
247
|
* Build metadata for tools, including annotations.
|
|
224
|
-
* @param {Record<string, unknown>} tool
|
|
248
|
+
* @param {Record<string, unknown>} tool - Tool definition object.
|
|
225
249
|
* @returns {Record<string, unknown>}
|
|
226
250
|
*/
|
|
227
251
|
function toolmeta(tool) {
|
|
@@ -234,7 +258,7 @@ function toolmeta(tool) {
|
|
|
234
258
|
|
|
235
259
|
/**
|
|
236
260
|
* Derive a display title with tool annotation fallback.
|
|
237
|
-
* @param {Record<string, unknown>} tool
|
|
261
|
+
* @param {Record<string, unknown>} tool - Tool definition object.
|
|
238
262
|
* @returns {string | undefined}
|
|
239
263
|
*/
|
|
240
264
|
function tooltitle(tool) {
|
|
@@ -249,7 +273,7 @@ function tooltitle(tool) {
|
|
|
249
273
|
|
|
250
274
|
/**
|
|
251
275
|
* Extract MCP Apps UI metadata from an item.
|
|
252
|
-
* @param {Record<string, unknown>} item
|
|
276
|
+
* @param {Record<string, unknown>} item - MCP definition object.
|
|
253
277
|
* @returns {Record<string, unknown> | undefined}
|
|
254
278
|
*/
|
|
255
279
|
function uiitem(item) {
|
|
@@ -278,7 +302,7 @@ function uiitem(item) {
|
|
|
278
302
|
|
|
279
303
|
/**
|
|
280
304
|
* Normalize a tool definition into the unified schema.
|
|
281
|
-
* @param {Record<string, unknown>} tool
|
|
305
|
+
* @param {Record<string, unknown>} tool - Raw tool definition from MCP.
|
|
282
306
|
* @returns {Record<string, unknown>}
|
|
283
307
|
*/
|
|
284
308
|
function toolitem(tool) {
|
|
@@ -306,7 +330,7 @@ function toolitem(tool) {
|
|
|
306
330
|
|
|
307
331
|
/**
|
|
308
332
|
* Normalize a resource definition into the unified schema.
|
|
309
|
-
* @param {Record<string, unknown>} resource
|
|
333
|
+
* @param {Record<string, unknown>} resource - Raw resource definition from MCP.
|
|
310
334
|
* @returns {Record<string, unknown>}
|
|
311
335
|
*/
|
|
312
336
|
function resourceitem(resource) {
|
|
@@ -328,7 +352,7 @@ function resourceitem(resource) {
|
|
|
328
352
|
|
|
329
353
|
/**
|
|
330
354
|
* Normalize a resource template definition into the unified schema.
|
|
331
|
-
* @param {Record<string, unknown>} template
|
|
355
|
+
* @param {Record<string, unknown>} template - Raw resource template definition from MCP.
|
|
332
356
|
* @returns {Record<string, unknown>}
|
|
333
357
|
*/
|
|
334
358
|
function templateitem(template) {
|
|
@@ -347,7 +371,7 @@ function templateitem(template) {
|
|
|
347
371
|
|
|
348
372
|
/**
|
|
349
373
|
* Build a JSON schema from prompt arguments so prompts share the input schema shape.
|
|
350
|
-
* @param {Record<string, unknown>} prompt
|
|
374
|
+
* @param {Record<string, unknown>} prompt - Raw prompt definition from MCP.
|
|
351
375
|
* @returns {{ schema: import('zod').ZodTypeAny, json: Record<string, unknown> | undefined, error?: string }}
|
|
352
376
|
*/
|
|
353
377
|
function promptinput(prompt) {
|
|
@@ -385,7 +409,7 @@ function promptinput(prompt) {
|
|
|
385
409
|
|
|
386
410
|
/**
|
|
387
411
|
* Normalize a prompt definition into the unified schema.
|
|
388
|
-
* @param {Record<string, unknown>} prompt
|
|
412
|
+
* @param {Record<string, unknown>} prompt - Raw prompt definition from MCP.
|
|
389
413
|
* @returns {Record<string, unknown>}
|
|
390
414
|
*/
|
|
391
415
|
function promptitem(prompt) {
|
|
@@ -404,7 +428,7 @@ function promptitem(prompt) {
|
|
|
404
428
|
|
|
405
429
|
/**
|
|
406
430
|
* Convert a set of MCP definitions into a unified item list.
|
|
407
|
-
* @param {{ tools?: Array<Record<string, unknown>>, resources?: Array<Record<string, unknown>>, templates?: Array<Record<string, unknown>>, prompts?: Array<Record<string, unknown>> }} data
|
|
431
|
+
* @param {{ tools?: Array<Record<string, unknown>>, resources?: Array<Record<string, unknown>>, templates?: Array<Record<string, unknown>>, prompts?: Array<Record<string, unknown>> }} data - Aggregated MCP list responses.
|
|
408
432
|
* @returns {Array<Record<string, unknown>>}
|
|
409
433
|
*/
|
|
410
434
|
function normalize(data) {
|
|
@@ -439,7 +463,7 @@ function normalize(data) {
|
|
|
439
463
|
|
|
440
464
|
/**
|
|
441
465
|
* Extract MCP tool/resource/prompt schemas into a unified Zod-backed format.
|
|
442
|
-
* @param {import('@mcp-layer/session').Session} link
|
|
466
|
+
* @param {import('@mcp-layer/session').Session} link - Active session with a connected MCP server.
|
|
443
467
|
* @returns {Promise<{ server: { info: Record<string, unknown> | undefined, capabilities: Record<string, unknown> | undefined, instructions: string | undefined }, items: Array<Record<string, unknown>> }>}
|
|
444
468
|
*/
|
|
445
469
|
export async function extract(link) {
|