@mcpdesc/validator 0.9.0 → 0.10.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/CHANGELOG.md CHANGED
@@ -8,6 +8,34 @@ Dates for published releases are the UTC publication dates recorded by npm.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.10.1] - 2026-09-07
12
+
13
+ ### Changed
14
+
15
+ - Narrowed active runtime support to RC.2 and RC.3 and marked RC.2 deprecated.
16
+ - Excluded retired runtime snapshots from generated bundles and package
17
+ contents while retaining their source and frozen fixtures in Git.
18
+ - Removed the retained snapshot-intake manifest; intake bundles are disposable
19
+ inputs and imported bytes remain protected by the snapshot integrity manifest.
20
+
21
+ ## [0.10.0] - 2026-09-07
22
+
23
+ ### Added
24
+
25
+ - Added the immutable `0.8.0-rc.3` selector with behavior equivalent to RC.2,
26
+ its RC.3 schema identity, and frozen fixtures.
27
+ - Added component reference resolution for RC.2 and RC.3 with deterministic
28
+ terminal-target provenance.
29
+
30
+ ### Changed
31
+
32
+ - Validator integrity now relies on package-owned schema, runtime, fixture, and
33
+ package bytes. Specification repository tags and commits are retained only as
34
+ informational provenance.
35
+ - Recorded maintainer-approved additive provenance corrections to the RC.2 and
36
+ RC.3 snapshot implementations. Their schemas, conformance results,
37
+ diagnostics, and frozen fixtures remain unchanged.
38
+
11
39
  ## [0.9.0] - 2026-09-04
12
40
 
13
41
  ### Added
@@ -111,7 +139,9 @@ Dates for published releases are the UTC publication dates recorded by npm.
111
139
  - Added synchronous structural and semantic validation for parsed JavaScript values with deterministic diagnostics and exact selector dispatch.
112
140
  - Added ESM browser support, TypeScript declarations, embedded schema provenance, frozen fixtures, and package-content checks.
113
141
 
