@mcpdesc/validator 0.10.1 → 0.11.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/CHANGELOG.md +18 -1
- package/README.md +18 -15
- package/index.d.ts +9 -9
- package/package.json +2 -2
- package/src/index.js +7 -9
- package/src/snapshots/{0.8.0-rc.2 → 0.8.0-rc.4}/base.js +0 -5
- package/src/snapshots/{0.8.0-rc.2 → 0.8.0-rc.4}/index.js +3 -3
- package/src/snapshots/{0.8.0-rc.2 → 0.8.0-rc.4}/schema.json +3 -3
- package/src/snapshots/{0.8.0-rc.2 → 0.8.0-rc.4}/semantic.js +10 -22
- package/standalone.js +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,22 @@ Dates for published releases are the UTC publication dates recorded by npm.
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## [0.11.0] - 2026-09-08
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
|
|
15
|
+
- Added the immutable `0.8.0-rc.4` selector, including protocol-independent
|
|
16
|
+
root info metadata behavior and its frozen conformance fixture corpus.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- Narrowed active runtime support to RC.3 and RC.4, deprecated RC.3, and removed
|
|
21
|
+
RC.2 from current registries, declarations, generated bundles, and package
|
|
22
|
+
contents while retaining its immutable source and fixtures in Git.
|
|
23
|
+
- Kept component reference resolution on RC.3 because RC.4's snapshot resolver
|
|
24
|
+
does not expose the terminal-target provenance required by the public result
|
|
25
|
+
contract.
|
|
26
|
+
|
|
11
27
|
## [0.10.1] - 2026-09-07
|
|
12
28
|
|
|
13
29
|
### Changed
|
|
@@ -139,7 +155,8 @@ Dates for published releases are the UTC publication dates recorded by npm.
|
|
|
139
155
|
- Added synchronous structural and semantic validation for parsed JavaScript values with deterministic diagnostics and exact selector dispatch.
|
|
140
156
|
- Added ESM browser support, TypeScript declarations, embedded schema provenance, frozen fixtures, and package-content checks.
|
|
141
157
|
|
|
142
|
-
[Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.
|
|
158
|
+
[Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.11.0...HEAD
|
|
159
|
+
[0.11.0]: https://github.com/mcpdesc/core/compare/validator-v0.10.1...validator-v0.11.0
|
|
143
160
|
[0.10.1]: https://github.com/mcpdesc/core/compare/validator-v0.10.0...validator-v0.10.1
|
|
144
161
|
[0.10.0]: https://github.com/mcpdesc/core/compare/validator-v0.9.0...validator-v0.10.0
|
|
145
162
|
[0.9.0]: https://github.com/mcpdesc/core/compare/validator-v0.8.0...validator-v0.9.0
|
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ npm install @mcpdesc/validator
|
|
|
25
25
|
import { validateMcpDescription } from '@mcpdesc/validator';
|
|
26
26
|
|
|
27
27
|
const result = validateMcpDescription(parsedDocument, {
|
|
28
|
-
specification: '0.8.0-rc.
|
|
28
|
+
specification: '0.8.0-rc.4',
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
for (const diagnostic of result.diagnostics) {
|
|
@@ -48,15 +48,19 @@ The package supports these immutable selectors, newest first:
|
|
|
48
48
|
|
|
49
49
|
| Selector | First validator release | Embedded schema SHA-256 |
|
|
50
50
|
|---|---|---|
|
|
51
|
-
| `0.8.0-rc.
|
|
52
|
-
| `0.8.0-rc.
|
|
51
|
+
| `0.8.0-rc.4` | `0.11.0` | `d38e54db859813b63be2a5c91dde91250035f18bcb5910208cf71fa6875d6eef` |
|
|
52
|
+
| `0.8.0-rc.3` (deprecated) | `0.10.0` | `a9c3ff77ba37c72362909f538f6e957d055e6fdb372f8b3d529e3651af3fecf4` |
|
|
53
53
|
|
|
54
54
|
The validator package embeds the schema and executable behavior for each
|
|
55
|
-
selector. RC.
|
|
56
|
-
should select RC.
|
|
55
|
+
selector. RC.3 remains available for migration compatibility; new integrations
|
|
56
|
+
should select RC.4. Earlier selectors remain available by pinning an older
|
|
57
57
|
immutable validator release. npm integrity and trusted-publishing provenance identify released
|
|
58
58
|
package bytes; specification repository tags and commits are informational.
|
|
59
59
|
|
|
60
|
+
Component reference resolution remains available for RC.3. RC.4 validation is
|
|
61
|
+
supported, but its snapshot resolver does not expose the terminal-target
|
|
62
|
+
provenance required by the package's public resolution result contract.
|
|
63
|
+
|
|
60
64
|
## Usage
|
|
61
65
|
|
|
62
66
|
The `options` argument and exact `specification` selector are required. The unqualified selector `0.8.0` is intentionally unsupported because draft and release-candidate iterations are immutable compatibility contracts.
|
|
@@ -127,20 +131,19 @@ Structural paths start with AJV's instance path. A `required` error appends its
|
|
|
127
131
|
|
|
128
132
|
## Support metadata
|
|
129
133
|
|
|
130
|
-
The package exports frozen `supportedSpecifications`, `deprecatedSpecifications`, `supportedProtocolVersions`, and `specificationProvenance` values. Provenance records include the snapshot tag, recorded schema URI, and embedded schema SHA-256 digest. Public validation dispatches through a registry keyed by exact specification selectors. The active selector set is `0.8.0-rc.
|
|
134
|
+
The package exports frozen `supportedSpecifications`, `deprecatedSpecifications`, `supportedProtocolVersions`, and `specificationProvenance` values. Provenance records include the snapshot tag, recorded schema URI, and embedded schema SHA-256 digest. Public validation dispatches through a registry keyed by exact specification selectors. The active selector set is `0.8.0-rc.3` and `0.8.0-rc.4`; `deprecatedSpecifications` contains RC.3. The protocol-version export is the deduplicated union supported by active snapshots.
|
|
131
135
|
|
|
132
|
-
|
|
133
|
-
`mcpExtensionMaturity` classifier
|
|
134
|
-
effective date, and official or experimental
|
|
135
|
-
recognition establishes authority and
|
|
136
|
-
extension-specific settings.
|
|
136
|
+
The package also exports the frozen `mcpExtensionCatalogue` and
|
|
137
|
+
`mcpExtensionMaturity` classifier pinned by the RC.3 snapshot. The catalogue
|
|
138
|
+
records its authoritative source, effective date, and official or experimental
|
|
139
|
+
identifier assignments. Catalogue recognition establishes authority and
|
|
140
|
+
maturity only; it does not validate extension-specific settings.
|
|
137
141
|
|
|
138
142
|
npm package SemVer tracks implementation releases independently from specification snapshot identity. Adding a later snapshot is additive: it must use a sibling implementation and selector rather than changing an existing snapshot's schema, semantics, metadata, fixtures, or results.
|
|
139
143
|
|
|
140
|
-
The RC.
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
recorded in the integrity manifest.
|
|
144
|
+
The RC.3 component resolver reports authored and terminal target paths for
|
|
145
|
+
successful substitutions. RC.4 component resolution is unavailable because its
|
|
146
|
+
snapshot resolver does not expose that provenance result.
|
|
144
147
|
|
|
145
148
|
The runtime bundles its schema, performs no network fetches for external schema references, and imports no Node.js built-ins. Unresolved external Tool-schema references produce incomplete-validation warnings and are preserved. All three ESM entry points support Node.js 20 or later and browser bundlers.
|
|
146
149
|
|
package/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type McpDescriptionSpecification = '0.8.0-rc.
|
|
1
|
+
export type McpDescriptionSpecification = '0.8.0-rc.3' | '0.8.0-rc.4';
|
|
2
2
|
|
|
3
3
|
export type SupportedProtocolVersion =
|
|
4
4
|
| '2024-11-05'
|
|
@@ -38,7 +38,7 @@ export interface McpDescriptionComponentResolutionResult {
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export interface ResolveMcpDescriptionComponentReferencesOptions {
|
|
41
|
-
readonly specification: '0.8.0-rc.
|
|
41
|
+
readonly specification: '0.8.0-rc.3';
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
export type McpExtensionMaturity = 'official' | 'experimental' | 'uncatalogued';
|
|
@@ -56,16 +56,16 @@ export interface McpExtensionCatalogue {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
export interface SpecificationProvenance {
|
|
59
|
-
readonly '0.8.0-rc.2': {
|
|
60
|
-
readonly snapshotTag: 'v0.8.0-rc.2';
|
|
61
|
-
readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.2.json';
|
|
62
|
-
readonly schemaSha256: '40f6775dde052224114e91d6aa484d826eecf56b77f7ac87b4cf707ffbcb6ce8';
|
|
63
|
-
};
|
|
64
59
|
readonly '0.8.0-rc.3': {
|
|
65
60
|
readonly snapshotTag: 'v0.8.0-rc.3';
|
|
66
61
|
readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.3.json';
|
|
67
62
|
readonly schemaSha256: 'a9c3ff77ba37c72362909f538f6e957d055e6fdb372f8b3d529e3651af3fecf4';
|
|
68
63
|
};
|
|
64
|
+
readonly '0.8.0-rc.4': {
|
|
65
|
+
readonly snapshotTag: 'v0.8.0-rc.4';
|
|
66
|
+
readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.4.json';
|
|
67
|
+
readonly schemaSha256: 'd38e54db859813b63be2a5c91dde91250035f18bcb5910208cf71fa6875d6eef';
|
|
68
|
+
};
|
|
69
69
|
}
|
|
70
70
|
|
|
71
71
|
export interface ResolveMcpDescriptionSpecificationOptions {
|
|
@@ -89,8 +89,8 @@ export type McpDescriptionSpecificationResolution =
|
|
|
89
89
|
| ResolvedMcpDescriptionSpecification
|
|
90
90
|
| UnresolvedMcpDescriptionSpecification;
|
|
91
91
|
|
|
92
|
-
export declare const supportedSpecifications: readonly ['0.8.0-rc.
|
|
93
|
-
export declare const deprecatedSpecifications: readonly ['0.8.0-rc.
|
|
92
|
+
export declare const supportedSpecifications: readonly ['0.8.0-rc.3', '0.8.0-rc.4'];
|
|
93
|
+
export declare const deprecatedSpecifications: readonly ['0.8.0-rc.3'];
|
|
94
94
|
|
|
95
95
|
export declare const supportedProtocolVersions: readonly [
|
|
96
96
|
'2024-11-05',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcpdesc/validator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Structural and semantic validation for MCP Description snapshots",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"src/index.js",
|
|
34
|
-
"src/snapshots/0.8.0-rc.2",
|
|
35
34
|
"src/snapshots/0.8.0-rc.3",
|
|
35
|
+
"src/snapshots/0.8.0-rc.4",
|
|
36
36
|
"standalone.js",
|
|
37
37
|
"index.d.ts",
|
|
38
38
|
"CHANGELOG.md",
|
package/src/index.js
CHANGED
|
@@ -1,31 +1,29 @@
|
|
|
1
|
-
import * as rc2 from './snapshots/0.8.0-rc.2/index.js';
|
|
2
1
|
import * as rc3 from './snapshots/0.8.0-rc.3/index.js';
|
|
3
|
-
import
|
|
2
|
+
import * as rc4 from './snapshots/0.8.0-rc.4/index.js';
|
|
4
3
|
import { resolveComponentReferences as resolveRc3ComponentReferences } from './snapshots/0.8.0-rc.3/semantic.js';
|
|
5
4
|
import {
|
|
6
5
|
mcpExtensionCatalogue,
|
|
7
6
|
mcpExtensionMaturity
|
|
8
|
-
} from './snapshots/0.8.0-rc.
|
|
7
|
+
} from './snapshots/0.8.0-rc.3/semantic.js';
|
|
9
8
|
|
|
10
9
|
export { mcpExtensionCatalogue, mcpExtensionMaturity };
|
|
11
10
|
|
|
12
11
|
const snapshots = Object.freeze({
|
|
13
|
-
[
|
|
14
|
-
[
|
|
12
|
+
[rc3.specification]: rc3,
|
|
13
|
+
[rc4.specification]: rc4
|
|
15
14
|
});
|
|
16
15
|
|
|
17
16
|
const componentResolvers = Object.freeze({
|
|
18
|
-
'0.8.0-rc.2': resolveRc2ComponentReferences,
|
|
19
17
|
'0.8.0-rc.3': resolveRc3ComponentReferences
|
|
20
18
|
});
|
|
21
19
|
|
|
22
20
|
const schemaUris = Object.freeze({
|
|
23
|
-
'0.8.0-rc.
|
|
24
|
-
'0.8.0-rc.
|
|
21
|
+
'0.8.0-rc.3': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.3.json',
|
|
22
|
+
'0.8.0-rc.4': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.4.json'
|
|
25
23
|
});
|
|
26
24
|
|
|
27
25
|
export const supportedSpecifications = Object.freeze(Object.keys(snapshots));
|
|
28
|
-
export const deprecatedSpecifications = Object.freeze(['0.8.0-rc.
|
|
26
|
+
export const deprecatedSpecifications = Object.freeze(['0.8.0-rc.3']);
|
|
29
27
|
export const supportedProtocolVersions = Object.freeze([
|
|
30
28
|
...new Set(Object.values(snapshots).flatMap((snapshot) => snapshot.supportedProtocolVersions))
|
|
31
29
|
]);
|
|
@@ -691,11 +691,6 @@ function validateVersionSpecificSemantics(document, rel, diagnostics) {
|
|
|
691
691
|
}
|
|
692
692
|
}
|
|
693
693
|
|
|
694
|
-
checkMinimumVersion('info', ['info'], document.info ?? {}, 'title', '2025-06-18', rootScope);
|
|
695
|
-
checkMinimumVersion('info', ['info'], document.info ?? {}, 'description', '2025-11-25', rootScope);
|
|
696
|
-
checkMinimumVersion('info', ['info'], document.info ?? {}, 'icons', '2025-11-25', rootScope);
|
|
697
|
-
checkMinimumVersion('info', ['info'], document.info ?? {}, 'websiteUrl', '2025-11-25', rootScope);
|
|
698
|
-
|
|
699
694
|
(document.transports ?? []).forEach((transport, index) => {
|
|
700
695
|
const scope = effectiveScope(document, transport, rootScope);
|
|
701
696
|
if (transport.type === 'streamable-http') {
|
|
@@ -3,9 +3,9 @@ import {
|
|
|
3
3
|
validateMcpdesc08Document
|
|
4
4
|
} from './semantic.js';
|
|
5
5
|
|
|
6
|
-
export const specification = '0.8.0-rc.
|
|
7
|
-
export const snapshotTag = 'v0.8.0-rc.
|
|
8
|
-
export const schemaSha256 = '
|
|
6
|
+
export const specification = '0.8.0-rc.4';
|
|
7
|
+
export const snapshotTag = 'v0.8.0-rc.4';
|
|
8
|
+
export const schemaSha256 = 'd38e54db859813b63be2a5c91dde91250035f18bcb5910208cf71fa6875d6eef';
|
|
9
9
|
export { supportedProtocolVersions };
|
|
10
10
|
|
|
11
11
|
export function validate(document) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://mcpdesc.org/schema/mcp-description/0.8.0-rc.
|
|
4
|
-
"title": "MCP Description",
|
|
5
|
-
"description": "MCP
|
|
3
|
+
"$id": "https://mcpdesc.org/schema/mcp-description/0.8.0-rc.4.json",
|
|
4
|
+
"title": "MCP Server Description (mcpdesc format)",
|
|
5
|
+
"description": "A static, curated description of what an MCP server offers. Uses MCP-native terminology, an OpenAPI-aligned info and security structure, and support for multiple transports, protocol revisions, and specification extensions. Supports MCP protocol revisions 2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25, and 2026-07-28.",
|
|
6
6
|
"type": "object",
|
|
7
7
|
"required": [
|
|
8
8
|
"mcpdesc",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// Validate the immutable 0.8.0-rc.
|
|
1
|
+
// Validate the immutable 0.8.0-rc.4 snapshot using only snapshot-local artifacts.
|
|
2
2
|
|
|
3
3
|
import Ajv from 'ajv';
|
|
4
4
|
import Ajv2020 from 'ajv/dist/2020.js';
|
|
@@ -62,7 +62,6 @@ function componentDiagnostic(code, rel, message, path) {
|
|
|
62
62
|
export function resolveComponentReferences(document, rel = 'document') {
|
|
63
63
|
const resolved = structuredClone(document);
|
|
64
64
|
const diagnostics = [];
|
|
65
|
-
const provenance = [];
|
|
66
65
|
let substitutions = 0;
|
|
67
66
|
|
|
68
67
|
function resolve(reference, expectedNamespace, path, stack = []) {
|
|
@@ -76,7 +75,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
76
75
|
`must target #/components/${expectedNamespace}, not #/components/${namespace}`,
|
|
77
76
|
path
|
|
78
77
|
));
|
|
79
|
-
return
|
|
78
|
+
return reference;
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
const key = `${namespace}/${name}`;
|
|
@@ -87,7 +86,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
87
86
|
`forms a cycle through ${[...stack, key].join(' -> ')}`,
|
|
88
87
|
path
|
|
89
88
|
));
|
|
90
|
-
return
|
|
89
|
+
return reference;
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
const target = document?.components?.[namespace]?.[name];
|
|
@@ -98,29 +97,18 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
98
97
|
`targets missing component ${JSON.stringify(reference.$componentRef)}`,
|
|
99
98
|
path
|
|
100
99
|
));
|
|
101
|
-
return
|
|
100
|
+
return reference;
|
|
102
101
|
}
|
|
103
102
|
substitutions += 1;
|
|
104
103
|
return isReferenceObject(target)
|
|
105
104
|
? resolve(target, expectedNamespace, path, [...stack, key])
|
|
106
|
-
:
|
|
107
|
-
value: structuredClone(target),
|
|
108
|
-
targetPath: ['components', namespace, name]
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
function substitute(reference, expectedNamespace, path, stack = []) {
|
|
113
|
-
const result = resolve(reference, expectedNamespace, path, stack);
|
|
114
|
-
if (result.targetPath) {
|
|
115
|
-
provenance.push({ referencePath: path, targetPath: result.targetPath });
|
|
116
|
-
}
|
|
117
|
-
return result.value;
|
|
105
|
+
: structuredClone(target);
|
|
118
106
|
}
|
|
119
107
|
|
|
120
108
|
for (const namespace of componentNamespaces) {
|
|
121
109
|
for (const [name, value] of Object.entries(document?.components?.[namespace] ?? {})) {
|
|
122
110
|
if (isReferenceObject(value)) {
|
|
123
|
-
resolved.components[namespace][name] =
|
|
111
|
+
resolved.components[namespace][name] = resolve(value, namespace, ['components', namespace, name], [`${namespace}/${name}`]);
|
|
124
112
|
}
|
|
125
113
|
}
|
|
126
114
|
}
|
|
@@ -136,7 +124,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
136
124
|
if (collection === 'tools') {
|
|
137
125
|
for (const field of ['inputSchema', 'outputSchema']) {
|
|
138
126
|
if (isReferenceObject(declaration[field])) {
|
|
139
|
-
resolvedDeclaration[field] =
|
|
127
|
+
resolvedDeclaration[field] = resolve(declaration[field], 'schemas', [collection, declarationIndex, field]);
|
|
140
128
|
}
|
|
141
129
|
}
|
|
142
130
|
}
|
|
@@ -150,7 +138,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
150
138
|
: 'promptExamples';
|
|
151
139
|
for (const [name, example] of Object.entries(declaration.examples ?? {})) {
|
|
152
140
|
if (isReferenceObject(example)) {
|
|
153
|
-
resolvedDeclaration.examples[name] =
|
|
141
|
+
resolvedDeclaration.examples[name] = resolve(
|
|
154
142
|
example,
|
|
155
143
|
exampleNamespace,
|
|
156
144
|
[collection, declarationIndex, 'examples', name]
|
|
@@ -164,7 +152,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
164
152
|
for (const [declarationIndex, declaration] of (document?.[collection] ?? []).entries()) {
|
|
165
153
|
for (const [elicitationIndex, elicitation] of (declaration.elicitations ?? []).entries()) {
|
|
166
154
|
if (isReferenceObject(elicitation.requestedSchema)) {
|
|
167
|
-
resolved[collection][declarationIndex].elicitations[elicitationIndex].requestedSchema =
|
|
155
|
+
resolved[collection][declarationIndex].elicitations[elicitationIndex].requestedSchema = resolve(
|
|
168
156
|
elicitation.requestedSchema,
|
|
169
157
|
'schemas',
|
|
170
158
|
[collection, declarationIndex, 'elicitations', elicitationIndex, 'requestedSchema']
|
|
@@ -174,7 +162,7 @@ export function resolveComponentReferences(document, rel = 'document') {
|
|
|
174
162
|
}
|
|
175
163
|
}
|
|
176
164
|
|
|
177
|
-
return { document: resolved, diagnostics, substitutions
|
|
165
|
+
return { document: resolved, diagnostics, substitutions };
|
|
178
166
|
}
|
|
179
167
|
|
|
180
168
|
function structuralPath(document, error) {
|