Configuration

YAML configuration file format, environment variable overrides, and complete reference for all config keys.

MCP Registry is configured through a YAML file specified at startup with the -config flag. Every value can be overridden with environment variables.

./mcp-registry -config /path/to/config.yaml

Configuration Precedence

  1. Environment variables (highest priority)
  2. YAML config file
  3. Defaults (lowest priority)

Environment Variable Overrides

Any configuration key can be overridden with an environment variable using the pattern:

MCP_REGISTRY_{SECTION}_{KEY}

All uppercase, with underscores separating nested keys.

Config KeyEnvironment Variable
server.listenMCP_REGISTRY_SERVER_LISTEN
db.dsnMCP_REGISTRY_DB_DSN
storage.typeMCP_REGISTRY_STORAGE_TYPE
storage.s3.bucketMCP_REGISTRY_STORAGE_S3_BUCKET
auth.modeMCP_REGISTRY_AUTH_MODE
auth.oss.issuer_secretMCP_REGISTRY_AUTH_OSS_ISSUER_SECRET
auth.enterprise.jwks_urlMCP_REGISTRY_AUTH_ENTERPRISE_JWKS_URL
public.read_catalogMCP_REGISTRY_PUBLIC_READ_CATALOG
presign.enabledMCP_REGISTRY_PRESIGN_ENABLED
logging.jsonMCP_REGISTRY_LOGGING_JSON

Environment variables take precedence over config file values, making them ideal for secrets and environment-specific settings.

Complete Configuration Reference

Server

server:
  listen: ":8080"
KeyTypeDefaultDescription
server.listenstring":8080"TCP address for the HTTP server. Use ":PORT" for all interfaces or "HOST:PORT" for a specific interface.

Database

db:
  dsn: "postgres://user:pass@localhost:5432/mcp_registry?sslmode=disable"