114
- [Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.9.0...HEAD
142
+ [Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.10.1...HEAD
143
+ [0.10.1]: https://github.com/mcpdesc/core/compare/validator-v0.10.0...validator-v0.10.1
144
+ [0.10.0]: https://github.com/mcpdesc/core/compare/validator-v0.9.0...validator-v0.10.0
115
145
  [0.9.0]: https://github.com/mcpdesc/core/compare/validator-v0.8.0...validator-v0.9.0
116
146
  [0.8.0]: https://github.com/mcpdesc/core/compare/validator-v0.7.1...validator-v0.8.0
117
147
  [0.7.1]: https://github.com/mcpdesc/core/compare/validator-v0.7.0...validator-v0.7.1
package/README.md CHANGED
@@ -44,16 +44,18 @@ a later draft is published.
44
44
 
45
45
  ## Supported snapshots
46
46
 
47
- Version `0.8.0` supports these immutable snapshots, newest first:
47
+ The package supports these immutable selectors, newest first:
48
48
 
49
- | Selector | Tag | Embedded schema SHA-256 |
49
+ | Selector | First validator release | Embedded schema SHA-256 |
50
50
  |---|---|---|
51
- | `0.8.0-rc.2` | `v0.8.0-rc.2` | `40f6775dde052224114e91d6aa484d826eecf56b77f7ac87b4cf707ffbcb6ce8` |
52
- | `0.8.0-rc.1` | `v0.8.0-rc.1` | `936a0f24ade501fcabf3d6498c0440c445daa672a575573a35954cee49430ac4` |
53
- | `0.8.0-draft.4` | `v0.8.0-draft.4` | `93ed03f74059b5b3ce7509a96b59161bdab2c3cf7734397a9bec5a7588d0b03b` |
54
- | `0.8.0-draft.3` | `v0.8.0-draft.3` | `8823c1f1946360b2a44d00920e2092e5e4acd139a1964befad4eb0bf3ce96002` |
55
- | `0.8.0-draft.2` | `v0.8.0-draft.2` | `ab692c1a5a0f7e5f29be1940aa8c64a56d4620be0a19d00cf0a64680b7e517fa` |
56
- | `0.8.0-draft.1` | `v0.8.0-draft.1` | `4ceb6042c3fd31703199cd3db869ec5c35c17d2fe9ab7b2f5b96a2a3af0cebe4` |
51
+ | `0.8.0-rc.3` | `0.10.0` | `a9c3ff77ba37c72362909f538f6e957d055e6fdb372f8b3d529e3651af3fecf4` |
52
+ | `0.8.0-rc.2` (deprecated) | `0.9.0` | `40f6775dde052224114e91d6aa484d826eecf56b77f7ac87b4cf707ffbcb6ce8` |
53
+
54
+ The validator package embeds the schema and executable behavior for each
55
+ selector. RC.2 remains available for migration compatibility; new integrations
56
+ should select RC.3. Earlier selectors remain available by pinning an older
57
+ immutable validator release. npm integrity and trusted-publishing provenance identify released
58
+ package bytes; specification repository tags and commits are informational.
57
59
 
58
60
  ## Usage
59
61
 
@@ -95,17 +97,10 @@ if (resolution.status === 'resolved') {
95
97
 
96
98
  Resolution is pure and performs no network retrieval. It does not validate the
97
99
  document and never infers a draft snapshot from `mcpdesc: "0.8.0"` alone.
98
- Draft 4's format-qualified schema URI resolves uniquely. Drafts 1 through 3
99
- share the legacy `https://mcpdesc.org/schema/0.8.0.json` URI, so that URI is
100
- ambiguous unless the caller supplies a consistent exact selector:
101
-
102
- ```js
103
- const resolution = resolveMcpDescriptionSpecification(parsedDocument, {
104
- specification: '0.8.0-draft.3'
105
- });
106
- ```
100
+ Retired schema identities are reported as unknown by current releases. Pin an
101
+ older package release to resolve or validate a retired selector.
107
102
 
108
- Unresolved results distinguish missing, invalid, unknown, ambiguous, and
103
+ Unresolved results distinguish missing, invalid, unknown, and
109
104
  contradictory identity, as well as unsupported caller selectors. A supplied
110
105
  selector can resolve a document with no `$schema`; when `$schema` is present it
111
106
  must match the selected snapshot's recorded schema URI.
@@ -132,9 +127,9 @@ Structural paths start with AJV's instance path. A `required` error appends its
132
127
 
133
128
  ## Support metadata
134
129
 
135
- The package exports frozen `supportedSpecifications`, `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 current repository selector set is `0.8.0-draft.1`, `0.8.0-draft.2`, `0.8.0-draft.3`, `0.8.0-draft.4`, `0.8.0-rc.1`, and `0.8.0-rc.2`; the protocol-version export is the deduplicated union supported by those snapshots.
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.2` and `0.8.0-rc.3`; `deprecatedSpecifications` contains RC.2. The protocol-version export is the deduplicated union supported by active snapshots.
136
131
 
137
- RC.2 also exports the frozen `mcpExtensionCatalogue` and
132
+ RC.2 and RC.3 also export the frozen `mcpExtensionCatalogue` and
138
133
  `mcpExtensionMaturity` classifier. The catalogue pins its authoritative source,
139
134
  effective date, and official or experimental identifier assignments. Catalogue
140
135
  recognition establishes authority and maturity only; it does not validate
@@ -142,10 +137,10 @@ extension-specific settings.
142
137
 
143
138
  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.
144
139
 
145
- The RC.1 component resolver has one maintainer-approved additive tooling
146
- correction: successful substitutions also report authored and terminal target
147
- paths. The correction does not change the RC.1 schema, validation results,
148
- diagnostics, or fixtures and is recorded in the integrity manifest.
140
+ The RC.2 and RC.3 component resolvers report authored and terminal target
141
+ paths for successful substitutions. The additive tooling corrections do not
142
+ change snapshot schemas, validation results, diagnostics, or fixtures and are
143
+ recorded in the integrity manifest.
149
144
 
150
145
  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.
151
146
 
@@ -159,7 +154,7 @@ exact specification repository tag or commit and then:
159
154
  3. Add the exact selector to the runtime registry and update support metadata, TypeScript declarations, tests, the package changelog, and expected package contents. Unqualified versions, aliases, ranges, and not-yet-published selectors remain unsupported.
160
155
  4. Run the package and repository validation suites. The schema digest, immutable metadata, fixture behavior, browser bundle, declarations, and tarball contents must all pass.
161
156
 
162
- The test snapshots are repository-only development assets and are excluded from the npm tarball. Runtime snapshot implementations and embedded schemas do ship so installed packages remain self-contained.
157
+ The test snapshots are repository-only development assets and are excluded from the npm tarball. Historical runtime sources remain in Git for integrity history. Only active runtime snapshot implementations and embedded schemas ship, so installed packages remain self-contained without accumulating retired selectors.
163
158
 
164
159
  Specification approval and imported supporting code do not authorize package
165
160
  publication. During release review, a maintainer explicitly decides the
@@ -182,4 +177,4 @@ npm run test:browser --workspace @mcpdesc/validator
182
177
  npm run test:package --workspace @mcpdesc/validator
183
178
  ```
184
179
 
185
- The package test runs each immutable snapshot against its own frozen valid, invalid, and warning fixture corpus. YAML source fixtures are decoded by the test harness before validation; the public API continues to accept parsed JavaScript values only. The other checks compile the declarations, bundle the public browser entry with esbuild and Vite, reject runtime AJV compiler inputs and dynamic code generation in those bundles, and inspect `npm pack --dry-run --json` against the intended tarball contents and declared export targets.
180
+ The package test runs each active snapshot against its own frozen valid, invalid, and warning fixture corpus and verifies historical artifact integrity separately. YAML source fixtures are decoded by the test harness before validation; the public API continues to accept parsed JavaScript values only. The other checks compile the declarations, bundle the public browser entry with esbuild and Vite, reject runtime AJV compiler inputs and dynamic code generation in those bundles, and inspect `npm pack --dry-run --json` against the intended tarball contents and declared export targets.
package/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export type McpDescriptionSpecification = '0.8.0-draft.1' | '0.8.0-draft.2' | '0.8.0-draft.3' | '0.8.0-draft.4' | '0.8.0-rc.1' | '0.8.0-rc.2';
1
+ export type McpDescriptionSpecification = '0.8.0-rc.2' | '0.8.0-rc.3';
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.1';
41
+ readonly specification: '0.8.0-rc.2' | '0.8.0-rc.3';
42
42
  }
43
43
 
44
44
  export type McpExtensionMaturity = 'official' | 'experimental' | 'uncatalogued';
@@ -56,36 +56,16 @@ export interface McpExtensionCatalogue {
56
56
  }
57
57
 
58
58
  export interface SpecificationProvenance {
59
- readonly '0.8.0-draft.1': {
60
- readonly snapshotTag: 'v0.8.0-draft.1';
61
- readonly schemaUri: 'https://mcpdesc.org/schema/0.8.0.json';
62
- readonly schemaSha256: '4ceb6042c3fd31703199cd3db869ec5c35c17d2fe9ab7b2f5b96a2a3af0cebe4';
63
- };
64
- readonly '0.8.0-draft.2': {
65
- readonly snapshotTag: 'v0.8.0-draft.2';
66
- readonly schemaUri: 'https://mcpdesc.org/schema/0.8.0.json';
67
- readonly schemaSha256: 'ab692c1a5a0f7e5f29be1940aa8c64a56d4620be0a19d00cf0a64680b7e517fa';
68
- };
69
- readonly '0.8.0-draft.3': {
70
- readonly snapshotTag: 'v0.8.0-draft.3';
71
- readonly schemaUri: 'https://mcpdesc.org/schema/0.8.0.json';
72
- readonly schemaSha256: '8823c1f1946360b2a44d00920e2092e5e4acd139a1964befad4eb0bf3ce96002';
73
- };
74
- readonly '0.8.0-draft.4': {
75
- readonly snapshotTag: 'v0.8.0-draft.4';
76
- readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-draft.4.json';
77
- readonly schemaSha256: '93ed03f74059b5b3ce7509a96b59161bdab2c3cf7734397a9bec5a7588d0b03b';
78
- };
79
- readonly '0.8.0-rc.1': {
80
- readonly snapshotTag: 'v0.8.0-rc.1';
81
- readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.1.json';
82
- readonly schemaSha256: '936a0f24ade501fcabf3d6498c0440c445daa672a575573a35954cee49430ac4';
83
- };
84
59
  readonly '0.8.0-rc.2': {
85
60
  readonly snapshotTag: 'v0.8.0-rc.2';
86
61
  readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.2.json';
87
62
  readonly schemaSha256: '40f6775dde052224114e91d6aa484d826eecf56b77f7ac87b4cf707ffbcb6ce8';
88
63
  };
64
+ readonly '0.8.0-rc.3': {
65
+ readonly snapshotTag: 'v0.8.0-rc.3';
66
+ readonly schemaUri: 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.3.json';
67
+ readonly schemaSha256: 'a9c3ff77ba37c72362909f538f6e957d055e6fdb372f8b3d529e3651af3fecf4';
68
+ };
89
69
  }
90
70
 
91
71
  export interface ResolveMcpDescriptionSpecificationOptions {
@@ -109,7 +89,8 @@ export type McpDescriptionSpecificationResolution =
109
89
  | ResolvedMcpDescriptionSpecification
110
90
  | UnresolvedMcpDescriptionSpecification;
111
91
 
112
- export declare const supportedSpecifications: readonly ['0.8.0-draft.1', '0.8.0-draft.2', '0.8.0-draft.3', '0.8.0-draft.4', '0.8.0-rc.1', '0.8.0-rc.2'];
92
+ export declare const supportedSpecifications: readonly ['0.8.0-rc.2', '0.8.0-rc.3'];
93
+ export declare const deprecatedSpecifications: readonly ['0.8.0-rc.2'];
113
94
 
114
95
  export declare const supportedProtocolVersions: readonly [
115
96
  '2024-11-05',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpdesc/validator",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Structural and semantic validation for MCP Description snapshots",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",
@@ -31,7 +31,8 @@
31
31
  },
32
32
  "files": [
33
33
  "src/index.js",
34
- "src/snapshots",
34
+ "src/snapshots/0.8.0-rc.2",
35
+ "src/snapshots/0.8.0-rc.3",
35
36
  "standalone.js",
36
37
  "index.d.ts",
37
38
  "CHANGELOG.md",
package/src/index.js CHANGED
@@ -1,10 +1,7 @@
1
- import * as draft1 from './snapshots/0.8.0-draft.1/index.js';
2
- import * as draft2 from './snapshots/0.8.0-draft.2/index.js';
3
- import * as draft3 from './snapshots/0.8.0-draft.3/index.js';
4
- import * as draft4 from './snapshots/0.8.0-draft.4/index.js';
5
- import * as rc1 from './snapshots/0.8.0-rc.1/index.js';
6
1
  import * as rc2 from './snapshots/0.8.0-rc.2/index.js';
7
- import { resolveComponentReferences as resolveRc1ComponentReferences } from './snapshots/0.8.0-rc.1/semantic.js';
2
+ import * as rc3 from './snapshots/0.8.0-rc.3/index.js';
3
+ import { resolveComponentReferences as resolveRc2ComponentReferences } from './snapshots/0.8.0-rc.2/semantic.js';
4
+ import { resolveComponentReferences as resolveRc3ComponentReferences } from './snapshots/0.8.0-rc.3/semantic.js';
8
5
  import {
9
6
  mcpExtensionCatalogue,
10
7
  mcpExtensionMaturity
@@ -13,24 +10,22 @@ import {
13
10
  export { mcpExtensionCatalogue, mcpExtensionMaturity };
14
11
 
15
12
  const snapshots = Object.freeze({
16
- [draft1.specification]: draft1,
17
- [draft2.specification]: draft2,
18
- [draft3.specification]: draft3,
19
- [draft4.specification]: draft4,
20
- [rc1.specification]: rc1,
21
- [rc2.specification]: rc2
13
+ [rc2.specification]: rc2,
14
+ [rc3.specification]: rc3
15
+ });
16
+
17
+ const componentResolvers = Object.freeze({
18
+ '0.8.0-rc.2': resolveRc2ComponentReferences,
19
+ '0.8.0-rc.3': resolveRc3ComponentReferences
22
20
  });
23
21
 
24
22
  const schemaUris = Object.freeze({
25
- '0.8.0-draft.1': 'https://mcpdesc.org/schema/0.8.0.json',
26
- '0.8.0-draft.2': 'https://mcpdesc.org/schema/0.8.0.json',
27
- '0.8.0-draft.3': 'https://mcpdesc.org/schema/0.8.0.json',
28
- '0.8.0-draft.4': 'https://mcpdesc.org/schema/mcp-description/0.8.0-draft.4.json',
29
- '0.8.0-rc.1': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.1.json',
30
- '0.8.0-rc.2': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.2.json'
23
+ '0.8.0-rc.2': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.2.json',
24
+ '0.8.0-rc.3': 'https://mcpdesc.org/schema/mcp-description/0.8.0-rc.3.json'
31
25
  });
32
26
 
33
27
  export const supportedSpecifications = Object.freeze(Object.keys(snapshots));
28
+ export const deprecatedSpecifications = Object.freeze(['0.8.0-rc.2']);
34
29
  export const supportedProtocolVersions = Object.freeze([
35
30
  ...new Set(Object.values(snapshots).flatMap((snapshot) => snapshot.supportedProtocolVersions))
36
31
  ]);
@@ -158,9 +153,9 @@ export function resolveMcpDescriptionComponentReferences(document, options) {
158
153
  if (!options || typeof options !== 'object' || Array.isArray(options) || !Object.hasOwn(options, 'specification')) {
159
154
  throw new TypeError('options.specification is required');
160
155
  }
161
- if (options.specification !== '0.8.0-rc.1') {
156
+ if (!Object.hasOwn(componentResolvers, options.specification)) {
162
157
  throw new RangeError(`Component reference resolution does not support specification: ${String(options.specification)}`);
163
158
  }
164
159
 
165
- return resolveRc1ComponentReferences(document);
160
+ return componentResolvers[options.specification](document);
166
161
  }
@@ -62,6 +62,7 @@ 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 = [];
65
66
  let substitutions = 0;
66
67
 
67
68
  function resolve(reference, expectedNamespace, path, stack = []) {
@@ -75,7 +76,7 @@ export function resolveComponentReferences(document, rel = 'document') {
75
76
  `must target #/components/${expectedNamespace}, not #/components/${namespace}`,
76
77
  path
77
78
  ));
78
- return reference;
79
+ return { value: reference };
79
80
  }
