@mcp-layer/schema 1.0.2 → 1.0.4

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 CHANGED
@@ -30,7 +30,7 @@ yarn add @mcp-layer/schema
30
30
  ```js
31
31
  import { load } from '@mcp-layer/config';
32
32
  import { connect } from '@mcp-layer/connect';
33
- import { extract } from '@mcp-layer/schema';
33
+ import { composeCatalog, extract } from '@mcp-layer/schema';
34
34
 
35
35
  const config = await load(undefined, process.cwd());
36
36
  const session = await connect(config, 'demo');
@@ -39,15 +39,37 @@ const output = await extract(session);
39
39
  console.log(output.server.info);
40
40
  console.log(output.items[0]);
41
41
  await session.close();
42
+
43
+ const catalog = composeCatalog({
44
+ server: {
45
+ info: { name: 'demo', version: '1.0.0' },
46
+ capabilities: { tools: {} },
47
+ instructions: 'Use the local catalog.',
48
+ },
49
+ tools: [{
50
+ name: 'echo',
51
+ description: 'Echo text.',
52
+ inputSchema: {
53
+ type: 'object',
54
+ properties: {
55
+ text: { type: 'string' },
56
+ },
57
+ required: ['text'],
58
+ },
59
+ }],
60
+ });
61
+
62
+ console.log(catalog.items[0]);
42
63
  ```
43
64
 
44
65
  ## What this package does
45
66
 
46
- 1) Reads the MCP server capabilities and metadata from the live client connection.
67
+ 1) Reads the MCP server capabilities and metadata from the live client connection with `extract(session)`.
47
68
  2) Calls MCP list endpoints (`tools/list`, `resources/list`, `resources/templates/list`, `prompts/list`) using pagination.
48
- 3) Normalizes everything into a unified, type-discriminated schema so generators can consume a single list.
49
- 4) Wraps tool input/output JSON Schemas into Zod validators backed by Ajv, while preserving the original JSON Schema.
50
- 5) Converts prompt arguments into a lightweight JSON Schema so prompts and tools share the same `detail.input` shape.
69
+ 3) Composes the same normalized catalog shape from raw definitions with `composeCatalog(...)` when a live session is not available yet.
70
+ 4) Normalizes everything into a unified, type-discriminated schema so generators can consume a single list.
71
+ 5) Wraps tool input/output JSON Schemas into Zod validators backed by Ajv, while preserving the original JSON Schema.
72
+ 6) Converts prompt arguments into a lightweight JSON Schema so prompts and tools share the same `detail.input` shape.
51
73
 
52
74
  ## Output shape (authoritative)
53
75
 
@@ -143,8 +165,9 @@ Suggested uses for the unified schema:
143
165
 
144
166
  ## Responsibilities and lifecycle
145
167
 
146
- - This package does not open or close connections. It expects a live `Session` from `@mcp-layer/connect` or `@mcp-layer/attach`.
168
+ - `extract(session)` does not open or close connections. It expects a live `Session` from `@mcp-layer/connect` or `@mcp-layer/attach`.
147
169
  - You are responsible for calling `session.close()` after extraction.
170
+ - `composeCatalog(...)` is pure and does not require a connection.
148
171
  - If the server doesn't advertise a capability (tools/resources/prompts), extraction skips that surface.
149
172
 
150
173
  ## Error handling
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcp-layer/schema",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Extract and normalize MCP schemas into a unified Zod-based format.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -16,8 +16,10 @@
16
16
  "prompts"
17
17
  ],
18
18
  "main": "src/index.js",
19
+ "types": "./types/index.d.ts",
19
20
  "exports": {
20
21
  ".": {
22
+ "types": "./types/index.d.ts",
21
23
  "import": "./src/index.js",
22
24
  "default": "./src/index.js"
23
25
  },
@@ -25,6 +27,7 @@
25
27
  },
26
28
  "files": [
27
29
  "src",
30
+ "types",
28
31
  "LICENSE"
29
32
  ],
30
33
  "publishConfig": {
@@ -33,15 +36,16 @@
33
36
  "dependencies": {
34
37
  "ajv": "^8.17.1",
35
38
  "zod": "^3.25.76",
36
- "@mcp-layer/error": "0.2.0"
39
+ "@mcp-layer/error": "0.2.1"
37
40
  },
38
41
  "devDependencies": {
39
- "@mcp-layer/attach": "1.1.1",
40
- "@mcp-layer/config": "1.0.1",
41
- "@mcp-layer/connect": "1.0.1",
42
- "@mcp-layer/test-server": "1.0.1"
42
+ "@mcp-layer/attach": "1.1.2",
43
+ "@mcp-layer/config": "1.0.2",
44
+ "@mcp-layer/connect": "1.2.1",
45
+ "@mcp-layer/test-server": "1.0.4"
43
46
  },
44
47
  "scripts": {
45
- "test": "node --test --experimental-test-coverage ./test/**/*.js"
48
+ "build:types": "tsc -p tsconfig.json",
49
+ "test": "node --test --experimental-test-coverage \"./test/**/*.js\""
46
50
  }
47
51
  }
package/src/index.js CHANGED
@@ -416,6 +416,45 @@ function normalize(data) {
416
416
  return list;
417
417
  }
