@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.
@@ -1,4 +1,4 @@
1
- // Validate the immutable 0.8.0-rc.1 snapshot using only snapshot-local artifacts.
1
+ // Validate the immutable 0.8.0-rc.3 snapshot using only snapshot-local artifacts.
2
2
 
3
3
  import Ajv from 'ajv';
4
4
  import Ajv2020 from 'ajv/dist/2020.js';
@@ -6,11 +6,13 @@ import addFormats from 'ajv-formats';
6
6
  import { UriTemplateMatcher } from 'uri-template-matcher';
7
7
  import schema from './schema.json' with { type: 'json' };
8
8
  import {
9
+ mcpExtensionCatalogue,
10
+ mcpExtensionMaturity,
9
11
  semanticValidateDocument as validateBaseSemantics,
10
12
  supportedProtocolVersions
11
13
  } from './base.js';
12
14
 
13
- export { supportedProtocolVersions };
15
+ export { mcpExtensionCatalogue, mcpExtensionMaturity, supportedProtocolVersions };
14
16
 
15
17
  const TOOL_INTERACTION_SENTINEL = '__interaction_example__';
16
18
  const ajv = new Ajv2020({ allErrors: true, strict: false });
@@ -21,7 +23,6 @@ const validateStructure = ajv.compile(schema);
21
23
  const primitiveCollections = ['tools', 'resources', 'resourceTemplates', 'prompts'];
22
24
  const componentNamespaces = ['schemas', 'toolExamples', 'resourceExamples', 'resourceTemplateExamples', 'promptExamples'];
23
25
  const knownClientCapabilities = new Set(['roots', 'sampling', 'elicitation', 'tasks', 'extensions', 'experimental']);
24
- const knownReservedCapabilityExtensions = new Set(['io.modelcontextprotocol/tasks']);
25
26
  const protocolOrder = new Map(supportedProtocolVersions.map((version, index) => [version, index]));
26
27
 
27
28
  const clientCapabilitiesByVersion = {
@@ -66,7 +67,7 @@ export function resolveComponentReferences(document, rel = 'document') {
66
67
 
67
68
  function resolve(reference, expectedNamespace, path, stack = []) {
68
69
  const match = /^#\/components\/([^/]+)\/([^/]+)$/.exec(reference?.$componentRef ?? '');
69
- if (!match) return { value: reference };
70
+ if (!match) return reference;
70
71
  const [, namespace, name] = match;
71
72
  if (namespace !== expectedNamespace) {
72
73
  diagnostics.push(componentDiagnostic(
@@ -581,7 +582,17 @@ function validateClientRequirements(document) {
581
582
  validateTasks(value, location, path, version);
582
583
  } else if (capability === 'extensions') {
583
584
  for (const extension of Object.keys(value)) {
584
- if (usesMcpReservedPrefix(extension) && !knownReservedCapabilityExtensions.has(extension)) {
585
+ if (!usesMcpReservedPrefix(extension)) continue;
586
+ const maturity = mcpExtensionMaturity(extension);
587
+ if (maturity === 'official') continue;
588
+ if (maturity === 'experimental') {
589
+ diagnostics.push(semanticDiagnostic(
590
+ 'experimental-reserved-extension-identifier',
591
+ 'warning',
592
+ `${location} contains experimental MCP extension ${JSON.stringify(extension)}; preserve it and review its maturity before relying on it`,
593
+ [...path, extension]
594
+ ));
595
+ } else {
585
596
  diagnostics.push(semanticDiagnostic(
586
597
  'unknown-reserved-extension-identifier',
587
598
  'warning',