80
81
 
81
82
  const key = `${namespace}/${name}`;
@@ -86,7 +87,7 @@ export function resolveComponentReferences(document, rel = 'document') {
86
87
  `forms a cycle through ${[...stack, key].join(' -> ')}`,
87
88
  path
88
89
  ));
89
- return reference;
90
+ return { value: reference };
90
91
  }
91
92
 
92
93
  const target = document?.components?.[namespace]?.[name];
@@ -97,18 +98,29 @@ export function resolveComponentReferences(document, rel = 'document') {
97
98
  `targets missing component ${JSON.stringify(reference.$componentRef)}`,
98
99
  path
99
100
  ));
100
- return reference;
101
+ return { value: reference };
101
102
  }
102
103
  substitutions += 1;
103
104
  return isReferenceObject(target)
104
105
  ? resolve(target, expectedNamespace, path, [...stack, key])
105
- : structuredClone(target);
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;
106
118
  }
107
119
 
108
120
  for (const namespace of componentNamespaces) {
109
121
  for (const [name, value] of Object.entries(document?.components?.[namespace] ?? {})) {
110
122
  if (isReferenceObject(value)) {
111
- resolved.components[namespace][name] = resolve(value, namespace, ['components', namespace, name], [`${namespace}/${name}`]);
123
+ resolved.components[namespace][name] = substitute(value, namespace, ['components', namespace, name], [`${namespace}/${name}`]);
112
124
  }
113
125
  }
114
126
  }
