Configuration - bishoku/vmcp GitHub Wiki

Configuration reference

All configuration is through environment variables. Durations use Go syntax (30s, 5m).

Shared

Variable Default Used by Meaning
VMCP_DATABASE_URL required both PostgreSQL connection string
VMCP_EGRESS_ALLOW_CIDRS empty both Comma-separated private/loopback CIDRs allowed for MCP upstreams and upstream OAuth token endpoints; metadata and prohibited destinations remain denied
VMCP_EGRESS_ALLOW_HOSTS empty both Optional exact DNS names/IP literals allowed for MCP/token HTTP traffic; when empty, public unicast destinations are allowed. Host grants do not override private CIDR checks
VMCP_MASTER_KEY required both Base64 32-byte key (openssl rand -base64 32) encrypting upstream headers and client keys. Retain recovery keys; use the reader-first keyring/rotation procedure rather than replacing it blindly. Both planes in one tenant share the keyring

Control plane

Variable Default Meaning
VMCP_ADMIN_TOKEN required Bootstrap admin token (admin role)
VMCP_CP_ADDR :8081 Listen address
VMCP_AUDIT_RETENTION_DAYS 90 Audit events older than this are deleted; 0 keeps forever
VMCP_OIDC_ISSUER unset Enables SSO when set
VMCP_OIDC_DISCOVERY_URL unset Where to fetch the discovery document when it is not reachable at the issuer URL (containers, split-horizon). The issuer stays the public value tokens carry
VMCP_OIDC_CLIENT_ID required with issuer OIDC client
VMCP_OIDC_CLIENT_SECRET empty OIDC client secret
VMCP_OIDC_REDIRECT_URL required with issuer Public URL of /auth/callback
VMCP_OIDC_GROUPS_CLAIM groups ID-token claim carrying groups or roles. Nested paths work, e.g. realm_access.roles (Keycloak realm roles)
VMCP_OIDC_ADMIN_GROUPS, VMCP_OIDC_EDITOR_GROUPS, VMCP_OIDC_VIEWER_GROUPS empty Comma-separated groups per role

Data plane

