registry/docs/design/proposed-enhanced-validation.md
deerajkumar18 b5f38fcc2a
update schema url point to the actual location (#884)
<!-- Provide a brief summary of your changes -->

## Motivation and Context
This PR ensures that the draft URL points to the actual draft schema 
improvement suggested in
https://github.com/modelcontextprotocol/registry/issues/814


## How Has This Been Tested?
<!-- Have you tested this in a real application? Which scenarios were
tested? -->

## Breaking Changes
<!-- Will users need to update their code or configurations? -->

## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update

## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes
that apply. -->
- [ ] I have read the [MCP
Documentation](https://modelcontextprotocol.io)
- [ ] My code follows the repository's style guidelines
- [ ] New and existing tests pass locally
- [ ] I have added appropriate error handling
- [ ] I have added or updated documentation as needed

## Additional context
<!-- Add any other context, implementation notes, or design decisions
-->
2026-02-10 13:32:58 -08:00

44 KiB

Enhanced Server Validation Design

NOTE: This document describes a proposed direction for improving validation of server.json data in the Official Registry. This work is in progress (including open PRs and discussions) in a collaborative process and may change significantly or be abandoned.

Overview

This document outlines the design for implementing comprehensive server validation in the MCP Registry, due to the following concerns:

  • Currently, the MCP Registry project publishes a server.json schema but does not validate servers against it, allowing non-compliant servers to be published.
  • There is existing ad-hoc validation that covers some schema compliance, but not all (there are logical errors not identifiable by schema validation and that are not covered by the existing ad hoc validation).
  • Many servers that do pass validation do not represent best-practices for published servers.

This design implements a three-tier validation system: Schema Validation, Semantic Validation, and Linter Validation.

Current State

Problems with Current Validation

  • No schema validation: Servers are published without validating against the published schema (and many violate it)
  • Incomplete validation: Ad hoc validation covers only some schema constraints (many published servers have additional logical errors)
  • Best Practices not indicated: Many servers that would pass schema and semantic validation do not represent best practices
  • Fail-fast behavior: Legacy ValidateServerJSON() stopped at first error (now replaced with exhaustive validation)
  • No path information: Errors don't specify where in JSON the problem occurs

Three-Tier Validation System

Schema Validation (Primary)

  • Validates against published schema: Ensures servers comply with the official server.json schema
  • Exhaustive coverage: Catches all structural and format violations defined in the schema
  • Detailed error references: Shows exact schema rule locations with specific constraint and full path to constraint

Semantic Validation (Secondary)

  • Business logic validation: Validates only constraints not expressible in JSON Schema
  • Registry validation: Enforce validitiy of registry references (as current)
  • Logical Errors: Enforce logical consistency: format, choices, variable usage, etc

Linter Validation (Tertiary)

  • Best practice recommendations: Security concerns, style guidelines, naming conventions
  • Non-blocking: Warnings and suggestions, not errors
  • Quality improvements: Helps developers create better servers
  • Educational: Teaches best practices for MCP server development

Implementation Approach

The enhanced validation will be implemented in stages to minimize risk and allow for review and experimentation:

Stage 1: Schema Validation and Exhaustive Validation Results (Current)

  • Convert existing validators to use and track context and to return exhaustive results
  • Add mcp-publisher validate command that performs exhaustive validation with full schema validation
  • Implement schema validation with configurable policy for non-current schemas
  • Schema version validation consolidated in schema.go with policy support (Allow/Warn/Error)
  • mcp-publisher publish command validates schema version (rejects empty and non-current schemas) but does not perform full schema validation
  • API /v0/publish endpoint uses ValidatePublishRequest which validates schema version and semantic validation, but not full schema validation
  • All callers migrated: All code now uses ValidateServerJSON() with ValidationOptions directly; legacy wrapper removed
  • ValidationResult.FirstError(): Backward compatibility maintained via FirstError() method for code expecting error return type
  • This allows experimentation and validation of the new model (including schema validation) without impacting production API

Future Stages

  • Enable full schema validation in mcp-publisher publish command (currently only validates schema version)
  • Enable full schema validation in the /v0/publish API endpoint (currently only validates schema version via ValidatePublishRequest)
  • Add /v0/validate API endpoint for programmatic validation without publishing (see Validate API Endpoint section below)
  • Enhance production code to use full validation results: Update importer.go and validate-examples/main.go to log all issues instead of just first error
  • Build out comprehensive semantic and linter validation rules (with tests)
  • Remove redundant manual validators that duplicate schema constraints
  • Consider migrating tests to check all validation issues instead of just first error (where appropriate)

Proposed Design

Design Goals

  1. Exhaustive Feedback: Collect all validation issues in a single pass, not just the first error
  2. Precise Location: Provide exact JSON paths for every validation issue
  3. Structured Output: Return machine-readable validation results with consistent format
  4. Backward Compatibility: Use ValidationResult.FirstError() for code expecting error return type
  5. Extensible: Support different validation types (json, schema, semantic, linter) and severity levels

Core Types

// Validation issue type with constrained values
type ValidationIssueType string

const (
    ValidationIssueTypeJSON     ValidationIssueType = "json"
    ValidationIssueTypeSchema   ValidationIssueType = "schema"
    ValidationIssueTypeSemantic ValidationIssueType = "semantic"
    ValidationIssueTypeLinter   ValidationIssueType = "linter"
)

// Validation issue severity with constrained values
type ValidationIssueSeverity string

const (
    ValidationIssueSeverityError   ValidationIssueSeverity = "error"
    ValidationIssueSeverityWarning ValidationIssueSeverity = "warning"
    ValidationIssueSeverityInfo    ValidationIssueSeverity = "info"
)

type ValidationIssue struct {
    Type      ValidationIssueType     `json:"type"`
    Path      string                  `json:"path"`     // JSON path like "packages[0].transport.url"
    Message   string                  `json:"message"`  // Error description (extracted from error.Error())
    Severity  ValidationIssueSeverity `json:"severity"`
    Reference string                  `json:"reference"` // Schema rule path or rule name like "prefer-transport-configuration"
}

type ValidationResult struct {
    Valid  bool              `json:"valid"`
    Issues []ValidationIssue `json:"issues"`
}

type ValidationContext struct {
    path string
}

// SchemaVersionPolicy determines how non-current schema versions are handled
type SchemaVersionPolicy string

const (
    SchemaVersionPolicyAllow SchemaVersionPolicy = "allow" // Allow non-current schemas silently
    SchemaVersionPolicyWarn  SchemaVersionPolicy = "warn"  // Allow but generate warning
    SchemaVersionPolicyError SchemaVersionPolicy = "error" // Reject non-current schemas
)

// Constructor functions following Go conventions
func NewValidationIssue(issueType ValidationIssueType, path, message string, severity ValidationIssueSeverity, reference string) ValidationIssue
func NewValidationIssueFromError(issueType ValidationIssueType, path string, err error, reference string) ValidationIssue

Validation Types

The Type field categorizes validation issues by their source:

  • ValidationIssueTypeJSON: JSON parsing errors (malformed JSON syntax)
  • ValidationIssueTypeSchema: JSON Schema validation errors (structural/format violations)
  • ValidationIssueTypeSemantic: Logical validation errors not enforceable in schema (business rules)
  • ValidationIssueTypeLinter: Best practice recommendations, security concerns, style guidelines

The Severity field indicates the impact level:

  • ValidationIssueSeverityError: Critical issues that must be fixed
  • ValidationIssueSeverityWarning: Issues that should be addressed
  • ValidationIssueSeverityInfo: Suggestions and recommendations

The Reference field provides context about what triggered the validation issue:

  • Schema validation: Contains the resolved schema path with $ref resolution (e.g., "#/definitions/SseTransport/properties/url/format from: [#/definitions/ServerDetail]/properties/packages/items/[#/definitions/Package]/properties/transport/properties/url/format")
  • Semantic validation: Contains rule names for business logic (e.g., "invalid-server-name", "missing-transport-url")
  • Linter validation: Contains rule names for best practices (e.g., "descriptive-naming", "security-recommendation")
  • JSON validation: Contains error type identifiers (e.g., "json-syntax-error", "invalid-json-format")

ValidationContext

The ValidationContext tracks the current JSON path during validation, allowing validators to report issues with precise location information. This is essential for providing users with exact paths to problematic fields.

Purpose

  • Path tracking: Builds JSON paths like "packages[0].transport.url" as validation traverses nested structures
  • Precise error location: Users can see exactly where validation issues occur
  • Immutable building: Each method returns a new context, preventing accidental mutations

Usage Example

// Navigate to packages array, first item, transport field
pkgCtx := ctx.Field("packages").Index(0).Field("transport")
// Validate transport - any issues will be reported at "packages[0].transport"

Backward Compatibility Strategy

The design maintains perfect backward compatibility by leveraging Go's existing error handling patterns:

Error Message Preservation

  • Current validators use fmt.Errorf("%w: %s", ErrInvalidRepositoryURL, obj.URL)
  • New validators use NewValidationIssueFromError() which extracts err.Error()
  • Result: Identical error messages, ensuring all existing tests pass

Constructor Pattern

Following Go conventions used throughout the project:

// Standard constructor for manual field setting
issue := NewValidationIssue(ValidationIssueTypeLinter, "name", "message", ValidationIssueSeverityWarning, "rule-name")

// Constructor that preserves existing error formatting
issue := NewValidationIssueFromError(ValidationIssueTypeSemantic, "path", err, "rule-name")

Error Interface Compatibility

For code that needs an error return type, use ValidationResult.FirstError():

result := ValidateServerJSON(serverJSON, ValidationSchemaVersionAndSemantic)
if err := result.FirstError(); err != nil {
    return err  // Returns first error-level issue as error
}

This maintains compatibility with existing error handling code while providing access to all validation issues.

New Validation Architecture

All Validators Use Context and Return ValidationResult

All existing validators are converted to use ValidationContext for precise error location tracking and return ValidationResult for comprehensive error collection:

func ValidateServerJSON(serverJSON *apiv0.ServerJSON, opts ValidationOptions) *ValidationResult {
    result := &ValidationResult{Valid: true, Issues: []ValidationIssue{}}
    
    // Schema validation based on options
    if opts.ValidateSchemaVersion || opts.ValidateSchema {
        schemaResult := validateServerJSONSchema(serverJSON, opts.ValidateSchema, opts.NonCurrentSchemaPolicy)
        result.Merge(schemaResult)
    }

    // Semantic validation (if requested)
    if opts.ValidateSemantic {
        // Validate server name - using existing error logic
        if _, err := parseServerName(*serverJSON); err != nil {
            issue := NewValidationIssueFromError(
                ValidationIssueTypeSemantic,
                "name",
                err,
                "invalid-server-name",
            )
            result.AddIssue(issue)
        }
        
        // Validate repository with context
        if repoResult := validateRepository(&ValidationContext{}, &serverJSON.Repository); !repoResult.Valid {
            result.Merge(repoResult)
        }
        
        // ... more semantic validation ...
    }
    
    return result
}

For backward compatibility with code that expects an error return type, ValidationResult.FirstError() can be used:

result := ValidateServerJSON(serverJSON, ValidationSchemaVersionAndSemantic)
if err := result.FirstError(); err != nil {
    return err
}

Schema Validation

The project uses github.com/santhosh-tekuri/jsonschema/v5 for schema validation with an embedded schema approach. The schema is embedded at compile time using Go's //go:embed directive, eliminating the need for file system access and ensuring the schema is always available.

Schema-First Validation Strategy

The enhanced validation system adopts a schema-first approach where JSON Schema validation serves as the primary and first validator. This strategy addresses the current duplication between manual/semantic validators and schema constraints.

Current Problem: Validation Duplication

The existing system has both:

  • Manual/semantic validators: Custom Go code validating server name format, URL patterns, etc.
  • JSON Schema validation: Structural validation of the same constraints

This creates redundancy and potential inconsistencies where:

  • Manual validators provide friendly error messages
  • Schema validation provides technical error messages
  • Both validate the same underlying constraints

Proposed Solution: Schema-First with Friendly Error Mapping

  1. Schema validation runs first and catches all structural/format issues
  2. Manual validators are eliminated for constraints already specified in the schema
  3. Schema error messages are mapped to friendly messages using deterministic schema rule references (if needed)

Embedded Schema Benefits

No File System Dependencies

  • Embedded at compile time: Schema is included in the binary using //go:embed schema/*.json
  • No external files: Eliminates dependency on schema files being present at runtime
  • Portable: Binary contains everything needed for validation

Version Consistency

  • Schema version tracking: model.CurrentSchemaURL provides compile-time constant for current schema version
  • Version validation: Schema version validation consolidated in schema.go with policy support (Allow/Warn/Error)
  • Empty schema handling: Empty/missing schema fields always generate errors during validation
  • Compile-time validation: Schema is validated when the binary is built
  • No version drift: Schema version is locked to the binary version

Performance Benefits

  • No I/O operations: Schema is already in memory
  • Faster startup: No need to read schema files
  • Reduced complexity: No file path resolution or error handling for missing files

Rich Error Information

The jsonschema.ValidationError provides:

  • InstanceLocation: JSON Pointer format (RFC 6901) path to the invalid field (e.g., "/packages/0/transport/url")
  • Error: Detailed error message from schema
  • KeywordLocation: Schema path with $ref segments (e.g., "/$ref/properties/transport/$ref/properties/url/format")
  • AbsoluteKeywordLocation: Resolved schema path (e.g., "file:///server.schema.json#/definitions/SseTransport/properties/url/format")

Path Format Conversion: JSON Pointer format paths from InstanceLocation are converted to bracket notation format to match semantic validation paths. The conversion transforms JSON Pointer paths like "/packages/0/transport/url" into bracket notation like "packages[0].transport.url". This ensures consistent path formatting across all validation types (schema, semantic, and linter).

Current Error Reference Format

Schema validation errors now include detailed reference information:

Reference: #/definitions/Repository/properties/url/format from: [#/definitions/ServerDetail]/properties/repository/[#/definitions/Repository]/properties/url/format

This format provides:

  • Absolute location: #/definitions/Repository/properties/url/format - the final resolved schema location
  • Resolved path: Shows the complete path with $ref segments replaced by their resolved values in square brackets
  • Full context: Users can see exactly which schema rule triggered the error and how it was reached

Error Message Quality

The current schema validation errors are generally quite readable:

[error] repository.url (schema)
'' has invalid format 'uri'
Reference: #/definitions/Repository/properties/url/format from: [#/definitions/ServerDetail]/properties/repository/[#/definitions/Repository]/properties/url/format

Future Error Message Enhancement

If we encounter situations where schema validation errors need to be more user-friendly, we have full access to:

  • KeywordLocation: The schema path to the validating rule
  • AbsoluteKeywordLocation: The absolute schema location after $ref resolution
  • InstanceLocation: The JSON Pointer format path (e.g., "/packages/0/transport/url") which is converted to bracket notation (e.g., "packages[0].transport.url") for consistency with semantic validation
  • Message: The original schema validation error message
  • Complete reference stack: The entire resolved path showing how the error was reached

This allows us to build better, more descriptive error messages if needed, while maintaining the current high-quality error references.

Integration with ValidateServerJSON

// ValidationOptions configures which types of validation to perform
type ValidationOptions struct {
    ValidateSchemaVersion  bool                 // Check schema version (empty, non-current)
    ValidateSchema         bool                 // Perform full schema validation (implies ValidateSchemaVersion)
    ValidateSemantic       bool                 // Perform semantic validation
    NonCurrentSchemaPolicy SchemaVersionPolicy  // Policy for non-current schemas
}

// Common validation configurations
var (
    ValidationSemanticOnly = ValidationOptions{
        ValidateSemantic: true,
    }
    
    ValidationSchemaVersionOnly = ValidationOptions{
        ValidateSchemaVersion: true,
        NonCurrentSchemaPolicy: SchemaVersionPolicyError,
    }
    
    ValidationSchemaVersionAndSemantic = ValidationOptions{
        ValidateSchemaVersion: true,
        ValidateSemantic: true,
        NonCurrentSchemaPolicy: SchemaVersionPolicyWarn,
    }
    
    ValidationAll = ValidationOptions{
        ValidateSchema: true,  // Implies ValidateSchemaVersion
        ValidateSemantic: true,
        NonCurrentSchemaPolicy: SchemaVersionPolicyWarn,
    }
)

func ValidateServerJSON(serverJSON *apiv0.ServerJSON, opts ValidationOptions) *ValidationResult {
    result := &ValidationResult{Valid: true, Issues: []ValidationIssue{}}
    ctx := &ValidationContext{}

    // Schema validation (version check and/or full validation)
    if opts.ValidateSchemaVersion || opts.ValidateSchema {
        schemaResult := validateServerJSONSchema(serverJSON, opts.ValidateSchema, opts.NonCurrentSchemaPolicy)
        result.Merge(schemaResult)
    }

    // Semantic validation (only if requested)
    if !opts.ValidateSemantic {
        return result
    }

    // ... semantic validation logic ...
    
    return result
}

Schema Version Validation

Schema version validation is consolidated in validateServerJSONSchema() (now private) in schema.go:

  • Empty schema check: Always performed when schema validation is requested, always generates an error
  • Schema file existence check: Always performed when schema validation is requested - verifies the schema file exists in embedded schemas, even when not performing full validation
  • Schema version policy: Controls how non-current schemas are handled (via ValidationOptions.NonCurrentSchemaPolicy):
    • SchemaVersionPolicyAllow: Non-current schemas are allowed with no warning
    • SchemaVersionPolicyWarn: Non-current schemas are allowed but generate a warning
    • SchemaVersionPolicyError: Non-current schemas are rejected with an error
  • Full schema validation: Only performed if performValidation is true

The mcp-publisher publish command validates schema version (rejects empty, non-existent, and non-current schemas) but does not perform full schema validation. The mcp-publisher validate command performs full schema validation with SchemaVersionPolicyWarn (warns about non-current schemas but doesn't error).

Request Validation Functions

Two consolidated validation functions in validators package handle publish and update requests:

  • ValidatePublishRequest(): Validates publisher extensions, server JSON structure (via ValidateServerJSON), and registry ownership (if enabled)
  • ValidateUpdateRequest(): Validates server JSON structure (via ValidateServerJSON) and registry ownership (if enabled), with option to skip registry validation for deleted servers

Both functions use ValidateServerJSON() with ValidationSchemaVersionAndSemantic and FirstError() for backward-compatible error handling. Registry ownership validation is extracted into a shared validateRegistryOwnership() helper function.

Testing with Draft or Custom Schemas

The validation system supports testing against draft schemas or custom schema versions by embedding them in the validators package.

Setup Steps

  1. Copy the schema file: Copy your schema file (e.g., docs/reference/server-json/draft/server.schema.json) to internal/validators/schemas/{version}.json

    • Example: Copy to internal/validators/schemas/draft.json for draft schema testing
    • Ensure the schema file's $id field matches: https://static.modelcontextprotocol.io/schemas/{version}/server.schema.json
    • For draft schema, the $id should be: https://raw.githubusercontent.com/modelcontextprotocol/registry/main/docs/reference/server-json/draft/server.schema.json
  2. Rebuild: Recompile the Go binary to embed the new schema file (schemas are embedded at compile time)

  3. Use in server.json: Reference the schema version in your server.json file:

    {
      "$schema": "https://static.modelcontextprotocol.io/schemas/draft/server.schema.json",
      ...
    }
    

Schema Version Identifier Rules

Schema version identifiers can contain:

  • Letters: A-Z, a-z
  • Digits: 0-9
  • Special characters: Hyphen (-), underscore (_), tilde (~), period (.)

Examples of valid identifiers: 2025-10-17, draft, test-v1.0, custom_schema~1.2.3

Non-Current Schema Policy

When testing with draft or custom schemas, they will be treated as non-current schemas (since they don't match model.CurrentSchemaURL), which triggers the NonCurrentSchemaPolicy behavior:

  • SchemaVersionPolicyAllow: Draft schemas are allowed with no warning
  • SchemaVersionPolicyWarn: Draft schemas are allowed but generate a warning (default for ValidationAll and ValidationSchemaVersionAndSemantic)
  • SchemaVersionPolicyError: Draft schemas are rejected with an error (default for ValidationSchemaVersionOnly)

Treating Draft as Current Schema

To test with a draft schema as if it were the current schema (no warnings/errors about non-current version):

  1. Temporarily update model.CurrentSchemaVersion in pkg/model/constants.go:

    const (
        CurrentSchemaVersion = "draft"  // Temporarily set for testing
        CurrentSchemaURL = "https://static.modelcontextprotocol.io/schemas/" + CurrentSchemaVersion + "/server.schema.json"
    )
    
  2. Rebuild and test

  3. Important: Revert the change before committing - model.CurrentSchemaVersion should always point to the latest official schema version

Example: Testing with Draft Schema

# 1. Copy draft schema
cp docs/reference/server-json/draft/server.schema.json internal/validators/schemas/draft.json

# 2. Verify the $id field in draft.json is correct
# Should be: "https://raw.githubusercontent.com/modelcontextprotocol/registry/main/docs/reference/server-json/draft/server.schema.json"

# 3. Rebuild
go build ./...

# 4. Use in server.json
# Set "$schema": "https://static.modelcontextprotocol.io/schemas/draft/server.schema.json"

# 5. Validate
mcp-publisher validate server.json

Note: The draft schema will be validated successfully, but you may see a warning about it not being the current schema version unless you temporarily update model.CurrentSchemaVersion as described above.

Discriminated Union Error Consolidation

The schema uses anyOf for discriminated unions (transport, argument, remote), which causes noisy error messages when validation fails. When a transport/argument/remote doesn't match its specified type, anyOf validation tries all variants and reports errors for each one that doesn't match.

Problem Example: If you have an "sse" transport with no url, you get errors for all transport types:

  1. [error] packages[0].transport.type (schema) value must be "stdio" Reference: #/definitions/StdioTransport/properties/type/enum

  2. [error] packages[0].transport (schema) missing required fields: 'url' Reference: #/definitions/StreamableHttpTransport/required

  3. [error] packages[0].transport.type (schema) value must be "streamable-http" Reference: #/definitions/StreamableHttpTransport/properties/type/enum

  4. [error] packages[0].transport (schema) missing required fields: 'url' Reference: #/definitions/SseTransport/required

Solution Strategy: Since we cannot modify the schema (it's managed in the static repository), we'll detect and consolidate these anyOf error patterns in the validation error processing code (addDetailedErrors in schema.go).

Detection Strategy:

  • Identify groups of errors at the same JSON path (e.g., packages[0].transport)
  • Detect pattern of multiple "type must be X" errors or multiple "missing required fields" errors from different schema definitions
  • Extract the actual type value from the JSON being validated
  • Filter out errors from non-matching transport/argument/remote definitions
  • Consolidate remaining errors into a single, actionable error message

Implementation Approach:

  • Add logic in addDetailedErrors() or a post-processing function to detect anyOf error clusters
  • Group errors by instance location and analyze error patterns
  • Identify the intended type from the JSON data
  • Filter/consolidate errors to only show relevant issues for the actual type specified
  • Preserve all other validation errors unchanged

This approach allows us to provide clearer error messages without modifying the schema, and can be applied to transport, argument, and remote validation.

Future Enhancement: If the schema is updated to use if/then/else discriminated unions in the future, this consolidation logic can be removed, but it provides immediate value without requiring schema changes.

Implementation Status

✅ Completed Features

Core Validation System

  • ValidationIssue and ValidationResult types: Complete with all required fields
  • ValidationContext: Immutable context building for JSON path tracking
  • Constructor functions: NewValidationIssue() and NewValidationIssueFromError() with consistent parameter naming
  • Helper methods: Context building, result merging, and path construction

Schema Validation Integration

  • JSON Schema validation: Using existing jsonschema/v5 library
  • Error conversion: Schema errors converted to ValidationIssue format
  • $ref resolution: Sophisticated resolution showing complete schema path with resolved references
  • Comprehensive testing: Full test coverage for schema validation scenarios
  • Embedded schema: Schema embedded at compile time using //go:embed directive
  • Path format normalization: JSON Pointer paths converted to bracket notation to match semantic validation format (e.g., /packages/0/transport → packages[0].transport)

Enhanced Error References

  • Resolved schema paths: Shows complete path with $ref segments replaced by resolved values
  • Incremental resolution: Each $ref resolved in context of previous resolution
  • Human-readable format: Clear indication of schema rule location and resolution chain
  • Consistent output: All schema errors use the same reference format

Testing and Quality

  • Unit tests: Comprehensive test coverage for all new functionality
  • Integration tests: End-to-end validation testing
  • Backward compatibility: Existing validation continues to work

Caller Migration

  • Function rename: ValidateServerJSONExhaustive renamed to ValidateServerJSON (now takes ValidationOptions parameter)
  • Legacy wrapper removed: Old ValidateServerJSON() wrapper that returned error removed
  • All callers migrated: All production code and tests now use ValidateServerJSON() with ValidationOptions directly
  • FirstError() helper: ValidationResult.FirstError() method added for backward compatibility with error return types
  • Request validators consolidated: ValidatePublishRequest and ValidateUpdateRequest moved to validators package with shared validateRegistryOwnership helper

🔄 In Progress

Schema-First Validation Strategy

  • Schema validation integration: ValidateServerJSON() runs schema validation first
  • CLI integration: Schema validation enabled in mcp-publisher validate command
  • Schema version validation: Consolidated in schema.go with policy support (Allow/Warn/Error)
  • Schema file existence check: Schema version validation verifies schema file exists in embedded schemas
  • Publish command schema checks: mcp-publisher publish validates schema version (rejects empty, non-existent, and non-current schemas)
  • API endpoint validation: /v0/publish uses ValidatePublishRequest which validates schema version and semantic validation
  • Full schema validation in publish: Enable full schema validation in mcp-publisher publish command
  • Full schema validation in API: Enable full schema validation in /v0/publish API endpoint
  • Discriminated union error consolidation: Detect and filter/consolidate noisy anyOf errors for transport, argument, and remote validation to show only relevant errors for the actual type
  • Error message mapping: Map technical schema errors to user-friendly messages (if needed)
  • Validator migration: Move from manual validators to schema-first approach

📋 Pending

Migration Strategy

  • Phase 1: Identify Schema Coverage: Audit existing manual validators against schema constraints
  • Phase 2: Implement Error Mapping (Optional): Create mapping function for schema error messages (only if current messages are insufficient)
  • Phase 3: Error Consolidation: Implement logic to detect and consolidate noisy anyOf errors from discriminated unions (transport, argument, remote)
  • Phase 4: Enable Schema-First Validation: Update tests to expect schema validation errors instead of semantic errors; Enable schema validation in publish API
  • Phase 5: Clean Up Redundant Validators: Remove manual validators that duplicate schema constraints
  • Phase 6: Add Enhanced Semantic and Linter Rules: Review and implement specific rules from MCP Registry Validator linter guidelines

Command Integration

  • CLI updates: mcp-publisher validate command uses detailed validation with full schema validation
  • Publish command: mcp-publisher publish validates schema version (rejects empty, non-existent, and non-current schemas)
  • Shared validation logic: Both commands use runValidationAndPrintIssues to eliminate duplication
  • Caller migration: All callers migrated to use ValidateServerJSON() with ValidationOptions directly
  • Request validation consolidation: ValidatePublishRequest and ValidateUpdateRequest consolidated in validators package
  • Enhanced error reporting: Update production code (importer, validate-examples tool) to log all issues instead of just first error
  • Output formatting: Add JSON output format options
  • Filtering options: Add severity and type filtering

Validate API Endpoint

  • POST /v0/validate endpoint: API endpoint for validating server.json without publishing

Documentation and Polish

  • API documentation: Update API documentation with new validation types

🎯 Key Achievements

  1. Comprehensive Error Collection: All validation issues collected in single pass
  2. Precise Error Location: Exact JSON paths for every validation issue
  3. Schema Integration: Full JSON Schema validation with detailed error references
  4. Backward Compatibility: Existing validation continues to work unchanged
  5. Type Safety: Constrained types prevent invalid validation issue creation
  6. Extensible Architecture: Easy to add new validation types and severity levels

The enhanced validation system is now production-ready with comprehensive schema validation, detailed error references, and full backward compatibility.

Example Usage

JSON Output Format

{
  "valid": false,
  "issues": [
    {
      "type": "json",
      "path": "",
      "message": "invalid JSON syntax at line 5, column 12",
      "severity": "error",
      "reference": "json-syntax-error"
    },
    {
      "type": "semantic",
      "path": "name",
      "message": "server name must be in format 'dns-namespace/name'",
      "severity": "error",
      "reference": "invalid-server-name"
    },
    {
      "type": "semantic", 
      "path": "packages[0].transport.url",
      "message": "url is required for streamable-http transport type",
      "severity": "error",
      "reference": "missing-transport-url"
    },
    {
      "type": "schema",
      "path": "packages[1].environmentVariables[0].name",
      "message": "string does not match required pattern",
      "severity": "error",
      "reference": "#/definitions/EnvironmentVariable/properties/name/pattern from: [#/definitions/ServerDetail]/properties/packages/items/[#/definitions/Package]/properties/environmentVariables/items/[#/definitions/EnvironmentVariable]/properties/name/pattern"
    },
    {
      "type": "linter",
      "path": "packages[1].description",
      "message": "consider adding a more descriptive package description",
      "severity": "warning",
      "reference": "descriptive-package-description"
    }
  ]
}

Note: The JSON output still uses string values for type and severity fields for JSON serialization compatibility, but the Go code uses the typed constants for type safety.

CLI Usage

# Basic validation
mcp-publisher validate server.json

# JSON output format
mcp-publisher validate --format json server.json

# Filter by severity
mcp-publisher validate --severity error server.json

# Include schema validation
mcp-publisher validate --schema server.json

Benefits and Achievements

✅ Comprehensive Feedback

  • Exhaustive error collection: See all validation issues at once, not just the first error
  • Better developer experience: No need to fix errors one by one
  • Precise error location: JSON paths show exactly where issues occur in large JSON files
  • Structured output: JSON format for tooling integration and machine-readable error information

✅ Schema-First Validation

  • Primary validator: Schema validation catches all structural and format violations defined in the schema
  • Semantic validation only for gaps: Covers business logic that cannot be expressed in JSON Schema
  • Standards compliance: Ensures server.json follows the official schema
  • Detailed error messages: Exact JSON paths and resolved schema references

✅ Backward Compatibility

  • Backward compatibility: Use ValidationResult.FirstError() for code expecting error return type
  • Error interface compatibility: Leverages Go's error interface and existing error constants
  • Constructor pattern: Follows established project conventions
  • No breaking changes: All error handling code remains functional

✅ Extensible Architecture

  • Easy to add new validation types: Schema, semantic, linter validation
  • Easy to add new severity levels: Error, warning, info
  • Easy to add filtering and formatting options: By type, severity, path pattern
  • Type safety: Constrained types prevent invalid validation issue creation

✅ Schema-First Strategy Benefits

  • Eliminates duplication: Single source of truth for structural constraints
  • Better error messages: Schema validation provides precise JSON paths with deterministic mapping
  • Maintainability: Schema changes automatically update validation
  • Standards compliance: Ensures validation matches official schema exactly

Technical Design

Architecture Overview

The enhanced validation system uses a schema-first approach with comprehensive error collection and precise location tracking. The system is designed for maximum backward compatibility while providing extensive new capabilities.

Error Interface Compatibility

  • Leverages existing error constants: ErrInvalidRepositoryURL, ErrVersionLooksLikeRange, etc.
  • Preserves error wrapping: Uses fmt.Errorf("%w: %s", err, context) pattern
  • Maintains error.Is() compatibility: Existing error checking continues to work
  • No breaking changes: All error handling code remains functional

Constructor Pattern

Following established Go conventions in the project:

  • NewValidationIssue(): Standard constructor following NewXxx() pattern
  • NewValidationIssueFromError(): Specialized constructor for error conversion
  • Consistent with project: Matches patterns used in NewConfig(), NewServer(), etc.
  • Type safety: Compile-time validation of required fields

Context Passing Architecture

  • Immutable context building: ctx.Field("name").Index(0) pattern
  • Clean composition: Validators focus on validation, not path building
  • Reusable validators: Same validator can be called with different contexts
  • No global state: Thread-safe validation with explicit context

Type Safety with Constrained Values

Following Go best practices used throughout the project:

  • Typed string constants: ValidationIssueType, ValidationIssueSeverity prevent invalid values
  • Compile-time validation: IDE autocomplete and error checking
  • JSON compatibility: Still serializes as strings for API compatibility
  • Refactoring safety: Rename constants without breaking code
  • Consistent with project: Matches patterns used in Status, Format, ArgumentType

Performance Considerations

  • Slightly slower than fail-fast validation: Acceptable trade-off for better user experience
  • Memory usage increases with error collection: Manageable for typical server.json files
  • Schema validation performance: Embedded schema eliminates I/O operations

Testing Strategy

  • Unit tests: Each validator with context
  • Integration tests: End-to-end validation testing
  • Backward compatibility tests: Ensure existing code continues to work
  • Performance benchmarks: Validate acceptable performance characteristics

Appendix: Future Enhancements

Additional Validation Types

  • Linter rules: Best practices and style guidelines
  • Warning level: Non-critical issues
  • Info level: Suggestions and improvements

Advanced Features

  • Error filtering: By type, severity, path pattern
  • Output formatting: Human-readable, JSON, XML
  • Configuration: Custom validation rules
  • IDE integration: Real-time validation feedback

Tooling Integration

  • WASM package: Browser-based validation
  • VS Code extension: Real-time validation
  • CI/CD integration: Automated validation in pipelines
  • API endpoint: Validation as a service (see Validate API Endpoint section below)

Validate API Endpoint

Overview

A REST API endpoint (POST /v0/validate) that validates server.json files without publishing them to the registry. This endpoint provides programmatic access to the same validation logic used by the CLI commands, returning structured validation results in JSON format.

Use Cases

  • CI/CD Pipelines: Validate server.json files before attempting to publish
  • Editor/IDE Integrations: Real-time validation feedback in development tools
  • Web UIs: Validate files in browser-based interfaces
  • Pre-publish Checks: Validate before authentication/publishing workflow
  • Validation as a Service: Allow external tools to validate server.json format

Implementation

Endpoint Specification

Endpoint: POST /v0/validate
Authentication: None required (read-only operation)
Content-Type: application/json

Request

Request body should be a valid ServerJSON object:

{
  "$schema": "https://static.modelcontextprotocol.io/schemas/2025-10-17/server.schema.json",
  "name": "io.example/server",
  "version": "1.0.0",
  ...
}

Response

Returns a ValidationResult in JSON format:

{
  "valid": false,
  "issues": [
    {
      "type": "schema",
      "path": "packages[0].transport.url",
      "message": "missing required field: 'url'",
      "severity": "error",
      "reference": "#/definitions/SseTransport/required"
    },
    {
      "type": "semantic",
      "path": "name",
      "message": "server name must be in format 'dns-namespace/name'",
      "severity": "error",
      "reference": "invalid-server-name"
    }
  ]
}

HTTP Status Codes:

  • 200 OK: Validation completed successfully (regardless of whether valid or invalid)
  • 400 Bad Request: Malformed JSON or invalid request format

Note: A 200 OK status does not mean the server.json is valid - check the valid field in the response body.

Implementation Details

Location: internal/api/handlers/v0/validate.go

Handler Function:

  • Accepts ServerJSON in request body
  • Calls validators.ValidateServerJSON(serverJSON, validators.ValidationAll)
  • Returns ValidationResult as JSON response
  • Uses Huma framework (same as publish endpoint) for request/response handling

Key Differences from Publish Endpoint:

  • No authentication required (read-only)
  • Does not save to database
  • Returns structured validation results instead of published server response
  • Returns warnings, not just errors (useful for comprehensive feedback)

Reuses Existing Infrastructure:

  • Same validation functions as CLI commands
  • Same ValidationResult type
  • Same issue types and severity levels
  • Consistent validation behavior across CLI and API

Testing Strategy

Unit Tests

Test handler function with mocked dependencies:

  • Valid server.json → valid: true, issues: []
  • Invalid server.json → valid: false with specific issues
  • Schema errors → issues with type: "schema"
  • Semantic errors → issues with type: "semantic"
  • Empty schema → schema-field-required issue
  • Non-current schema → schema-version-deprecated issue
  • Multiple issues → all issues returned in response
  • Malformed JSON → proper error handling

Integration Tests

Follow patterns from publish_integration_test.go:

  • Start test server
  • Send HTTP POST requests with various server.json payloads
  • Assert response JSON matches expected ValidationResult structure
  • Verify HTTP status codes (200 for valid requests, 400 for malformed)
  • Test both valid and invalid inputs
  • Reuse test fixtures from validation_detailed_test.go

Test Infrastructure

  • Reuse existing test server setup
  • Use same patterns as test_endpoints.sh for manual testing
  • Leverage existing validation test cases

Future Enhancements

  • Query Parameters: Optional parameters to filter by issue type or severity
  • Partial Validation: Validate specific sections (e.g., only schema, only semantic)
  • Format Options: Request different output formats (detailed vs. summary)
  • Batch Validation: Validate multiple server.json files in one request