@@ -124,7 +136,7 @@ export function resolveComponentReferences(document, rel = 'document') {
124
136
  if (collection === 'tools') {
125
137
  for (const field of ['inputSchema', 'outputSchema']) {
126
138
  if (isReferenceObject(declaration[field])) {
127
- resolvedDeclaration[field] = resolve(declaration[field], 'schemas', [collection, declarationIndex, field]);
139
+ resolvedDeclaration[field] = substitute(declaration[field], 'schemas', [collection, declarationIndex, field]);
128
140
  }
129
141
  }
130
142
  }
@@ -138,7 +150,7 @@ export function resolveComponentReferences(document, rel = 'document') {
138
150
  : 'promptExamples';
139
151
  for (const [name, example] of Object.entries(declaration.examples ?? {})) {
140
152
  if (isReferenceObject(example)) {
141
- resolvedDeclaration.examples[name] = resolve(
153
+ resolvedDeclaration.examples[name] = substitute(
142
154
  example,
143
155
  exampleNamespace,
144
156
  [collection, declarationIndex, 'examples', name]
@@ -152,7 +164,7 @@ export function resolveComponentReferences(document, rel = 'document') {
152
164
  for (const [declarationIndex, declaration] of (document?.[collection] ?? []).entries()) {
153
165
  for (const [elicitationIndex, elicitation] of (declaration.elicitations ?? []).entries()) {
154
166
  if (isReferenceObject(elicitation.requestedSchema)) {
155
- resolved[collection][declarationIndex].elicitations[elicitationIndex].requestedSchema = resolve(
167
+ resolved[collection][declarationIndex].elicitations[elicitationIndex].requestedSchema = substitute(
156
168
  elicitation.requestedSchema,
157
169
  'schemas',
158
170
  [collection, declarationIndex, 'elicitations', elicitationIndex, 'requestedSchema']
@@ -162,7 +174,7 @@ export function resolveComponentReferences(document, rel = 'document') {
162
174
  }
163
175
  }
164
176
 
165
- return { document: resolved, diagnostics, substitutions };
177
+ return { document: resolved, diagnostics, substitutions, provenance };
166
178
  }
167
179
 
168
180
  function structuralPath(document, error) {
@@ -23,11 +23,25 @@ export const supportedProtocolVersions = Object.freeze([
23
23
  const protocolOrder = new Map(supportedProtocolVersions.map((version, index) => [version, index]));
24
24
  const toolSchemaDialectVersion = '2025-11-25';
25
25
  const completeSemanticConformanceVersion = '2025-06-18';
26
- const knownReservedCapabilityExtensions = new Set([
27
- 'io.modelcontextprotocol/tasks'
28
- ]);
26
+ export const mcpExtensionCatalogue = Object.freeze({
27
+ effectiveDate: '2026-09-04',
28
+ source: 'https://modelcontextprotocol.io/extensions/overview',
29
+ officialIdentifiers: Object.freeze([
30
+ 'io.modelcontextprotocol/enterprise-managed-authorization',
31
+ 'io.modelcontextprotocol/oauth-client-credentials',
32
+ 'io.modelcontextprotocol/tasks',
33
+ 'io.modelcontextprotocol/ui'
34
+ ]),
35
+ experimentalIdentifiers: Object.freeze([])
36
+ });
29
37
  const metaKeyPattern = /^(?:(?:[A-Za-z](?:[A-Za-z0-9-]*[A-Za-z0-9])?)(?:\.[A-Za-z](?:[A-Za-z0-9-]*[A-Za-z0-9])?)*\/)?(?:[A-Za-z0-9](?:[A-Za-z0-9._-]*[A-Za-z0-9])?)?$/;
30
38
 
39
+ export function mcpExtensionMaturity(identifier) {
40
+ if (mcpExtensionCatalogue.officialIdentifiers.includes(identifier)) return 'official';
41
+ if (mcpExtensionCatalogue.experimentalIdentifiers.includes(identifier)) return 'experimental';
42
+ return 'uncatalogued';
43
+ }
44
+
31
45
  function createValidatorForDialect(dialect) {
32
46
  const Factory = dialect === '2020-12' ? Ajv2020 : Ajv;
33
47
  const instance = new Factory({ allErrors: true, strict: false });
@@ -785,20 +799,26 @@ function validateVersionSpecificSemantics(document, rel, diagnostics) {
785
799
  diagnostics.push(
786
800
  makeDiagnostic(
787
801
  'extensions-not-supported-by-version',
788
- 'error',
789
- `capabilities[${index}].extensions is not defined for MCP ${version}; it requires 2026-07-28`,
802
+ 'warning',
803
+ `capabilities[${index}].extensions is not defined by the MCP ${version} core schema; this description preserves a deployed pre-standard extension negotiation convention. Formal extensions capability negotiation was introduced in MCP 2026-07-28`,
790
804
  [...capabilityPath, 'extensions']
791
805
  )
792
806
  );
793
807
  }
794
808
  }
795
809
  for (const identifier of Object.keys(capability.extensions ?? {})) {
796
- if (!usesMcpReservedPrefix(identifier) || knownReservedCapabilityExtensions.has(identifier)) continue;
810
+ if (!usesMcpReservedPrefix(identifier)) continue;
811
+ const maturity = mcpExtensionMaturity(identifier);
812
+ if (maturity === 'official') continue;
797
813
  diagnostics.push(
798
814
  makeDiagnostic(
799
- 'unknown-reserved-extension-identifier',
815
+ maturity === 'experimental'
816
+ ? 'experimental-reserved-extension-identifier'
817
+ : 'unknown-reserved-extension-identifier',
800
818
  'warning',
801
- `capabilities[${index}].extensions contains unrecognized identifier ${JSON.stringify(identifier)} under an MCP-reserved prefix; preserve it and review its authority`,
819
+ maturity === 'experimental'
820
+ ? `capabilities[${index}].extensions contains experimental MCP extension ${JSON.stringify(identifier)}; preserve it and review its maturity before relying on it`
821
+ : `capabilities[${index}].extensions contains unrecognized identifier ${JSON.stringify(identifier)} under an MCP-reserved prefix; preserve it and review its authority`,
802
822
  [...capabilityPath, 'extensions', identifier]
803
823
  )
804
824
  );
@@ -3,9 +3,9 @@ import {
3
3
  validateMcpdesc08Document
4
4
  } from './semantic.js';
5
5
 
6
- export const specification = '0.8.0-rc.1';
7
- export const snapshotTag = 'v0.8.0-rc.1';
8
- export const schemaSha256 = '936a0f24ade501fcabf3d6498c0440c445daa672a575573a35954cee49430ac4';
6
+ export const specification = '0.8.0-rc.3';
7
+ export const snapshotTag = 'v0.8.0-rc.3';
8
+ export const schemaSha256 = 'a9c3ff77ba37c72362909f538f6e957d055e6fdb372f8b3d529e3651af3fecf4';
9
9
  export { supportedProtocolVersions };
10
10
 
11
11
  export function validate(document) {