@mcp-layer/schema
Advanced tools
+7
-6
| { | ||
| "name": "@mcp-layer/schema", | ||
| "version": "1.0.1", | ||
| "version": "1.0.2", | ||
| "description": "Extract and normalize MCP schemas into a unified Zod-based format.", | ||
@@ -35,9 +35,10 @@ "repository": { | ||
| "ajv": "^8.17.1", | ||
| "zod": "^3.25.76" | ||
| "zod": "^3.25.76", | ||
| "@mcp-layer/error": "0.2.0" | ||
| }, | ||
| "devDependencies": { | ||
| "@mcp-layer/attach": "1.1.0", | ||
| "@mcp-layer/config": "1.0.0", | ||
| "@mcp-layer/connect": "1.0.0", | ||
| "@mcp-layer/test-server": "1.0.0" | ||
| "@mcp-layer/attach": "1.1.1", | ||
| "@mcp-layer/config": "1.0.1", | ||
| "@mcp-layer/connect": "1.0.1", | ||
| "@mcp-layer/test-server": "1.0.1" | ||
| }, | ||
@@ -44,0 +45,0 @@ "scripts": { |
+46
-0
@@ -5,2 +5,15 @@ # @mcp-layer/schema | ||
| ## Table of Contents | ||
| - [Installation](#installation) | ||
| - [Usage](#usage) | ||
| - [What this package does](#what-this-package-does) | ||
| - [Output shape (authoritative)](#output-shape-authoritative) | ||
| - [MCP Apps support](#mcp-apps-support) | ||
| - [Generator guidance](#generator-guidance) | ||
| - [Responsibilities and lifecycle](#responsibilities-and-lifecycle) | ||
| - [Error handling](#error-handling) | ||
| - [JSON Schema vs Zod](#json-schema-vs-zod) | ||
| - [Runtime Error Reference](#runtime-error-reference) | ||
| ## Installation | ||
@@ -147,1 +160,34 @@ | ||
| Zod validators are produced to allow direct runtime validation, but the original JSON Schema is preserved in `detail.input.json` and `detail.output.json` so generators can emit OpenAPI, JSON Schema, or other schema formats without losing fidelity. | ||
| ## Runtime Error Reference | ||
| This section is written for high-pressure debugging moments. Each entry maps directly to schema extraction preconditions. | ||
| <a id="error-49ae61"></a> | ||
| ### Expected a Session instance. | ||
| Thrown from: `extract` | ||
| This happens when `extract(link)` is called without a connected `Session` object (or with an object that does not expose `.client`). The extractor relies on MCP client capabilities and list calls. | ||
| Step-by-step resolution: | ||
| 1. Verify you are passing the `Session` returned by `connect(...)` or `attach(...)`. | ||
| 2. Confirm session setup completed and `session.client` is available. | ||
| 3. Avoid passing raw MCP client objects directly; wrap flows around `Session`. | ||
| 4. Add an integration test that extracts from a real connected session. | ||
| <details> | ||
| <summary>Fix Example: extract schemas from a connected Session</summary> | ||
| ```js | ||
| const session = await connect(config, 'local-dev'); | ||
| const catalog = await extract(session); | ||
| console.log(catalog.items.length); | ||
| await session.close(); | ||
| ``` | ||
| </details> | ||
| ## License | ||
| MIT |
+31
-76
| import Ajv from 'ajv'; | ||
| import { z } from 'zod'; | ||
| import { LayerError } from '@mcp-layer/error'; | ||
@@ -21,9 +22,5 @@ const ajv = new Ajv({ allErrors: true, strict: false }); | ||
| function ismissing(error) { | ||
| if (!error || typeof error !== 'object') { | ||
| return false; | ||
| } | ||
| if (!error || typeof error !== 'object') return false; | ||
| const code = 'code' in error ? error.code : undefined; | ||
| if (code === -32601) { | ||
| return true; | ||
| } | ||
| if (code === -32601) return true; | ||
| const message = 'message' in error ? String(error.message) : ''; | ||
@@ -48,5 +45,3 @@ return message.includes('Method') && message.includes('not found'); | ||
| const ok = check(value); | ||
| if (ok) { | ||
| return; | ||
| } | ||
| if (ok) return; | ||
| const text = validator.errorsText(check.errors, { dataVar: 'value' }); | ||
@@ -93,9 +88,5 @@ ctx.addIssue({ code: z.ZodIssueCode.custom, message: text }); | ||
| const batch = pull(result); | ||
| if (Array.isArray(batch)) { | ||
| list.push(...batch); | ||
| } | ||
| if (Array.isArray(batch)) list.push(...batch); | ||
| cursor = result.nextCursor; | ||
| if (!cursor) { | ||
| break; | ||
| } | ||
| if (!cursor) break; | ||
| } | ||
@@ -196,5 +187,3 @@ | ||
| } catch (error) { | ||
| if (ismissing(error)) { | ||
| return []; | ||
| } | ||
| if (ismissing(error)) return []; | ||
| throw error; | ||
@@ -241,8 +230,4 @@ } | ||
| const out = {}; | ||
| if (Array.isArray(item.icons)) { | ||
| out.icons = item.icons; | ||
| } | ||
| if (isrecord(item._meta)) { | ||
| out._meta = item._meta; | ||
| } | ||
| if (Array.isArray(item.icons)) out.icons = item.icons; | ||
| if (isrecord(item._meta)) out._meta = item._meta; | ||
| return out; | ||
@@ -258,5 +243,3 @@ } | ||
| const out = meta(tool); | ||
| if (isrecord(tool.annotations)) { | ||
| out.annotations = tool.annotations; | ||
| } | ||
| if (isrecord(tool.annotations)) out.annotations = tool.annotations; | ||
| return out; | ||
@@ -271,8 +254,4 @@ } | ||
| function tooltitle(tool) { | ||
| if (typeof tool.title === 'string') { | ||
| return tool.title; | ||
| } | ||
| if (isrecord(tool.annotations) && typeof tool.annotations.title === 'string') { | ||
| return tool.annotations.title; | ||
| } | ||
| if (typeof tool.title === 'string') return tool.title; | ||
| if (isrecord(tool.annotations) && typeof tool.annotations.title === 'string') return tool.annotations.title; | ||
| return undefined; | ||
@@ -287,22 +266,10 @@ } | ||
| function uiitem(item) { | ||
| if (!isrecord(item._meta)) { | ||
| return undefined; | ||
| } | ||
| if (!isrecord(item._meta.ui)) { | ||
| return undefined; | ||
| } | ||
| if (!isrecord(item._meta)) return undefined; | ||
| if (!isrecord(item._meta.ui)) return undefined; | ||
| const ui = /** @type {Record<string, unknown>} */ (item._meta.ui); | ||
| const out = {}; | ||
| if (typeof ui.resourceUri === 'string') { | ||
| out.resourceUri = ui.resourceUri; | ||
| } | ||
| if (typeof ui.csp === 'string') { | ||
| out.csp = ui.csp; | ||
| } | ||
| if (Array.isArray(ui.permissions)) { | ||
| out.permissions = ui.permissions; | ||
| } | ||
| if (Object.keys(out).length === 0) { | ||
| return undefined; | ||
| } | ||
| if (typeof ui.resourceUri === 'string') out.resourceUri = ui.resourceUri; | ||
| if (typeof ui.csp === 'string') out.csp = ui.csp; | ||
| if (Array.isArray(ui.permissions)) out.permissions = ui.permissions; | ||
| if (Object.keys(out).length === 0) return undefined; | ||
| return out; | ||
@@ -322,8 +289,4 @@ } | ||
| if (isrecord(tool.outputSchema)) { | ||
| detail.output = output; | ||
| } | ||
| if (ui) { | ||
| detail.ui = ui; | ||
| } | ||
| if (isrecord(tool.outputSchema)) detail.output = output; | ||
| if (ui) detail.ui = ui; | ||
@@ -387,5 +350,3 @@ return { | ||
| function promptinput(prompt) { | ||
| if (!Array.isArray(prompt.arguments)) { | ||
| return wrapschema(undefined); | ||
| } | ||
| if (!Array.isArray(prompt.arguments)) return wrapschema(undefined); | ||
@@ -396,14 +357,8 @@ const properties = {}; | ||
| for (const item of prompt.arguments) { | ||
| if (!isrecord(item)) { | ||
| continue; | ||
| } | ||
| if (typeof item.name !== 'string' || item.name.length === 0) { | ||
| continue; | ||
| } | ||
| if (!isrecord(item)) continue; | ||
| if (typeof item.name !== 'string' || item.name.length === 0) continue; | ||
| properties[item.name] = { | ||
| description: typeof item.description === 'string' ? item.description : undefined | ||
| }; | ||
| if (item.required === true) { | ||
| required.push(item.name); | ||
| } | ||
| if (item.required === true) required.push(item.name); | ||
| } | ||
@@ -482,3 +437,7 @@ | ||
| if (!link || !link.client) { | ||
| throw new Error('Expected a Session instance.'); | ||
| throw new LayerError({ | ||
| name: 'schema', | ||
| method: 'extract', | ||
| message: 'Expected a Session instance.', | ||
| }); | ||
| } | ||
@@ -498,5 +457,3 @@ | ||
| if (caps && caps.tools) { | ||
| data.tools = await tools(client); | ||
| } | ||
| if (caps && caps.tools) data.tools = await tools(client); | ||
@@ -508,5 +465,3 @@ if (caps && caps.resources) { | ||
| if (caps && caps.prompts) { | ||
| data.prompts = await prompts(client); | ||
| } | ||
| if (caps && caps.prompts) data.prompts = await prompts(client); | ||
@@ -513,0 +468,0 @@ const items = normalize(data); |
22810
6.49%192
31.51%3
50%413
-9.83%+ Added
+ Added