Variable Default Meaning
VMCP_AUDIT_MODE strict strict persists tool admission before dispatch; best_effort permits queue loss and does not provide complete audit coverage. Control-plane administrative audit is always strict
VMCP_AUTH_MAX_STALE 30s Maximum age of successfully confirmed authorization configuration; positive Go duration. Stale MCP requests return 503
VMCP_DP_ADDR :8080 Listen address
VMCP_ALLOWED_ORIGINS empty Comma-separated exact browser origins for MCP POST/GET/DELETE, e.g. https://agent.example; no paths. Empty denies all supplied Origins. Native clients may omit Origin
VMCP_TRUSTED_PROXIES empty CIDRs of reverse proxies whose X-Forwarded-For is trusted (for IP allowlists and audit client IPs)
VMCP_BREAKER_THRESHOLD 5 Consecutive transport failures that open the circuit; 0 disables
VMCP_BREAKER_COOLDOWN 30s How long an open circuit refuses calls before one probe
VMCP_HEALTH_INTERVAL 30s Upstream health probe interval; 0 disables
VMCP_NODE_ID hostname Node name shown in health reports
VMCP_REDIS_URL unset Optional. Shares rate-limit counters between nodes
VMCP_AGENT_OIDC_ISSUER unset Enables OAuth for agents on the data plane when set. Expected iss claim
VMCP_AGENT_OIDC_DISCOVERY_URL unset OIDC discovery base URL if different from issuer (e.g. internal network)
VMCP_AGENT_OIDC_AUDIENCE required with issuer Mandatory expected aud claim for incoming agent JWTs
VMCP_AGENT_OIDC_ALGS RS256,ES256 Allowed JWT signing algorithms (asymmetric only)
VMCP_PUBLIC_URL unset Canonical public base URL of the data plane (e.g. https://gateway.example.com). Used for RFC 9728 protected resource metadata

Health endpoints

Both services expose GET /healthz (liveness) and GET /readyz. Control-plane readiness checks the database. Data-plane readiness reports authorization freshness and fails on expired confirmation, unavailable audit writes, or a strict Redis quota dependency. Draining planes report unready. See Authorization consistency.

Tests only

VMCP_TEST_DATABASE_URL, VMCP_TEST_REDIS_URL: see Development.

MCP network policy

Set the same egress policy on both services and restart after changes. See MCP network security for defaults, private-network examples, disabled redirects/proxies, TLS behavior and deployment compatibility. MCP POST requires Content-Type: application/json and Accept: application/json, text/event-stream; GET requires Accept: text/event-stream and opens an authenticated, session-scoped SSE stream when durable delivery is enabled.

Audit durability

Data-plane /audit-status and authenticated control-plane /api/v1/audit-status expose failure counters and incomplete operations. Read Audit durability before choosing best-effort mode or rolling back migration 18.

Resource and drain limits

VMCP_DRAIN_TIMEOUT defaults to 75s and accepts 65s–2m. On SIGTERM the data plane rejects new admissions and readiness returns 503, while admitted requests retain live snapshot and audit services. After HTTP drain (or forced connection closure plus a six-second outcome-write allowance), local upstream sessions retire, background producers stop, audit buffers flush, and pools close. Compose grants 105 seconds; increase that when increasing the drain timeout (allow at least another 15 seconds for cancellation and audit flushing). A killed process can leave durable incomplete admissions; recovery evidence remains available. Shutdown does not revoke sessions stored for other nodes.

Limits are currently fixed per process: 10,000 cached sessions, 1,024 concurrent MCP admissions, 128 per virtual server, and 16 per authenticated identity (all anonymous requests share the anonymous identity bucket). These counters include initialization and body reading and return 429 when saturated; shared sessions and replicas do not provide cluster-wide concurrency quotas. Request bodies have a ten-second read deadline, and JSON response writes have a ten-second deadline. Upstream JSON responses and assembled SSE data frames are limited to 10 MiB; discovery stops at 100 pages or 10,000 tools and rejects repeated/oversized cursors. Health probes run at most 16 concurrently. OAuth source caching retains at most 1,024 entries and failed token fetches back off for one second. Cache turnover may refetch credentials; no secret is used as a telemetry label.

Non-idempotent tool calls never automatically replay a session-expiry response or HTTP 401. A subsequent client request may reconnect/refresh; clients must resolve uncertain side effects before retrying. Read-only/idempotent annotations permit bounded replay and are trusted upstream declarations, not a proof of idempotency. Caller cancellation and IdP failures do not trip upstream breakers.

Pool, telemetry, identity and operational services

Variable Default Meaning
VMCP_DB_MAX_CONNS, VMCP_DB_MIN_CONNS 16, 2 Request pool size per plane; account for every replica
VMCP_DB_ACQUIRE_TIMEOUT 2s Pool acquisition deadline
VMCP_DB_LISTENER_URL database URL Direct/session-pooling PostgreSQL endpoint for persistent LISTEN; transaction pooling is unsuitable
VMCP_SKIP_MIGRATIONS false Control plane checks the schema instead of migrating; run cmd/migrate first
VMCP_TENANT_ID default Dedicated database deployment identity, consistent on planes and operational commands
VMCP_REDIS_FAILURE_POLICY local Per-node fallback (local) or quota denial/readiness failure (strict) on Redis outage
VMCP_OTEL_ENABLED false Enable bounded OTLP HTTP tracing
VMCP_OTEL_SAMPLE_RATIO 0.1 Local trace sampling ratio, 0–1
VMCP_KEY_ID primary Primary encryption key ID
VMCP_DECRYPT_KEYS unset JSON recovery-key map for reader-first rotation
VMCP_CIPHERTEXT_WRITE_VERSION v1 v1 bound envelope, or transitional legacy during reader-first rollout
VMCP_APPROVAL_URL unset Optional HTTPS metadata/digest request-approval service
VMCP_AUDIT_EXPORT_DATABASE_URL, VMCP_AUDIT_EXPORT_CONSUMER, VMCP_AUDIT_EXPORT_URL required by exporter Separate exporter pool, stable consumer name and HTTPS sink

See observability for pool/tracing constraints and OTel variables, security operations for rotation/identity containment, audit operations for export/retention roles, and tenant operations for router variables. The manual stack supplies an explicit local configuration.

Independent audit exporter processes

HTTPS, Kafka and RabbitMQ exporters use their own database connection pools and configuration. See all exporter variables and deployment examples. No broker configuration is required by the control plane or data plane.