MCP Forge
View Markdown
YAML configuration reference.mdDownload .md

Configuration reference

config.yaml is deliberately minimal: bootstrap only. It says how to find and secure Runku's own admin database, which target databases to protect, and how to verify OIDC tokens. It does not say which tables are exposed, what's masked, what writes are allowed, or who's allowed to do what — that all lives in Runku's own admin database (see auth-and-permissions.md and policy.md), managed live via the runku auth/runku policy CLI, never by hand-editing this file and redeploying.

Parsing is strict: unknown fields are a hard error at startup, not a silently-ignored typo. ${VAR} anywhere in the file is expanded from the environment before parsing.

Minimal example

# HTTP listener shared by the portal and MCP endpoints.
server:
  # TCP port exposed by the runku process.
  port: 8080

# Private Runku state: policy, identities, roles and API-key hashes.
# This database is never published as a connector.
store:
  # PostgreSQL is recommended for production and multiple instances.
  driver: postgres
  # Dedicated admin-store DSN, injected instead of committed to this file.
  dsn: ${RUNKU_MCP_STORE_DSN}

# External sources published through governed MCP endpoints.
connectors:
  # Stable identifier for this independently governed source.
  - id: main
    database:
      # External source engine: postgres, mysql or sqlserver.
      driver: postgres
      # Source credentials; deliberately separate from RUNKU_MCP_STORE_DSN.
      dsn: ${DATABASE_URL}

store and connectors are different boundaries

They may both use PostgreSQL, but they must not be treated as the same database or credential:

Configuration Purpose Typical contents Accessed by agents
store Runku's private control state Policies, roles, identities, API-key hashes and connector metadata Never
connectors[] External sources governed by Runku Your application or business data Only through generated tools allowed by policy
flowchart LR
  Operator[Operator] -->|manages policy and identities| Store[(Runku admin store)]
  Agent[MCP client] -->|typed tool call| Runku[Runku MCP Forge]
  Store -->|policy and authorization| Runku
  Runku -->|validated, parameterized operation| Source[(Connected source)]
  Source -->|allowed result| Runku
  Runku -->|masked result| Agent

The admin store belongs to the Runku deployment. A connector belongs to the operator and represents a source Runku protects. Use a dedicated database and credentials for the PostgreSQL admin store, even when a connected source also uses PostgreSQL.

server

Field Type Default Notes
port int 8080
tls object, optional disabled see below
# Listener and optional transport encryption.
server:
  # TCP port used by the service.
  port: 8080
  tls:
    # Serve HTTPS directly. Disable when a trusted reverse proxy terminates TLS.
    enabled: true
    # Mounted PEM certificate chain and matching private key.
    cert_file: /etc/runku/tls/cert.pem
    key_file: /etc/runku/tls/key.pem

tls.enabled: true switches the listener to ListenAndServeTLScert_file/key_file are then required. Without it, Runku serves plain HTTP, same as every version before TLS support existed — the common case being a reverse proxy in front of it that already terminates TLS.

store

Runku's own admin database — roles, identities, API key hashes, role bindings, and each connector's policy. Never one of the databases Runku protects; a completely separate engine and connection.

Field Type Notes
driver string "sqlite" or "postgres"; both are implemented.
path string SQLite only. Required when driver: sqlite; forbidden otherwise.
dsn string Postgres only. Required when driver: postgres; forbidden otherwise.

PostgreSQL is the recommended production backend and supports shared or multi-instance deployments. Keep its DSN in the environment or a secrets manager:

# Dedicated database for Runku's internal operational state.
store:
  # Recommended for production, HA and multi-instance deployments.
  driver: postgres
  # Secret DSN for the admin database; not a connector DSN.
  dsn: ${RUNKU_MCP_STORE_DSN}

SQLite is fully supported for evaluation, local operation and small single-instance deployments:

# Simple single-instance admin store for evaluation or small installations.
store:
  # Embedded storage; no external database server is required.
  driver: sqlite
  # Persistent file containing Runku policy, roles and identities.
  path: data/runku.db

Exactly one engine, never a hybrid — store is unrelated to connectors[].database, which is the database(s) being protected.

connectors