418
418
 
419
+ /**
420
+ * Derive advertised capabilities from the provided raw MCP definition sets.
421
+ * @param {{ tools?: Array<Record<string, unknown>>, resources?: Array<Record<string, unknown>>, templates?: Array<Record<string, unknown>>, prompts?: Array<Record<string, unknown>> }} data - Raw MCP definition sets.
422
+ * @returns {Record<string, unknown> | undefined}
423
+ */
424
+ function capabilities(data) {
425
+ const caps = {};
426
+
427
+ if (Array.isArray(data.tools)) caps.tools = {};
428
+ if (Array.isArray(data.resources) || Array.isArray(data.templates)) caps.resources = {};
429
+ if (Array.isArray(data.prompts)) caps.prompts = {};
430
+
431
+ return Object.keys(caps).length > 0 ? caps : undefined;
432
+ }
433
+
434
+ /**
435
+ * Compose a unified catalog from raw MCP definitions without a live session.
436
+ * This lets adapters bootstrap routes from already-known tool/resource shapes
437
+ * while keeping the output identical to `extract(session)`.
438
+ *
439
+ * @param {{ server?: { info?: Record<string, unknown>, capabilities?: Record<string, unknown>, instructions?: string }, tools?: Array<Record<string, unknown>>, resources?: Array<Record<string, unknown>>, templates?: Array<Record<string, unknown>>, prompts?: Array<Record<string, unknown>> }} input - Raw server metadata and MCP definitions.
440
+ * @returns {{ server: { info: Record<string, unknown> | undefined, capabilities: Record<string, unknown> | undefined, instructions: string | undefined }, items: Array<Record<string, unknown>> }}
441
+ */
442
+ export function composeCatalog(input = {}) {
443
+ const server = isrecord(input.server) ? input.server : {};
444
+ const info = isrecord(server.info) ? server.info : undefined;
445
+ const caps = isrecord(server.capabilities) ? server.capabilities : capabilities(input);
446
+ const instructions = typeof server.instructions === 'string' ? server.instructions : undefined;
447
+
448
+ return {
449
+ server: {
450
+ info,
451
+ capabilities: caps,
452
+ instructions,
453
+ },
454
+ items: normalize(input),
455
+ };
456
+ }
457
+
419
458
  /**
420
459
  * Extract MCP tool/resource/prompt schemas into a unified Zod-backed format.
421
460
  * @param {import('@mcp-layer/session').Session} link - Active session with a connected MCP server.
@@ -451,14 +490,12 @@ export async function extract(link) {
451
490
 
452
491
  if (caps && caps.prompts) data.prompts = await prompts(client);
453
492
 
454
- const items = normalize(data);
455
-
456
- return {
493
+ return composeCatalog({
457
494
  server: {
458
495
  info,
459
496
  capabilities: caps,
460
- instructions
497
+ instructions,
461
498
  },
462
- items
463
- };
499
+ ...data,
500
+ });
464
501
  }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Compose a unified catalog from raw MCP definitions without a live session.
3
+ * This lets adapters bootstrap routes from already-known tool/resource shapes
4
+ * while keeping the output identical to `extract(session)`.
5
+ *
6
+ * @param {{ server?: { info?: Record<string, unknown>, capabilities?: Record<string, unknown>, instructions?: string }, tools?: Array<Record<string, unknown>>, resources?: Array<Record<string, unknown>>, templates?: Array<Record<string, unknown>>, prompts?: Array<Record<string, unknown>> }} input - Raw server metadata and MCP definitions.
7
+ * @returns {{ server: { info: Record<string, unknown> | undefined, capabilities: Record<string, unknown> | undefined, instructions: string | undefined }, items: Array<Record<string, unknown>> }}
8
+ */
9
+ export function composeCatalog(input?: {
10
+ server?: {
11
+ info?: Record<string, unknown>;
12
+ capabilities?: Record<string, unknown>;
13
+ instructions?: string;
14
+ };
15
+ tools?: Array<Record<string, unknown>>;
16
+ resources?: Array<Record<string, unknown>>;
17
+ templates?: Array<Record<string, unknown>>;
18
+ prompts?: Array<Record<string, unknown>>;
19
+ }): {
20
+ server: {
21
+ info: Record<string, unknown> | undefined;
22
+ capabilities: Record<string, unknown> | undefined;
23
+ instructions: string | undefined;
24
+ };
25
+ items: Array<Record<string, unknown>>;
26
+ };
27
+ /**
28
+ * Extract MCP tool/resource/prompt schemas into a unified Zod-backed format.
29
+ * @param {import('@mcp-layer/session').Session} link - Active session with a connected MCP server.
30
+ * @returns {Promise<{ server: { info: Record<string, unknown> | undefined, capabilities: Record<string, unknown> | undefined, instructions: string | undefined }, items: Array<Record<string, unknown>> }>}
31
+ */
32
+ export function extract(link: any): Promise<{
33
+ server: {
34
+ info: Record<string, unknown> | undefined;
35
+ capabilities: Record<string, unknown> | undefined;
36
+ instructions: string | undefined;
37
+ };
38
+ items: Array<Record<string, unknown>>;
39
+ }>;