@mcpdesc/validator 0.11.0 → 0.11.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,15 @@ Dates for published releases are the UTC publication dates recorded by npm.
8
8
 
9
9
  ## [Unreleased]
10
10
 
11
+ ## [0.11.1] - 2026-09-08
12
+
13
+ ### Fixed
14
+
15
+ - Added terminal-target provenance to RC.4 component reference resolution and
16
+ enabled RC.4 through the public resolver. This is an approved additive
17
+ tooling-metadata correction; schemas, conformance results, diagnostics, and
18
+ frozen fixtures are unchanged.
19
+
11
20
  ## [0.11.0] - 2026-09-08
12
21
 
13
22
  ### Added
@@ -155,7 +164,8 @@ Dates for published releases are the UTC publication dates recorded by npm.
155
164
  - Added synchronous structural and semantic validation for parsed JavaScript values with deterministic diagnostics and exact selector dispatch.
156
165
  - Added ESM browser support, TypeScript declarations, embedded schema provenance, frozen fixtures, and package-content checks.
157
166
 
158
- [Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.11.0...HEAD
167
+ [Unreleased]: https://github.com/mcpdesc/core/compare/validator-v0.11.1...HEAD
168
+ [0.11.1]: https://github.com/mcpdesc/core/compare/validator-v0.11.0...validator-v0.11.1
159
169
  [0.11.0]: https://github.com/mcpdesc/core/compare/validator-v0.10.1...validator-v0.11.0
160
170
  [0.10.1]: https://github.com/mcpdesc/core/compare/validator-v0.10.0...validator-v0.10.1
161
171
  [0.10.0]: https://github.com/mcpdesc/core/compare/validator-v0.9.0...validator-v0.10.0
package/README.md CHANGED
@@ -57,9 +57,8 @@ 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.
60
+ Component reference resolution is available for RC.3 and RC.4 with
61
+ terminal-target provenance for each authored reference.
63
62
 
64
63
  ## Usage
65
64
 
@@ -141,9 +140,9 @@ maturity only; it does not validate extension-specific settings.
141
140
 
142
141
  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.
143
142
 
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.
143
+ The RC.3 and RC.4 component resolvers report authored and terminal target paths
144
+ for successful substitutions. Additive tooling corrections that provide this
145
+ metadata are recorded explicitly in the integrity manifest.
147
146
 
148
147
  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.
149
148
 
package/index.d.ts CHANGED
@@ -38,7 +38,7 @@ export interface McpDescriptionComponentResolutionResult {
38
38
  }
39
39
 
40
40
  export interface ResolveMcpDescriptionComponentReferencesOptions {
41
- readonly specification: '0.8.0-rc.3';
41
+ readonly specification: '0.8.0-rc.3' | '0.8.0-rc.4';
42
42
  }
43
43
 
44
44
  export type McpExtensionMaturity = 'official' | 'experimental' | 'uncatalogued';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mcpdesc/validator",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "Structural and semantic validation for MCP Description snapshots",
5
5
  "type": "module",
6
6
  "types": "./index.d.ts",
package/src/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import * as rc3 from './snapshots/0.8.0-rc.3/index.js';
2
2
  import * as rc4 from './snapshots/0.8.0-rc.4/index.js';
3
3
  import { resolveComponentReferences as resolveRc3ComponentReferences } from './snapshots/0.8.0-rc.3/semantic.js';
4
+ import { resolveComponentReferences as resolveRc4ComponentReferences } from './snapshots/0.8.0-rc.4/semantic.js';
4
5
  import {
5
6
  mcpExtensionCatalogue,
6
7
  mcpExtensionMaturity
@@ -14,7 +15,8 @@ const snapshots = Object.freeze({
14
15
  });
15
16
 
16
17
  const componentResolvers = Object.freeze({
17
- '0.8.0-rc.3': resolveRc3ComponentReferences
18
+ '0.8.0-rc.3': resolveRc3ComponentReferences,
19
+ '0.8.0-rc.4': resolveRc4ComponentReferences
18
20
  });
19
21
 
20
22
  const schemaUris = Object.freeze({
@@ -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) {