Chapter 4: Authentication Models and Namespace Ownership

April 13, 2026 ยท View on GitHub

Welcome to Chapter 4: Authentication Models and Namespace Ownership. In this part of MCP Registry Tutorial: Publishing, Discovery, and Governance for MCP Servers, you will build an intuitive mental model first, then move into concrete implementation details and practical production tradeoffs.

Authentication method and server-name namespace must align, or publishing is rejected.

Learning Goals

  • choose auth mode based on namespace strategy
  • implement GitHub, DNS, or HTTP verification paths
  • handle CI-friendly auth flows with least friction
  • prevent namespace mismatch errors early

Auth Decision Table

Auth MethodNamespace PatternTypical Context
GitHub OAuth/OIDCio.github.<user-or-org>/*open-source repo publishers
DNSreverse-domain namespaceowned domains with DNS control
HTTPreverse-domain namespaceowned domains with .well-known control
OIDC admin exchangeadmin workflowsregistry operations

Practical Guardrail

Define server naming convention first, then standardize one primary auth path in docs and CI templates.

Source References

Summary

You now have a reliable mapping from namespace policy to authentication workflow.

Next: Chapter 5: API Consumption, Subregistries, and Sync Strategies

Source Code Walkthrough

internal/validators/validators.go

The ValidatePublishRequest function in internal/validators/validators.go handles a key part of this chapter's functionality:

}

// ValidatePublishRequest validates a complete publish request including extensions
// Note: ValidateServerJSON should be called separately before this function
func ValidatePublishRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config) error {
	// Validate publisher extensions in _meta
	if err := validatePublisherExtensions(req); err != nil {
		return err
	}

	// Validate registry ownership for all packages if validation is enabled
	if cfg.EnableRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

// ValidateUpdateRequest validates an update request including registry ownership
// Note: ValidateServerJSON should be called separately before this function
func ValidateUpdateRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config, skipRegistryValidation bool) error {
	if cfg.EnableRegistryValidation && !skipRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

This function is important because it defines how MCP Registry Tutorial: Publishing, Discovery, and Governance for MCP Servers implements the patterns covered in this chapter.

internal/validators/validators.go

The ValidateUpdateRequest function in internal/validators/validators.go handles a key part of this chapter's functionality:

}

// ValidateUpdateRequest validates an update request including registry ownership
// Note: ValidateServerJSON should be called separately before this function
func ValidateUpdateRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config, skipRegistryValidation bool) error {
	if cfg.EnableRegistryValidation && !skipRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

func validateRegistryOwnership(ctx context.Context, req apiv0.ServerJSON) error {
	for i, pkg := range req.Packages {
		if err := ValidatePackage(ctx, pkg, req.Name); err != nil {
			return fmt.Errorf("registry validation failed for package %d (%s): %w", i, pkg.Identifier, err)
		}
	}
	return nil
}

func validatePublisherExtensions(req apiv0.ServerJSON) error {
	const maxExtensionSize = 4 * 1024 // 4KB limit

	// Check size limit for _meta publisher-provided extension
	if req.Meta != nil && req.Meta.PublisherProvided != nil {
		extensionsJSON, err := json.Marshal(req.Meta.PublisherProvided)
		if err != nil {
			return fmt.Errorf("failed to marshal _meta.io.modelcontextprotocol.registry/publisher-provided extension: %w", err)
		}

This function is important because it defines how MCP Registry Tutorial: Publishing, Discovery, and Governance for MCP Servers implements the patterns covered in this chapter.

internal/validators/validators.go

The validateRegistryOwnership function in internal/validators/validators.go handles a key part of this chapter's functionality:

	// Validate registry ownership for all packages if validation is enabled
	if cfg.EnableRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

// ValidateUpdateRequest validates an update request including registry ownership
// Note: ValidateServerJSON should be called separately before this function
func ValidateUpdateRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config, skipRegistryValidation bool) error {
	if cfg.EnableRegistryValidation && !skipRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

func validateRegistryOwnership(ctx context.Context, req apiv0.ServerJSON) error {
	for i, pkg := range req.Packages {
		if err := ValidatePackage(ctx, pkg, req.Name); err != nil {
			return fmt.Errorf("registry validation failed for package %d (%s): %w", i, pkg.Identifier, err)
		}
	}
	return nil
}

func validatePublisherExtensions(req apiv0.ServerJSON) error {

This function is important because it defines how MCP Registry Tutorial: Publishing, Discovery, and Governance for MCP Servers implements the patterns covered in this chapter.

internal/validators/validators.go

The validatePublisherExtensions function in internal/validators/validators.go handles a key part of this chapter's functionality:

func ValidatePublishRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config) error {
	// Validate publisher extensions in _meta
	if err := validatePublisherExtensions(req); err != nil {
		return err
	}

	// Validate registry ownership for all packages if validation is enabled
	if cfg.EnableRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

// ValidateUpdateRequest validates an update request including registry ownership
// Note: ValidateServerJSON should be called separately before this function
func ValidateUpdateRequest(ctx context.Context, req apiv0.ServerJSON, cfg *config.Config, skipRegistryValidation bool) error {
	if cfg.EnableRegistryValidation && !skipRegistryValidation {
		if err := validateRegistryOwnership(ctx, req); err != nil {
			return err
		}
	}

	return nil
}

func validateRegistryOwnership(ctx context.Context, req apiv0.ServerJSON) error {
	for i, pkg := range req.Packages {
		if err := ValidatePackage(ctx, pkg, req.Name); err != nil {
			return fmt.Errorf("registry validation failed for package %d (%s): %w", i, pkg.Identifier, err)

This function is important because it defines how MCP Registry Tutorial: Publishing, Discovery, and Governance for MCP Servers implements the patterns covered in this chapter.

How These Components Connect

flowchart TD
    A[ValidatePublishRequest]
    B[ValidateUpdateRequest]
    C[validateRegistryOwnership]
    D[validatePublisherExtensions]
    E[parseServerName]
    A --> B
    B --> C
    C --> D
    D --> E