KeyTypeDefaultRequiredDescription
db.dsnstringYesDatabase connection string. Supports SQLite (sqlite:/path/to/file.db) and PostgreSQL (postgres://user:pass@host:port/dbname).

SQLite – Suitable for development and small, single-instance deployments. The database file is created automatically. Does not support concurrent writes well.

db:
  dsn: "sqlite:/tmp/mcp-registry.db"

PostgreSQL – Recommended for production. Supports concurrent access, transactions, and horizontal scaling.

db:
  dsn: "postgres://mcp_user:[email protected]:5432/mcp_registry?sslmode=require"

Common PostgreSQL parameters: sslmode (disable, require, verify-full), connect_timeout, application_name.

Storage

storage:
  type: "s3"
  fs:
    root: "/data/artifacts"
  s3:
    bucket: "mcp-artifacts"
    region: "us-east-1"
    endpoint: ""
KeyTypeDefaultRequiredDescription
storage.typestringYesStorage backend: "fs" (filesystem) or "s3" (S3-compatible).
storage.fs.rootstringWhen type=fsRoot directory for local artifact storage. Created if it does not exist.
storage.s3.bucketstringWhen type=s3S3 bucket name. Must already exist.
storage.s3.regionstringWhen type=s3AWS region for the bucket.
storage.s3.endpointstring""NoCustom S3 endpoint for MinIO or other compatible services. Empty uses AWS default.

Authentication

auth:
  mode: "oss"
  oss:
    issuer: "mcp-registry-oss"
    audience: "mcp-registry"
    issuer_secret: "your-32-byte-or-longer-secret-here"
    enable_basic: false
  enterprise:
    jwks_url: "https://idp.example.com/.well-known/jwks.json"
    issuer: "https://idp.example.com/"
    audience: "mcp-registry"
KeyTypeDefaultRequiredDescription
auth.modestringYesAuthentication mode: "oss" or "enterprise".
auth.oss.issuerstring"mcp-registry-oss"NoIssuer identifier for self-issued JWTs (iss claim).
auth.oss.audiencestring"mcp-registry"NoAudience identifier for JWTs (aud claim).
auth.oss.issuer_secretstringIn OSS modeSecret for signing JWTs (HS256). Must be >= 32 bytes.
auth.oss.enable_basicboolfalseNoEnable HTTP Basic Auth for API requests.
auth.enterprise.jwks_urlstringIn Enterprise modeURL to the JWKS endpoint for JWT signature verification.
auth.enterprise.issuerstringIn Enterprise modeExpected iss claim in externally-issued JWTs.
auth.enterprise.audiencestring"mcp-registry"NoExpected aud claim in externally-issued JWTs.

Public Access

public:
  read_catalog: true
  download_artifacts: false
KeyTypeDefaultDescription
public.read_catalogboolfalseAllow unauthenticated GET /v1/catalog requests. Returns only public packages.
public.download_artifactsboolfalseAllow unauthenticated download of public package artifacts. Private packages still require auth.

Repository Policy

repo_policy:
  allow_domains:
    - "github.com"
    - "gitlab.com"
  deny_patterns:
    - "/malware-"
    - "/blocked-org/"
  allow_orgs:
    - "acme"
    - "trusted-vendor"
KeyTypeDefaultDescription
repo_policy.allow_domains[]string[] (all allowed)Whitelist of allowed repository domains. Empty list allows all domains.
repo_policy.deny_patterns[]string[]URL path patterns to block (substring match).
repo_policy.allow_orgs[]string[] (all allowed)Whitelist of allowed repository owners. Empty list allows all orgs.

Policy evaluation order:

  1. If allow_domains is non-empty, the repo_url host must match
  2. The repo_url path must not contain any deny_patterns
  3. If allow_orgs is non-empty, the first path segment of repo_url must match

Versions that fail policy evaluation are set to quarantined status (not rejected).

Presigned URLs

presign:
  enabled: true
  ttl_seconds: 300
KeyTypeDefaultDescription
presign.enabledbooltrueEnable presigned URLs for direct S3 uploads and downloads. Only effective with S3 storage.
presign.ttl_secondsint300Presigned URL lifetime in seconds.

Logging

logging:
  json: true
KeyTypeDefaultDescription
logging.jsonboolfalseOutput logs in JSON format. Recommended for production (log aggregation systems). When false, uses human-readable format.

Example Configurations

Development (SQLite + Filesystem)

Minimal configuration for local development with no external dependencies.

server:
  listen: ":8080"

db:
  dsn: "sqlite:/tmp/mcp-registry.db"

storage:
  type: "fs"
  fs:
    root: "/tmp/mcp-registry-storage"

auth:
  mode: "oss"
  oss:
    issuer_secret: "super-secret-key-for-development-only-32chars!"

public:
  read_catalog: true
  download_artifacts: true

presign:
  enabled: false

logging:
  json: false

Production OSS (PostgreSQL + S3)

For small teams managing their own registry without an external IdP.

server:
  listen: ":8080"

db:
  dsn: "postgres://mcp_user:${DB_PASSWORD}@db.internal:5432/mcp_registry?sslmode=require"

storage:
  type: "s3"
  s3:
    bucket: "company-mcp-artifacts"
    region: "us-east-1"

auth:
  mode: "oss"
  oss:
    issuer: "mcp-registry"
    audience: "mcp-registry"
    issuer_secret: "${MCP_REGISTRY_AUTH_OSS_ISSUER_SECRET}"
    enable_basic: false

public:
  read_catalog: false
  download_artifacts: false

repo_policy:
  allow_domains:
    - "github.com"
  deny_patterns: []
  allow_orgs:
    - "my-company"

presign:
  enabled: true
  ttl_seconds: 300

logging:
  json: true

Production Enterprise (PostgreSQL + S3 + External IdP)

For organizations with existing identity infrastructure.

server:
  listen: ":8080"

db:
  dsn: "postgres://mcp_user:${DB_PASSWORD}@db.internal:5432/mcp_registry?sslmode=require"

storage:
  type: "s3"
  s3:
    bucket: "company-mcp-artifacts"
    region: "us-east-1"

auth:
  mode: "enterprise"
  enterprise:
    jwks_url: "https://auth.company.com/.well-known/jwks.json"
    issuer: "https://auth.company.com/"
    audience: "mcp-registry"

public:
  read_catalog: false
  download_artifacts: false

repo_policy:
  allow_domains:
    - "github.com"
  allow_orgs:
    - "company-org"

presign:
  enabled: true
  ttl_seconds: 300

logging:
  json: true

Docker Compose Stack (PostgreSQL + MinIO)

Configuration matching the MCP Hub Platform docker-compose.yml.

server:
  listen: ":8080"

db:
  dsn: "postgres://mcphub:mcphub@postgres:5432/mcp_registry?sslmode=disable"

storage:
  type: "s3"
  s3:
    bucket: "mcp"
    region: "us-east-1"
    endpoint: "http://minio:9000"

auth:
  mode: "oss"
  oss:
    issuer: "mcp-registry-oss"
    audience: "mcp-registry"
    issuer_secret: "${MCP_REGISTRY_AUTH_OSS_ISSUER_SECRET}"

public:
  read_catalog: true
  download_artifacts: false

repo_policy:
  allow_domains:
    - "github.com"
  deny_patterns:
    - "/malware-"
  allow_orgs: []

presign:
  enabled: true
  ttl_seconds: 300

logging:
  json: true

Startup Validation

On startup, the registry validates the configuration:

  1. Database connection – Attempts to connect and run auto-migrations
  2. Storage access – Verifies the storage backend is accessible (bucket exists for S3, directory is writable for filesystem)
  3. Auth configuration – Validates the issuer secret length (>= 32 bytes) in OSS mode, or verifies the JWKS URL is reachable in enterprise mode

Invalid configuration causes the server to exit immediately with a descriptive error message. Check the startup logs for details.

Gotchas

  • issuer_secret must be >= 32 characters – The server refuses to start with a shorter secret. Use openssl rand -base64 32 to generate one.
  • SQLite does not support concurrent writes – Use PostgreSQL for production or any setup with multiple concurrent requests.
  • Presigned URLs only work with S3 storage – The filesystem backend always proxies artifact bytes through the registry.
  • Enterprise mode has no login endpointPOST /v1/auth/login returns 501 Not Implemented. Tokens must come from the external IdP.
  • MCP_REGISTRY_PUBLIC_READ_CATALOG=true allows unauthenticated browsing – Disable this in enterprise deployments where catalog visibility is sensitive.
  • Repo policy violations quarantine, not reject – Versions failing policy checks are created with quarantined status rather than being rejected outright.