At least one required. Each connector is one target database, exposed on its own MCP endpoint — a single runku serve process can serve several simultaneously.

Field Type Default Notes
id string "default" for the first connector if omitted Must be unique.
path string /mcp/<id> Must start with /; must be unique.
database.driver string postgres | mysql | sqlserver
database.dsn string Required
# Each connector is an external source with an independent MCP URL and policy.
connectors:
  # First source: a PostgreSQL business database.
  - id: postgres-main
    # Explicit MCP route; defaults to /mcp/<id> when omitted.
    path: /mcp/postgres-main
    database:
      # Driver used to introspect and query this external source.
      driver: postgres
      # Credentials belong to the source, not Runku's admin store.
      dsn: ${DATABASE_URL}
  # Second source: a separate MySQL business database.
  - id: mysql-secondary
    database:
      driver: mysql
      dsn: ${MYSQL_DSN}

DSN formats per engine:

What each connector actually exposes (tables, columns, mutations, procedures) is not configured here — see policy.md.

audit

Local audit buffering, optional outbound shipping, optional rotated file logging. The stdout audit line (one JSON object per tool call) is always on, unconditionally, regardless of anything in this section — this section only adds sinks on top of it.

Field Type Default Notes
sqlite_path string disabled if empty Local SQLite buffer — powers /reports/* and the portal.
shipper object disabled See below.
runtime_metrics object disabled Same shape as shipper, a separate channel for runtime/tool-analysis metrics.
log_file object, optional disabled Writes the same trail to a rotated file, in addition to stdout.
# Optional audit sinks in addition to the always-enabled stdout audit stream.
audit:
  # Local outbox and portal/reporting buffer; separate from the admin store.
  sqlite_path: data/runku-audit.db
  shipper:
    # HTTPS receiver for batched audit events.
    endpoint: ${RUNKU_SHIPPER_ENDPOINT}
    # Delivery cadence and maximum events per request.
    interval: 30s
    batch_size: 200
    headers:
      # Optional static authentication header.
      X-Api-Key: ${SHIPPER_API_KEY}
    oauth2:
      # Optional OAuth2 client-credentials authentication for the receiver.
      token_url: https://idp.example.com/oauth2/token
      client_id: ${SHIPPER_CLIENT_ID}
      client_secret: ${SHIPPER_CLIENT_SECRET}
      scopes: [audit:write]
  log_file:
    # Optional rotated local JSON audit file.
    path: data/runku-audit.log
    # Rotation size, retained files, age and compression behavior.
    max_size_mb: 100
    max_backups: 5
    max_age_days: 30
    compress: false

shipper is a plain webhook POST — it has no idea any particular backend exists; point it at whatever ingests JSON over HTTPS. Entries are only deleted from the local buffer after a confirmed successful delivery (an outbox pattern — a failing shipper never loses data, it just accumulates locally). headers are static, sent on every request. oauth2 is the standard client-credentials grant (RFC 6749 §4.4) — token fetch, caching and refresh are handled entirely by the underlying OAuth2 library. Both may be combined; both are optional; with neither set, the shipper POSTs unauthenticated.

Leaving shipper.endpoint empty disables shipping. Entries remain in the local SQLite buffer for reports and the portal until retention removes them.

auth

Authenticates every request to /mcp and /reports/* — who's calling, verified cryptographically, not self-reported. Disabled by default.

Field Type Default Notes
enabled bool false
oidc object, optional unset Only how to verify incoming tokens — issuing/storing credentials is never Runku's job.
# Request authentication. Authorization remains in roles/policy in the store.
auth:
  # Require a valid API key or verified OIDC bearer token.
  enabled: true
  oidc:
    # Trusted issuer discovered through its OIDC metadata endpoint.
    issuer: https://idp.example.com/realms/runku
    # Audience that incoming access tokens must contain.
    audience: runku-mcp
    # Public PKCE client used only by browser portal login.
    portal_client_id: runku-portal

API keys are not configured here — see auth-and-permissions.md; they live in the admin store and are managed with runku auth apikey.

Configuration checklist

Before starting the service, validate the listen address, persistent store path or DSN, connector DSNs, audit retention, TLS and authentication settings. Unknown fields fail startup so configuration mistakes are visible immediately.