Configuration reference
Every MCPG gateway configuration key, generated from the live AppConfig schema. The gateway rejects unknown fields at boot, so this is the exact, complete surface.
Generated from
apps/gateway/src/config/viamcpg-config-doc.
The audience-facing sections below are curated inside the generator; the per-block reference at the bottom is sourced from///rustdoc +#[serde(...)]annotations on the liveAppConfigtree.
Re-generate with:cargo run -p mcpg --bin mcpg-config-doc > apps/gateway/docs/configuration.md.
Overview
Top-level gateway configuration. Loaded from YAML file and/or MCPG_ environment variables via figment. Bindings live under mcp.capabilities.{tools,prompts,resources,resource_templates}[]. Each binding carries an explicit nested backend: block that picks the implementation, discriminated by kind: (kind: http, kind: sql, kind: openai_chat, …). Env-var expansion (${env.X}) happens at startup time via CEL.
deny_unknown_fields is set so a typo at the root (or a stale renamed block left in an operator's YAML) fails parsing instead of silently parsing to defaults. The same strictness applies to every typed sub-config; this flag closes the gap at the root.
Operator workflow
The four config-tooling binaries cover the operator's full loop — pick a starting point, drill into a field, validate, boot:
$ mcpg-config-init # pick a deployment template, write config.yaml
$ mcpg-config-explain governance.audit.on_failure # describe a field by dotted path
$ mcpg-config-check config.yaml # pre-flight validate (multi-file too)
$ MCPG_CONFIG=config.yaml mcpg # boot
Multi-file layering is supported — files later on the command line override earlier ones, and MCPG_* env vars apply last:
$ MCPG_CONFIG=base.yaml:production-overrides.yaml mcpg
For in-place config rotation (kill -HUP) vs restart-required fields, see hot-reload.md.
For IDE autocomplete, point your YAML language server at the committed schema:
# yaml-language-server: $schema=../../examples/deployments/config.schema.json
gateway:
server:
bind_address: "127.0.0.1:8787"
# ↑ IDE autocompletes here, with `///` doc-comment as hover.
Top-level keys (Layout D'')
Layout D'' (P1–P12) collapsed the pre-D'' flat root into seven typed top-level keys. The migration map for any pre-D'' YAML or env-var examples you might still be reading:
| Pre-D'' key | Layout D'' key |
|---|---|
auth: | governance.access: |
policy: | governance.policy: |
audit: | governance.audit: |
approvals: | governance.approvals: |
server: | gateway.server: |
admin: | gateway.admin: |
control_plane: | gateway.control_plane: |
content_storage: | storage: |
mcp.tools[] (etc.) | mcp.capabilities.tools[] (etc.) |
plugins.entries[] | plugins[] (flat array, no wrapper) |
plugins.kv / caches / secrets / configs / transports / policy / capability_grants / trust / credentials | DELETED — point-of-use slots + per-entry replace these (RFC mcp_gateway_point_of_use_wiring_rfc.md) |
plugins.health_probe | observability.plugin_health_probe |
plugins.registry | gateway.plugin_registry |
plugins.config_overlay | gateway.config_overlay |
plugins.response_cache | storage.response_cache |
plugins.enabled / plugins.plugin_dir | DELETED |
BackendImpl.type: (in a binding's backend: block) | BackendImpl.kind: |
The ten D'' top-level keys are: mcp:, governance:, gateway:, observability:, feature_flags:, debug:, schema_registry:, storage:, cluster:, plugins: (plus MCPG_CONFIG-only config_source:). governance: and gateway: are umbrellas — their children correspond one-to-one to former root peers.
MCPG_* env vars track the new shape with __ as the dotted-path separator. The corresponding env-var prefix migrations:
| Pre-D'' env var | Layout D'' env var |
|---|---|
MCPG_AUTH__* | MCPG_GOVERNANCE__ACCESS__* |
MCPG_POLICY__* | MCPG_GOVERNANCE__POLICY__* |
MCPG_AUDIT__* | MCPG_GOVERNANCE__AUDIT__* |
MCPG_APPROVALS__* | MCPG_GOVERNANCE__APPROVALS__* |
MCPG_SERVER__* | MCPG_GATEWAY__SERVER__* |
MCPG_ADMIN__* | MCPG_GATEWAY__ADMIN__* |
MCPG_CONTROL_PLANE__* | MCPG_GATEWAY__CONTROL_PLANE__* |
MCPG_CONTENT_STORAGE__* | MCPG_STORAGE__* |
MCPG_MCP__TOOLS__* (etc.) | MCPG_MCP__CAPABILITIES__TOOLS__* (etc.) |
MCPG_PLUGINS__HEALTH_PROBE__* | MCPG_OBSERVABILITY__PLUGIN_HEALTH_PROBE__* |
MCPG_PLUGINS__REGISTRY__* | MCPG_GATEWAY__PLUGIN_REGISTRY__* |
MCPG_PLUGINS__CONFIG_OVERLAY__* | MCPG_GATEWAY__CONFIG_OVERLAY__* |
MCPG_PLUGINS__RESPONSE_CACHE__* | MCPG_STORAGE__RESPONSE_CACHE__* |
Quick start (minimal viable)
Goal: gateway answers /health, tools/list, and one tools/call against your binding. No auth, no cluster, no compliance plumbing.
Template: examples/deployments/dev-single-node.yaml. Six fields are load-bearing — everything else takes a sensible default.
| Field | Why it matters | Default | Reference |
|---|---|---|---|
gateway.server.bind_address | The TCP listener. 127.0.0.1:8787 for dev; 0.0.0.0:8787 once you trust auth. | "127.0.0.1:8787" | ServerConfig |
gateway.server.allowed_origins | CORS allowlist for browser clients. Empty disables browser-cross-origin. | [] | ServerConfig |
mcp.capabilities.tools[] (and prompts[], resources[], resource_templates[]) | The tools / prompts / resources this gateway exposes. At least one entry to be useful. | [] | McpConfig, BackendConfig |
governance.access | Inbound identity. Empty = anonymous (loopback only). | {} | AccessConfig |
observability.logs.sinks | Where logs go. Default stderr-JSON is fine for dev. | one stderr JSON sink | LogsConfig |
governance.audit | Compliance audit. On by default with the built-in local-file sink — drop directory into a tmpfs / scratch mount if your dev disk is read-only. | enabled, file sink | AuditConfig |
Boot it:
$ mcpg-config-init --template dev-single-node --output config.yaml
$ mcpg-config-check config.yaml
$ MCPG_CONFIG=config.yaml mcpg
Production hardening
Goal: external traffic, OIDC, audit you can ship to compliance, multi-replica behind an LB. Pick this once dev clicks.
Templates: production-single-redis.yaml (single instance), production-redis-cluster.yaml (multi-replica), production-nats-cluster.yaml (NATS variant).
| Block | What it gates | Reference |
|---|---|---|
gateway.server.tls | Listener TLS — drop if your LB terminates TLS instead. | TlsConfig |
gateway.server.allowed_origins | Browser CORS allowlist. Wildcards are rejected. | ServerConfig |
gateway.server.max_sessions_per_tenant | Per-tenant session quota. 0 = unlimited; tighten for SaaS deploys. | ServerConfig |
cluster | Coordinator (KV + pub/sub). single_node for single-replica, redis / nats for multi-replica. | ClusterConfig |
governance.access.oidc_oauth | Inbound OIDC — verifies Bearer tokens against your IdP's JWKS. | OidcOAuthConfig |
governance.access.jwks | Static JWKS variant for air-gapped deploys (no IdP discovery call). | JwksConfig |
governance.policy | Pre-dispatch tool gate. default_minimum_trust + per-tool overrides + CEL allow_if. | PolicyConfig |
governance.audit | Compliance audit fan-out. required: true refuses to boot without a serving sink. | AuditConfig |
governance.approvals | RFC 0017 human-in-the-loop approvals — signing key + callback URL + grace window. | ApprovalsConfig |
plugins[] | Tool-gate / transform / identity / cluster / catalog plugins. Rate limiting, IP allowlist, circuit breakers all live here. Each entry carries its own signature.trusted_keys: + granted_capabilities: (per-entry, not a wiring block). | PluginEntryConfig |
observability.metrics / traces | Prometheus scrape endpoint + OTLP traces to your collector. | MetricsConfig, TracesConfig |
Cluster pub/sub inheritance. Capability store:/bus: overrides default to kind: cluster (the cluster backend's primitive) when omitted, so when cluster.kind is redis or nats, mcp.configurations.delivery.bus and mcp.configurations.cancellation.bus automatically use the cluster's pub/sub. Server-initiated messages (cancellations, sampling responses, elicitations) reach the right replica without operator config. Override these only when you explicitly want single-replica behaviour despite a cluster (e.g. bus: { kind: memory }).
Advanced / experimental
Goal: pipeline tools, server-initiated suspensions, per-plugin observability carve-outs, control-plane attachment. Ignore until production basics are solid.
| Feature | Block | Reference |
|---|---|---|
| Pipeline bindings — multi-step tools that chain HTTP / SQL / Command / Transform / CEL gate steps. | mcp.capabilities.tools[].backend: { kind: pipeline, steps: [...] } | PipelineBackendConfig, PipelineStepConfig |
Suspending pipeline steps — elicitation, sampling, roots_list. The pipeline pauses, the gateway sends a server-initiated request, the step resumes when the client responds. | mcp.capabilities.tools[].backend.steps[].kind: elicitation | sampling | roots_list | PipelineElicitationStepConfig, PipelineSamplingStepConfig, PipelineRootsListStepConfig |
| RFC 0017 approval gates — block a tool call until a human approves it via callback URL. | governance.approvals + plugin entry for the approvals provider | ApprovalsConfig |
| MCP App URL — link a resource to a rich UI for client-side rendering. | mcp.capabilities.resources[].mcp_app_url / mcp.capabilities.resource_templates[].mcp_app_url (CEL-templatable) | BackendConfig |
Resource subscription with custom watch strategy — push-based change notification with notifications/resources/updated. | mcp.capabilities.resources[].watch / mcp.capabilities.resource_templates[].watch | ResourceWatchConfig |
| Per-plugin observability override — silence a noisy plugin or boost its verbosity in isolation, optionally redirect its events to a separate sink set. | plugins[].observability | PluginObservabilityToggle, SignalToggle, SinkMode |
| Control-plane attachment — gateway registers with a CP at boot, opens an agent Channel, ships per-tool-call samples. | gateway.control_plane + cp-attached Cargo feature | ControlPlaneAttachConfig |
Notification filter — server-side filtering of tools/list_changed etc. before broadcast. | mcp.capabilities.resources[].watch.notification_filter / mcp.capabilities.resource_templates[].watch.notification_filter | NotificationFilterConfig |
| Plugin config overlay — operator-staged dynamic config delivered via config-provider plugins (consul / k8s ConfigMap / etc.). | gateway.config_overlay | ConfigOverlayConfig |
Multi-tenant deployments
MCPG has no top-level tenants: block by design. Per-tenant differentiation composes from three orthogonal primitives that already exist:
-
Tenant identity. Comes off the verified principal —
$identity.subject_id,$identity.attributes.<claim>,$identity.roles[],$identity.groups[]. Whichever OIDC claim represents your tenant (commonlytid,org_id, or a custom claim) ends up under$identity.attributes.<claim>once the inbound JWT verifier resolves it. No config knob is needed for the tenant ID itself. -
Per-tenant binding allowlist. Goes through
governance.policy.tool_access.rules[].cel_allow_if. Each binding gets a CEL predicate that references the principal's tenant claim:yamlgovernance: policy: tool_access: default_minimum_trust: verified rules: - tool_name: "acme.*" cel_allow_if: '$identity.attributes.tenant == "acme" || "platform" in $identity.groups' - tool_name: "partner.*" cel_allow_if: '$identity.attributes.tenant == "partner"' # shared.* falls through to default_minimum_trust (any verified caller).The CEL predicate runs pre-dispatch alongside trust-floor checks, so a deny is observable through the same audit shape (
mcpg.policy.tool_call.denied) as any other policy denial. -
Per-tenant rate limit + quota. Lives in the rate-limit plugin (post-P0-3, plugin-only). The plugin's config is keyed by tenant identity from the same
$identitysurface. Example shape (rate-limit plugin's config; the actual fields depend on the plugin you load):yamlplugins: - id: dev.mcpg.builtin.rate_limit config: default: tools_per_minute: 1000 by_tenant: acme: { tools_per_minute: 10000, burst: 200 } partner: { tools_per_minute: 100, burst: 10 } tenant_key: '$identity.attributes.tenant'Per-binding rate-limit references go through the backend's own per-use slot (point-of-use wiring) — same shape as any other plugin reference.
The pre-existing gateway.server.max_sessions_per_tenant knob is the one gateway-resident tenant-aware quota; it's enforced inside the session store (per-tenant cap on concurrent sessions) and works regardless of which CEL gate let the request through.
A first-class tenants: block that desugars into the above is a future option logged in docs/internal/FUTURE.md. Until the recipes turn out painful in operator hands, the existing primitives stay the source of truth — adding a parallel mechanism would split tenant config across two places.
Templating and secret resolution
MCPG uses a single CEL-based expression syntax everywhere — ${...} outer markers wrap a CEL expression. There's exactly one form for environment variables, identity, arguments, OAuth tokens, and credential lookups; no parallel layers.
mcp:
capabilities:
tools:
- name: github.user.repos.list
description: Fetch a user's repositories from GitHub.
backend:
kind: http
url: "https://api.github.com/users/${$arguments.username}/repos"
method: get
headers:
Authorization: "Bearer ${env.GITHUB_TOKEN}"
X-Trace-Id: "${$identity.subject_id}-${$arguments.username}"
gateway:
plugin_registry:
auth:
username: "${env.GHCR_USERNAME}"
password: "${env.GHCR_TOKEN}"
plugins:
# Outbound OAuth 2.0 (RFC 6749 client_credentials) lives behind
# the `dev.mcpg.credential.oauth-client-credentials` plugin.
# Bindings reference issued tokens via the standard `cred://`
# URI scheme — see the table below.
- id: dev.mcpg.credential.oauth-client-credentials
config:
providers:
analytics:
token_url: "https://auth.example.com/oauth/token"
client_id: "mcpg-prod"
client_secret: "${env.ANALYTICS_CLIENT_SECRET}"
scopes: ["read:events"]
Available roots:
| Root | Resolved at | Notes |
|---|---|---|
$env.<NAME> | Config-load (once) | Process environment. Errors if unset. |
$arguments.<key> | Per request | Tool-call arguments. |
$identity.<field> | Per request | subject_id, attributes.<key>, roles[N], groups[N], … |
cred://<plugin_id>/<target>[#part] | Per request | Credential plugin lookup. Covers outbound OAuth tokens (cred://dev.mcpg.credential.oauth-client-credentials/<provider>), Vault dynamic DB creds (cred://vault-dynamic-db/orders#username), and any other registered credential_issuer plugin. |
$context.<field> | Per request | Transport, principal, trust level, etc. |
$tool_name | Per request | Current tool's MCP name. |
$steps.<id>.output | Pipeline only | Previous step's result. |
$env.X is resolved once at config-load — restarts pick up new values. Everything else is per-request, so a token rotation reaches in-flight calls on the next dispatch without a reload.
Reference
What follows is the full alphabetical reference of every type reachable from AppConfig, generated from /// rustdoc + #[serde(...)] annotations. Use mcpg-config-explain <field> to drill into a single field on the command line.
Top-level structure (AppConfig)
Every field on the root AppConfig, alphabetised. Click a type to jump to its per-block reference below.
| Field | Type | Default | Summary |
|---|---|---|---|
cluster | ClusterConfig | (see type) | Cluster coordinator (spec §9.13). Singleton: the operator picks one coordinator and configures it inline. Default is the built-in single-node coordinator — safe for single-instance deployments. Other kinds map to mcpg-plugin-cluster-* cdylib plugins; the cdylib must still be declared under plugins.entries[] for the gateway to load it. The inline cluster block is the single source of truth for the coordinator's runtime config — it overrides any config: block on the matching plugins.entries[] row. |
debug | DebugConfig | (see type) | Operator-defined diagnostic tools (mcpg.command.* / mcpg.network.*) plus their probe profiles. The block is fully ignored unless feature_flags.debug_tools_enabled is true; production deploys keep that flag off and treat this block as scaffolding for CI / dev rollouts. |
feature_flags | FeatureFlagsConfig | (see type) | Operator-controlled strictness / compatibility flags. Every flag defaults off; flipping one is an explicit acknowledgement that the operator is taking on the risk the default protects against. These were previously MCPG_* env-var toggles (ALLOW_HEADER_PASSTHROUGH, SEP2260_PANIC); collapsing them into this block lets them show up in the curated reference + JSON Schema and audit-emit when active. |
gateway | GatewayConfig | (see type) | gateway: umbrella — the binary's network face: listener (server), admin surface (admin), Control Plane attachment (control_plane). |
governance | GovernanceConfig | (see type) | governance: umbrella — tool-call lifecycle: identity (access) → authorization (policy) → human gate (approvals) → evidence (audit). Co-located under one umbrella so the governance story reads as a coherent block. |
mcp | McpConfig | (see type) | mcp: namespace — the MCP protocol surface. Two children: capabilities: (tools / prompts / resources / resource_templates / tasks / elicitation / sampling / roots — what the server advertises in initialize) and configurations: (sessions / pipelines / subscriptions / delivery / cancellation — runtime-emergent state). Capability persistence (store: / bus:) defaults to kind: cluster — the cluster coordinator's primitive — and can be overridden per capability with kind: memory / file. |
observability | ObservabilityConfig | (see type) | All observability concerns — log/metric/trace emission, the binding-backend health prober, and the sink fan-out routing for telemetry / log events. Sub-fields all default to safe single-node values so the block is fully optional. |
plugins | array<PluginEntryConfig> | [] | Loaded plugin entries — flat array, no wrapper. Each entry is self-contained (id / class / source / signature / config / limits / enforce / granted_capabilities / observability / http_route / disabled). Identity / policy / credential / catalog / cluster plugins all dispatch via the class: field. An empty array is the kill switch — no plugins are loaded. |
schema_registry | map<string, SchemaEntry> | {} | Named JSON Schemas operator-declared once, referenced by {"$schema_ref": "<name>"} in any binding's input_schema: / output_schema:. Named schema_registry: (rather than schemas:) to disambiguate from the per-binding schema fields (input_schema:, output_schema:). Each entry (SchemaEntry) is inline / file / url. |
storage | StorageConfig | (see type) | storage: block. Holds operator-declared content-store providers AND the gateway-managed LLM response cache. Each provider entry produces a named ContentStore in the gateway's registry; bindings reference providers by id via their own content_storage: field. When providers is empty AND no binding declares a content_storage: route, the gateway auto-creates a single in-process provider with id default and the standard 256 MiB cap. |
Per-block reference
Every type reachable from AppConfig, alphabetised. Field tables show type, default, and the field's /// doc-comment summary.
AccessConfig
| Field | Type | Default | Summary |
|---|---|---|---|
jwks | JwksConfig (optional) | ||
oidc_oauth | OidcOAuthConfig (optional) | ||
resource_metadata | OAuthResourceMetadataConfig (optional) | OAuth 2.1 Protected Resource Metadata (RFC 9728). When set, enables GET /.well-known/oauth-protected-resource. If omitted but oidc_oauth providers are configured, metadata is auto-derived. |
AdminAuthConfig
Variants:
-
static_bearerbearer_token_env: string
-
trusted_header— Security: trusted-header mode requires a value match viatrusted_value_env. Header-presence-only is insecure and generates warnings on every request.header_name: stringtrusted_value_env: string (optional)
-
disabled
AdminConfig
| Field | Type | Default | Summary |
|---|---|---|---|
auth | AdminAuthConfig | (see type) | |
base_path | string | "/admin/v1" | |
bind_address | string | "127.0.0.1:9090" | |
disclosure | DisclosureLevel | "summary" | |
enabled | boolean | false |
ApprovalsConfig
Tool-gate human approval (RFC 0017) configuration.
| Field | Type | Default | Summary |
|---|---|---|---|
callback_base_url | string (optional) | Public base url the gateway hands to notifiers as the callback URL prefix (e.g. "https://gw.example.com"). The runtime appends /webhooks/approvals/<id>?expires=...&sig=.... | |
callback_grace_ms | integer | 60000 | Seconds beyond deadline_at during which late callbacks still authenticate. Defence-in-depth — the registry's own deadline timer already rejects late resolutions; this just keeps the URL valid for short retries. Default 60s. |
signing_key_env | string (optional) | Env var name from which the gateway reads the HMAC signing key for approval callback URLs. The key MUST be at least 32 bytes (256 bits) — the gateway hard-fails boot if shorter. When unset, the gateway falls back to a random per-process key (callbacks won't survive a restart). |
AppsConfig
apps: config — SEP-1865 MCP Apps support.
MCP Apps lets a server attach an interactive HTML UI to a tool. The ui/* postMessage protocol runs host↔iframe and never reaches the gateway; MCPG's role is passthrough of _meta.ui, capability advertisement (both downstream to clients and upstream to federated servers), federation resourceUri rewriting, and a tighten-only CSP/permission policy layer. See apps/gateway/docs/multi-version/mcp-apps-rfc.md.
Off by default. When enabled: false, MCPG omits the io.modelcontextprotocol/ui extension from its capability advertisement and applies no policy — but _meta.ui still round-trips on tool/resource descriptors (passthrough is wire-shape, not capability-gated, so a client with a cached template keeps working). When enabled: true, advertisement lights up and the csp_policy / allowed_permissions / allowed_domains clamps below are enforced on egress.
| Field | Type | Default | Summary |
|---|---|---|---|
allowed_domains | array<string> (optional) | If set, a _meta.ui.domain outside this list is dropped (the host falls back to its default sandbox origin); in strict mode the whole response is rejected instead. None ⇒ any domain allowed. | |
allowed_permissions | array<AppsPermission> | (see type) | iframe permissions MCPG will let through; any _meta.ui.permissions key outside this list is stripped on egress. Default: all four standard permissions. |
csp_policy | AppsCspPolicy | (see type) | CSP upper bound. Each axis is intersected (never unioned) with the upstream's declared _meta.ui.csp. ["*"] on an axis imposes no bound on that axis (upstream passes through). An omitted axis on the upstream is left omitted (the host applies its restrictive default — frame-src 'none' / base-uri 'self'); policy never materializes an absent axis. |
enabled | boolean | false | Master switch for DOWNSTREAM advertisement + egress policy. Default false (opt-in). |
federate_upstream | boolean (optional) | Advertise the Apps capability on MCPG's OUTGOING (client→upstream) initialize so federated servers emit their UI-enabled tools. A spec-compliant upstream checks the client's io.modelcontextprotocol/ui capability before registering UI tools — omit this and such an upstream withholds every UI tool. None ⇒ inherit enabled. Set true explicitly to pull UI tools from upstreams while still withholding the capability from your own clients. | |
strict | boolean | false | Reject (vs sanitize) an upstream response whose _meta.ui escaped the policy below — a domain/permission/CSP entry outside the operator allow-list. Default false (permissive: narrow + log, never reject). |
AppsCspPolicy
The four CSP-axis allow-lists. Defaults mirror a sensible middlebox posture: no bound on what the app may fetch/connect to (["*"]), but frame embedding and <base> pinned to self.
| Field | Type | Default | Summary |
|---|---|---|---|
base_uri_domains | array<string> | (see type) | |
connect_domains | array<string> | (see type) | |
frame_domains | array<string> | (see type) | |
resource_domains | array<string> | (see type) |
AppsPermission
A standard iframe permission. Serialized snake_case in config; maps to the camelCase _meta.ui.permissions key on the wire.
Allowed values:
cameramicrophonegeolocationclipboard_write
AuditConfig
Top-level audit: block. A top-level peer (rather than nested under observability:), with an inner schema aligned to the OTel signal-triad sinks-list pattern (logs / metrics / traces). Spec §9.12 defines the semantics; the fields here are the Rust projection.
Audit sinks fan out via sinks: [{kind, config, level?}]. The built-in dev.mcpg.builtin.audit.local-file activates only when its plugin id appears in sinks[].kind (there is no disable_builtins toggle — just omit the sink to disable it).
| Field | Type | Default | Summary |
|---|---|---|---|
emit_tool_call_allowed | boolean | true | Emit mcpg.tool.call.allowed after every successful pre-dispatch tool_gate chain. Default true for the compliance posture most operators want — every tool call on record. High-volume / low-compliance deploys can set false; deny + challenge paths still emit regardless. |
emit_tool_call_completed | boolean | true | Emit mcpg.tool.call.completed after every successful post-dispatch tool_gate chain. Default true. Records execution_duration_ms for auditors flagging long-running calls. |
enabled | boolean | true | Master toggle for the audit channel. When false, no audit sinks are registered (built-in or plugin), no audit events are emitted, and required is ignored. Default true. Set false only for dev/test runs where compliance is out of scope. |
on_failure | AuditOnFailure | "fail_closed" | Policy for per-event emit failures. Today the fan-out is always best-effort at the registry level (failures are metricsed but don't block the request). This field is captured + validated so the operator's intent is durable; the runtime behavior hookup lands in a future improvement (the emit site needs to translate this into "return error from the tool-gate chain" on fail_closed). |
required | boolean | true | When true (default), the gateway REFUSES TO START unless at least one audit sink is serving traffic after plugin registration completes. Ignored when enabled: false. Operators explicitly set false only for dev / CI runs where compliance is not in scope. |
sinks | array<SinkConfig> | (see type) | Audit-sink fan-out. Each entry's kind: is a plugin id resolved against the registered audit sinks at boot. The built-in dev.mcpg.builtin.audit.local-file is the canonical default — listed in [AuditConfig::default]. |
AuditOnFailure
Operator policy when an audit-sink emit fails.
Variants:
-
fail_closed— (default) On emit failure, refuse to serve the triggering request. Compliance-safe: no action happens without a durable audit trail. Subtle: this can wedge the gateway if every registered sink is broken — operators should always configure at least one sink whose availability they actually monitor. -
fail_open— On emit failure, log + continue. The triggering request completes even if the audit event does not persist. Dev / CI use only — a compliance auditor will not accept this as SOC2-clean.
AuthConfig
How MCPG authenticates to the upstream.
| Field | Type | Default | Summary |
|---|---|---|---|
credential | string (optional) | Credential-issuer reference for oauth_client_credentials: a standard cred://<plugin_id>/<target> URI (RFC 0016), e.g. cred://dev.mcpg.credential.oauth-client-credentials/notion. The referenced issuer plugin mints + refreshes the upstream bearer; no client secret lives in the federation config. | |
mode | AuthMode | "none" | |
token | string (optional) | Static bearer token for service_token (supports ${env.X}). |
AuthMode
Identity-propagation mode (RFC v1 §6).
Variants:
-
none— No auth sent. -
service_token— Static bearer token. -
pass_through— Forward the inboundAuthorizationheader verbatim. -
oauth_client_credentials— Machine-identity token via an OAuth provider. Phase 2. -
oauth_impersonation— Per-caller token-exchange (RFC 8693). Phase 2.
BackendAnnotationsConfig
Tool annotation hints configurable per binding. Maps to MCP ToolAnnotations.
| Field | Type | Default | Summary |
|---|---|---|---|
destructive | boolean (optional) | ||
idempotent | boolean (optional) | ||
open_world | boolean (optional) | ||
read_only | boolean (optional) |
BackendConfig
| Field | Type | Default | Summary |
|---|---|---|---|
annotations | BackendAnnotationsConfig (optional) | ||
backend | BackendImpl | Implementation backend — discriminated by kind:. The backend is an explicit nested object (backend: { kind: http, url: ... }) rather than fields hoisted onto the binding itself. | |
cache | KindRef (optional) | Per-binding LLM response-cache override. Resolves via resolve_kind(SlotClass::Cache, ...) at boot: | |
content_storage | string (optional) | Content-store provider this binding routes through. Must match one of the storage.providers: [{id, ...}] entries declared at the top level. When unset, the binding falls back to the provider id named in content_storage.default (or the conventional default id when neither is set). See mcpg_gateway_llm_phase_5_rfc.md §7 for the full content-store routing design. | |
description | string | ||
descriptor_meta | any | ||
governance | BackendGovernanceConfig | (see type) | |
icons | array<BackendIconConfig> (optional) | MCP 2025-11-25 descriptor extensions — icons and free-form _meta. Populated directly on the tool/prompt/resource/template descriptor that this binding produces. | |
input_schema | any | ||
mcp_app_url | string (optional) | MCP App URL — a link to a rich UI for this resource. Populated on _meta.mcpAppUrl in resources/list descriptors and resources/read results. Supports CEL interpolation for dynamic segments (e.g., https://app.example.com/docs/${$arguments.id}). Only meaningful on kind: resource or kind: resource_template. | |
mime_type | string (optional) | ||
name | string | ||
output_schema | any | ||
prompt_arguments | array<PromptArgumentConfig> (optional) | ||
quotas | BackendQuotasRef (optional) | Per-binding quota policy reference. Names at most one of each kind by id; each id must resolve to a registered policy in governance.quotas.{rate_limits,budgets,concurrency}[]. None (default) means this binding is exempt from quota enforcement. The runtime gate that consults this field is behind the governance-quotas cargo feature — until that feature is on, the field is parsed + validated but inert. | |
resource_annotations | BackendResourceAnnotations (optional) | Optional resource annotations (audience, priority, lastModified) surfaced on resources/list entries. Meaningful only on kind: resource or kind: resource_template bindings. | |
resource_size | integer (optional) | Optional per-resource size hint (bytes) surfaced on resources/list entries. Meaningful only on kind: resource bindings; ignored elsewhere. | |
retry | RetryConfig (optional) | ||
task_support | string (optional) | ||
title | string (optional) | ||
uri | string (optional) | ||
uri_template | string (optional) | ||
variable_completions | map<string, VariableCompletionSource> (optional) | Optional completion sources per template variable. The completion/complete handler returns the filtered subset matching the caller's prefix when the MCP client opens auto-complete on a resource template variable. Keys MUST match a {variable} declared in uri_template; mismatched keys are dropped at registration with a warning. | |
watch | ResourceWatchConfig (optional) |
BackendGovernanceConfig
| Field | Type | Default | Summary |
|---|---|---|---|
allow_if | string (optional) | ||
minimum_trust | TrustLevelConfig | "header_asserted" |
BackendIconConfig
Configurable descriptor icon shape, mirrored onto MCP's Icon type.
| Field | Type | Default | Summary |
|---|---|---|---|
mime_type | string (optional) | ||
sizes | array<string> (optional) | ||
src | string | ||
theme | string (optional) |
BackendImpl
Variants:
-
(unnamed variant)expected_status_codes: array<integer>headers: map<string, string>kind: stringmax_response_bytes: integermethod:HttpBackendMethodrequire_json_response: booleantimeout_ms: integerurl: string
-
(unnamed variant)args: array<string>command: stringkind: stringmax_output_bytes: integerrequire_json_stdout: booleantimeout_ms: integer
-
(unnamed variant)credentials_path: string (optional)kind: stringmax_response_bytes: integersubject: stringtimeout_ms: integerurl: string
-
(unnamed variant)headers: map<string, string>kind: stringmax_response_bytes: integermethod: stringservice: stringtimeout_ms: integerurl: string
-
(unnamed variant)headers: map<string, string>kind: stringmax_response_bytes: integeroperation: stringtimeout_ms: integerurl: string
-
(unnamed variant)bootstrap_servers: stringgroup_id: stringkind: stringmax_response_bytes: integerrequest_topic: stringresponse_topic: stringtimeout_ms: integer
-
(unnamed variant)delay_ms: integererror: booleanerror_message: string (optional)kind: stringpassthrough: booleanresponse: any
-
(unnamed variant)kind: stringpipeline_timeout_ms: integersteps: array<PipelineStepConfig>
-
(unnamed variant)— OpenAPI binding (mcpg-plugin-backend-openapi, kindopenapi). References one operation of asourceregistered in the plugin's own config (plugins.entries[].config.sources). The plugin derives the tool input/output schema from the operation and dispatches the call as an outbound HTTP request — the operator names only which source + operation to surface, not a URL or schema.kind: stringoperation: stringsource: string
-
(unnamed variant)— SQL database binding (Postgres / MySQL / SQLite). -
(unnamed variant)— OpenAI public chat-completion API (mcpg-plugin-backend-llm-openai, kindopenai_chat). Same flatten-passthrough pattern asSql: the gateway forwards the raw spec to the plugin, which owns the schema. Seedocs/rfcs-archive/mcpg/mcp_gateway_llm_phase_5_rfc.md§5.0. -
(unnamed variant)— Azure OpenAI deployments (mcpg-plugin-backend-llm-openai, kindazure_openai_chat). Operator supplies a per-deployment URL with embedded?api-version=…. -
(unnamed variant)— Anthropic Messages API (mcpg-plugin-backend-llm-anthropic, kindanthropic_chat). -
(unnamed variant)— Google Gemini AI Studio API (mcpg-plugin-backend-llm-gemini, kindgemini_chat). -
(unnamed variant)— Generic OpenAI-compatible endpoint (mcpg-plugin-backend-llm-compat, kindcompat_chat): vLLM, LocalAI, Together, Groq, OpenRouter, llama.cpp's OpenAI server, Vertex AI's OpenAI compatibility surface, etc. Operator MUST declarebase_url;api_keyis optional. -
(unnamed variant)— OpenAI embeddings API (mcpg-plugin-backend-llm-openai, kindopenai_embedding). -
(unnamed variant)— Azure OpenAI embeddings deployments (mcpg-plugin-backend-llm-openai, kindazure_openai_embedding). -
(unnamed variant)— Google Gemini AI Studio embeddings (mcpg-plugin-backend-llm-gemini, kindgemini_embedding). -
(unnamed variant)— Generic OpenAI-compatible embeddings endpoint (mcpg-plugin-backend-llm-compat, kindcompat_embedding). -
(unnamed variant)— OpenAI image generation (DALL-E) (mcpg-plugin-backend-llm-openai, kindopenai_image). -
(unnamed variant)— Azure OpenAI image deployments (mcpg-plugin-backend-llm-openai, kindazure_openai_image). -
(unnamed variant)— Google Imagen image generation (mcpg-plugin-backend-llm-gemini, kindgemini_image). -
(unnamed variant)— Stability AI Stable Image generation (Core / SD3 / Ultra) (mcpg-plugin-backend-llm-stability, kindstability_image). -
(unnamed variant)— OpenAI text-to-speech (mcpg-plugin-backend-llm-openai, kindopenai_tts). -
(unnamed variant)— Azure OpenAI TTS (mcpg-plugin-backend-llm-openai, kindazure_openai_tts). -
(unnamed variant)— OpenAI speech-to-text (Whisper) (mcpg-plugin-backend-llm-openai, kindopenai_stt). -
(unnamed variant)— Azure OpenAI STT (mcpg-plugin-backend-llm-openai, kindazure_openai_stt).
BackendQuotasRef
Per-binding quota reference — operator names at most one of each policy kind by id. The runtime gate that consults these refs is gated behind the governance-quotas cargo feature.
All three fields are independent options; an absent field means "no policy of that kind for this binding". A binding may name more than one kind at once (e.g. both a rate limit AND a concurrency cap), but at most one policy of each kind.
| Field | Type | Default | Summary |
|---|---|---|---|
budget | string (optional) | Id from governance.quotas.budgets[].id. Optional. | |
concurrency | string (optional) | Id from governance.quotas.concurrency[].id. Optional. | |
rate_limit | string (optional) | Id from governance.quotas.rate_limits[].id. Optional. |
BackendResourceAnnotations
Operator-configurable MCP ContentAnnotations for a resource binding.
| Field | Type | Default | Summary |
|---|---|---|---|
audience | array<string> (optional) | ||
last_modified | string (optional) | ||
priority | number (optional) |
BudgetPolicy
One named budget policy (cost cap / call count / token count).
| Field | Type | Default | Summary |
|---|---|---|---|
cap_calls | integer (optional) | Call cap when kind: call_count. Required for that kind. | |
cap_token_count | integer (optional) | Token cap when kind: token_count. Required for that kind. | |
cap_usd | number (optional) | Cost cap in USD when kind: cost. Required for that kind. | |
id | string | ||
identity_claim | string (optional) | JWT claim path for per_identity scope. | |
kind | string | "cost" | Budget kind: cost (USD), call_count, or token_count. |
on_exceeded | string | "deny" | Action when the cap is hit (same vocabulary as RateLimitPolicy). |
scope | string | "per_identity" | Scope discriminator (same vocabulary as RateLimitPolicy). |
warn_at_pct | integer (optional) | Emit governance.quota.warn when drawdown crosses this percentage of the cap. Defaults to no warning. 0..=100. | |
window | string | Rolling window over which the cap applies. Suffixes s/m/ h/d. Maximum 30d. |
BusOverrideConfig
<capability>.bus: { kind, … } — produces an Arc<dyn mcpg_cluster_api::PubSub> at boot.
Recognised kind values: cluster, memory. (redis and nats are not accepted here — set cluster.kind: redis | nats and use kind: cluster here, or omit the override entirely.)
| Field | Type | Default | Summary |
|---|---|---|---|
kind | string |
CancellationConfig
cancellation: config — cluster-wide cancellation fan-out (notifications/cancelled and tasks/cancel) plus a per-capability bus: override. Same shape as DeliveryConfig.
| Field | Type | Default | Summary |
|---|---|---|---|
bus | BusOverrideConfig (optional) |
ClaimMappingConfig
| Field | Type | Default | Summary |
|---|---|---|---|
attribute_claim_mappings | map<string, string> | {} | |
group_claim_paths | array<string> | [] | |
role_claim_paths | array<string> | [] | |
scope_claim_paths | array<string> | (see type) | |
subject_claim | string | "sub" |
ClientCertMode
Operator-facing client-cert acceptance mode. Same vocabulary as RFC 0008 §4.4.
Allowed values:
noneoptionalmandatory
ClusterConfig
Top-level cluster config. The cluster plugin is the unified backbone for MCPG multi-instance state + coordination — it internally instantiates the four primitive impls (KeyValueStore, PubSub, Lease, Watch) and exposes them via accessor methods. kind is the discriminator; everything else is kind-specific config that flows straight to the plugin's factory as JSON.
yaml cluster: kind: redis # single_node | etcd | consul | nats | redis url: ${env.REDIS_URL} # rest of the fields are kind-specific key_prefix: "mcpg:cluster:"
kind: single_node (the default when cluster: is omitted) installs the in-process built-in coordinator and ignores the rest of the block. Other kinds map to mcpg-plugin-cluster-<kind>; the cdylib must still be declared under plugins.entries[] (the inline cluster.* fields override any config: block on the matching entry).
| Field | Type | Default | Summary |
|---|---|---|---|
kind | string | "single_node" |
ConcurrencyPolicy
One named concurrency cap.
| Field | Type | Default | Summary |
|---|---|---|---|
id | string | ||
identity_claim | string (optional) | ||
max_concurrent | integer | Maximum simultaneous in-flight calls. | |
on_exceeded | string | "deny" | Action when the cap is hit. deny returns immediately; queue waits up to queue_timeout_ms. |
queue_timeout_ms | integer | 30000 | Timeout for queued callers when on_exceeded: queue. Default 30s. |
scope | string | "per_identity" | Scope (typically per_tool, global, or per_identity). |
ConfigWatchConfig
gateway.config_watch: — operator-tunable file-watch reload trigger. Same semantics as SIGHUP and the admin endpoint: full GatewayRuntime rebuild via ArcSwap; session store preserved; credential cache rebuilt fresh; list_changed emitted per category for operational sessions on inventory delta.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | false | When true, the gateway watches its config files on disk and triggers a hot-reload when contents change. Polling- based — handles editor-write-via-rename (vim/emacs) and K8s ConfigMap atomic-symlink-swap transparently because the watcher reads through the symlink chain regardless of how the write landed. Defaults to disabled — operators must opt in. |
poll_interval_ms | integer | 5000 | Poll interval in milliseconds. Lower = faster reload after edit; higher = lower disk I/O. Default 5000 (5s) is imperceptible for config changes and trivial in I/O cost. Values below 1000 (1s) are clamped to 1000 at validate time with a warning — sub-second polling burns I/O for no human-perceivable benefit. |
ConflictPolicy
Conflict policy on a body-hash mismatch with a stored record. Today only Reject is implemented — design doc §7 explicitly rejected permissive_replay for v1.
Variants:
reject— Same key + different body hash → JSON-RPC error-32010 IdempotencyConflict(HTTP 422).
ControlPlaneAttachConfig
Control Plane attachment config. See apps/gateway/src/cp_attach.rs for the wiring logic.
| Field | Type | Default | Summary |
|---|---|---|---|
bootstrap_ca_pem | string (optional) | PEM-encoded CA bundle to trust on the very first connect (Register), before the agent has its own creds. Once Register completes, the CP-issued cert/key/ca_chain trio supplants this. Optional; only required when the CP gRPC listener is TLS and the operator hasn't pre-populated a previous run's agent-creds.json. | |
capture_payloads | boolean | false | Enterprise opt-in. When true, the gateway captures the JSON-serialized request arguments + response of each tool call and ships them in the MetricsReport (Channel-encrypted; the CP further encrypts at-rest with a per-tenant KMS-derived key). The captured bytes can contain PII / secrets, so this is off by default; the CP also gates ingest on the active license carrying the payload_capture feature flag, so flipping this true without a matching license is a no-op (samples ship but CP drops the payload bytes). |
enrollment_url | string (optional) | One-time enrollment URL minted by the CP UI. Required on first boot; subsequent boots reuse the cached creds in state_dir. | |
heartbeat_interval_ms | integer (optional) | Seconds between heartbeats. Default 30s. | |
instance_uid | string (optional) | Stable per-instance id. Defaults to ${HOSTNAME}-${uuid7-prefix} when unset. | |
state_dir | string | "./mcpg-cp-state" | Where to persist agent creds (agent-creds.json) and the LKG cache. Defaults to ./mcpg-cp-state. |
url | string | gRPC URL of the Control Plane (e.g. "https://cp.example.com:7844"). |
DebugCommandToolConfig
| Field | Type | Default | Summary |
|---|---|---|---|
args | array<string> | (see type) | |
command | string | "printf" | |
max_output_bytes | integer | 4096 | |
timeout_ms | integer | 2000 |
DebugConfig
Top-level debug: block — diagnostic tools surface only. The master switch lives at feature_flags.debug_tools_enabled. When that flag is false, every field below is ignored AND the mcpg.debug.* tools are stripped from the capability registry regardless of tools.exposure.
| Field | Type | Default | Summary |
|---|---|---|---|
tools | DebugToolsConfig | (see type) | Operator-defined diagnostic tools surfaced as MCP tools when feature_flags.debug_tools_enabled: true. See [DebugToolsConfig] for the surface. |
DebugNetworkToolConfig
| Field | Type | Default | Summary |
|---|---|---|---|
expected_status_codes | array<integer> | (see type) | |
headers | map<string, string> | {} | |
max_response_bytes | integer | 4096 | |
require_json_response | boolean | false | |
timeout_ms | integer | 2000 | |
url | string | "http://127.0.0.1:8787/health" |
DebugToolBackendsConfig
| Field | Type | Default | Summary |
|---|---|---|---|
command_probe_profile | string | "default_command_probe" | |
network_json_call_profile | string | "default_network_probe" | |
network_probe_profile | string | "default_network_probe" |
DebugToolExposureConfig
| Field | Type | Default | Summary |
|---|---|---|---|
command_probe | boolean | true | |
network_json_call | boolean | false | |
network_probe | boolean | true | |
operational_overview_prompt | boolean | true | |
runtime_overview_resource | boolean | true |
DebugToolsConfig
| Field | Type | Default | Summary |
|---|---|---|---|
bindings | DebugToolBackendsConfig | (see type) | |
command_profiles | map<string, DebugCommandToolConfig> | {} | |
exposure | DebugToolExposureConfig | (see type) | |
network_profiles | map<string, DebugNetworkToolConfig> | {} |
DeliveryConfig
delivery: config — delivery bus (the internal pub/sub that fans server-initiated messages out to the SSE stream owning each session) + per-capability bus: override. When bus is unset, the gateway inherits the cluster's pub_sub() primitive.
| Field | Type | Default | Summary |
|---|---|---|---|
bus | BusOverrideConfig (optional) |
DisclosureLevel
Allowed values:
summaryredactedfull
FeatureFlagsConfig
Operator-controlled strictness / compat flags.
Every field defaults to the safe / standards-compliant value; flipping a flag is an explicit acknowledgement that the operator is taking on the risk the default protects against.
| Field | Type | Default | Summary |
|---|---|---|---|
allow_header_passthrough | boolean | false | Forward credential-shaped inbound HTTP headers (Authorization, Cookie, X-API-Key, …) through to outbound bindings. The gateway strips these by default to avoid leaking client tokens to upstreams. Flip to true only for deployments that intentionally proxy bearer tokens to the binding (e.g., a pure-router deployment in a trusted network). |
debug_tools_enabled | boolean | false | Master switch for the operator-defined diagnostic tools (mcpg.command.* / mcpg.network.*). When false, every field under the top-level debug: block is ignored AND the debug tools are stripped from the capability registry regardless of debug.tools.exposure. Production deploys keep this off; flip on for CI / dev only. |
sep2260_panic_on_orphan | boolean | false | Upgrade SEP-2260 violations (server-initiated request emitted without an originating client request id) from a warning + metric counter to a process panic. Useful in CI / dev where the violation indicates a bug; should stay false in production so a single misrouted code path does not take the gateway down. |
FederationCacheConfig
Capability-cache behaviour.
| Field | Type | Default | Summary |
|---|---|---|---|
capability_ttl_secs | integer | 300 | Re-list the upstream's capabilities every N seconds even without a list_changed notification. |
FederationConfig
One federated upstream MCP server.
| Field | Type | Default | Summary |
|---|---|---|---|
cache | FederationCacheConfig | (see type) | Capability-cache behaviour (TTL refresh). |
filter | FilterConfig | (see type) | Allow/deny filtering of imported tool names. |
governance | BackendGovernanceConfig | (see type) | Governance inherited by every capability imported from this upstream — identical block to a native binding's, so the gate chain treats a federated call exactly like a native one. |
import | ImportConfig | (see type) | Which capability surfaces to import. Phase 1 honours tools. |
name | string | Source id. Also the default capability-prefix namespace and the federated_from label on synthetic capabilities. | |
naming | NamingConfig | {} | Prefixes applied to imported capability names / URIs. |
response | ResponseConfig | (see type) | Per-call response limits enforced gateway-side. |
retry | RetryConfig (optional) | Per-call retry policy for upstream dispatch. | |
session | SessionConfig | (see type) | Upstream-session behaviour. |
upstream | UpstreamConfig | Upstream connection (url, transport, auth, safety). |
FilterConfig
Allow/deny filtering of imported tool names (glob * suffix).
| Field | Type | Default | Summary |
|---|---|---|---|
exclude_tools | array<string> | [] | |
include_tools | array<string> | (see type) |
GatewayConfig
| Field | Type | Default | Summary |
|---|---|---|---|
admin | AdminConfig | (see type) | Admin HTTP surface — /admin/* routes, mutual-TLS or bearer-token auth, the operator-facing disclosure_level gate that controls how much detail diagnostic endpoints expose. Defaults to disabled; production deploys mount it behind an internal-only listener. |
config_overlay | array<string> | Ordered list of config_provider URIs to snapshot at gateway boot + deep-merge into an overlay value (spec §9.16). Lives here (rather than per-plugin) because it's gateway-process bootstrap config. Each URI must use a scheme bound by a registered config-provider plugin. | |
config_watch | ConfigWatchConfig | (see type) | File-watch config-reload trigger (third trigger, alongside SIGHUP and POST /admin/v1/config:reload). Background task polls the MCPG_CONFIG source set on disk and triggers a hot-reload when contents change. Default disabled. See [ConfigWatchConfig] for tuning. Useful for bare-metal systemd deployments and K8s deployments without the MCPG operator (which already does cluster-level config propagation via mcpg.dev/config-hash annotation forcing rolling restart). |
control_plane | ControlPlaneAttachConfig (optional) | Optional Control Plane attachment. When set AND the cp-attached Cargo feature is built in, the gateway registers with the CP at boot, opens an agent Channel, and ships per-tool-call samples for centralized observability (RFC 0009 / RFC 0010). When the feature isn't built in, this block is silently ignored. | |
plugin_registry | PluginRegistryConfig | (see type) | OCI plugin-registry configuration. Lives here (rather than per-plugin) because it's gateway-process tuning — where to fetch plugin artifacts from — not per-plugin config. Per-plugin source auth/tls live inline in each plugin entry's source.{auth,tls}:. Only consulted when at least one plugin entry uses source: { oci: ... }. |
server | ServerConfig | (see type) | Listener configuration — bind address, transport mode (HTTP / stdio / SSE), TLS, allowed origins, and per-request timeouts. The block is mandatory in practice (the listener won't bind without bind_address) but defaults to a localhost dev-mode shape so out-of-the-box mcpg boots without any config. |
GatherInputConfig
One entry in a [PipelineGatherStepConfig]. A trimmed projection of the standalone suspending-step configs carrying only the fields needed to mint the outgoing server request.
Variants:
-
(unnamed variant)correlation_token: stringkind: stringmessage: stringrequested_schema: any
-
(unnamed variant)correlation_token: stringkind: stringmax_tokens: integermessages: array<SamplingMessageConfig>system_prompt: string (optional)
-
(unnamed variant)correlation_token: stringkind: string
GovernanceConfig
Tool-call governance lifecycle: who → allowed? → extra gate → recorded → within limits.
Every child defaults to its own zero-value: an empty governance: block is valid YAML and produces a fully-default configuration (anonymous identity, untrusted-by-default policy, no human-gate signing key, audit channel disabled, no quotas declared).
| Field | Type | Default | Summary |
|---|---|---|---|
access | AccessConfig | (see type) | Inbound identity establishment — JWKS-backed JWT verification or OIDC discovery + introspection. When unset the gateway accepts unauthenticated callers and stamps every request with identity_kind: anonymous so the policy gate can deny them. jwks and oidc_oauth are mutually exclusive. |
approvals | ApprovalsConfig | (see type) | Tool-gate human approval (RFC 0017) — signing key + callback base url + grace window. When unset, the runtime defaults to a random per-process signing key + empty callback base url (suitable for tests + dev only — production deploys must supply a stable signing key). |
audit | AuditConfig | (see type) | Compliance-grade event sink fan-out (spec §9.12). Lives under governance: (rather than observability:) so the audit-as-evidence-of-governance story reads alongside access / policy / approvals. |
policy | PolicyConfig | (see type) | Tool-access policy — default minimum trust level + per-tool override rules. Operators can also point at a Cedar / Casbin / OPA bundle plugin under plugins[] to delegate the actual decision; this block stays useful for the gateway-internal default-trust gate every tool flows through before any plugin policy fires. RFC 0007. |
quotas | QuotasConfig | (see type) | Registry of named rate-limit / budget / concurrency policies. Bindings opt into specific policies by id via their per-binding quotas: block. Storage backend is a kind: slot under governance.quotas.store:. Full design lives in docs/rfcs-archive/mcpg/mcp_gateway_governance_quotas_rfc.md. |
HealthCheckConfig
| Field | Type | Default | Summary |
|---|---|---|---|
degraded_latency_threshold_ms | integer | 1000 | |
enabled | boolean | true | |
interval_ms | integer | 30 | |
timeout_ms | integer | 2000 | |
unhealthy_threshold | integer | 3 |
HealthProbeConfig
Periodic health-probe configuration. The probe is the only writer of PluginState::Degraded; without it plugins stay perpetually Active regardless of whether they're actually responding.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | true | Probe plugins periodically. Default: true. Set false to turn off the prober entirely (the Degraded state then never flips — test-only or historical deployments). |
failure_threshold | integer | 3 | Consecutive failures before flipping Active → Degraded. Default: 3. |
interval_ms | integer | 30000 | Seconds between probe cycles. Default: 30. |
probe_timeout_ms | integer | 5000 | Per-probe deadline in seconds. A plugin whose FFI call exceeds this is counted as a failure. Default: 5. |
HttpBackendMethod
Allowed values:
postget
IdempotencyConfig
idempotency: config — opt-in dedupe for tools/call and tasks/create. When enabled: false (the default), the gateway omits the dev.mcpg/idempotency extension from its initialize capability advertisement and silently ignores any _meta["dev.mcpg/idempotency-key"] the caller sets.
| Field | Type | Default | Summary |
|---|---|---|---|
conflict_policy | ConflictPolicy | "reject" | Conflict policy — only reject for v1. |
default_ttl_ms | integer | 86400000 | Default TTL applied to any reservation. Default 86_400_000 (24 hours) — matches Stripe's window. |
enabled | boolean | false | Master switch. Default false (opt-in, like governance.quotas was before it became cargo-feature-gated). |
max_ttl_ms | integer | 604800000 | Hard upper bound on per-record TTL. Default 604_800_000 (7 days). Future per-binding idempotency.ttl_ms overrides saturate at this cap. |
scope | IdempotencyScopeKind | "per_identity" | Scope strategy — per_identity (default), per_session, or per_tenant. |
store | StoreOverrideConfig (optional) | Per-capability store: override. Same shape as tasks.store / sessions.store. When unset, the idempotency KV inherits from the cluster coordinator's key_value_store() primitive. | |
supported_methods | array<string> | (see type) | JSON-RPC methods this extension applies to. Default ["tools/call", "tasks/create"] — read-only methods (resources/read, prompts/get, completion/complete) are intentionally excluded as they're idempotent by nature. |
IdempotencyScopeKind
Default scope strategy for idempotency records. Operator can widen to per_tenant (service-account dedupe) or narrow to per_session (ephemeral test harnesses).
Note: global is intentionally NOT a variant — see design doc §2.6. Cross-tenant replay is the #2 anti-pattern in the industry survey; we don't expose the footgun.
Variants:
-
per_session— All requests sharing one MCP session share the namespace. Useful for ephemeral test harnesses; resets on every re-initialize. -
per_identity— All requests sharing one resolved identity (OIDC subject + auth provider) share the namespace. The default — matches Stripe / Square idempotency semantics. -
per_tenant— All requests sharing one tenant id share the namespace. Useful for service-to-service workloads where multiple service accounts retry the same operation.
ImportConfig
Which capability surfaces to import.
| Field | Type | Default | Summary |
|---|---|---|---|
prompts | boolean | false | |
resource_templates | boolean | false | |
resources | boolean | false | |
tools | boolean | true |
JwksConfig
| Field | Type | Default | Summary |
|---|---|---|---|
allow_missing_audience | boolean | false | Dev escape-hatch: allow tokens without audience binding. Production MUST set an audience. |
audience | string (optional) | ||
header_name | string | "authorization" | |
header_prefix | string | "Bearer " | |
issuer | string (optional) | ||
keys_json | string (optional) | ||
url | string | "" |
KindRef
Discriminator + config payload at every consumer slot. Operators write { kind: <value>, ...config } in YAML; the gateway parses it as this type and resolves via [resolve_kind].
The config: field is a free-form JSON object passed to the resolved handle (built-in or plugin). The slot's resolver validates kind; the implementation validates config.
| Field | Type | Default | Summary |
|---|---|---|---|
config | any | Inline config forwarded to the resolved handle. Empty by default. | |
kind | string | Discriminator. One of: built-in keyword, full plugin id, short alias, or cluster. |
LogsConfig
observability.logs: — the logs signal.
Gateway internals (every tracing::info!() / warn!() / error!() call) AND plugin-emitted log events both flow through the configured sink list. Default sinks ship one stderr JSON emitter — production deployments add file, otlp, or plugin sinks (Loki, Splunk, …) by appending entries to sinks:.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | true | Master enable for the logs signal. When false, no log events are emitted regardless of sinks: content. |
level | string | "info" | Signal-level severity floor (trace / debug / info / warn / error). Per-sink level: can raise it further but can't lower it below this floor. Default: info. |
sinks | array<SinkConfig> | (see type) | Sink fan-out. Each entry's kind: resolves to a built-in factory (stderr / stdout / file / otlp) or plugin id. Default: one stderr sink with JSON format. |
McpCapabilitiesConfig
mcp.capabilities: — the MCP protocol-advertised surface.
Matches the protocol's initialize handshake's capabilities vocabulary: tools / prompts / resources / resource_templates, plus the gateway-side feature configs that govern protocol behaviour (tasks, elicitation, sampling, roots).
| Field | Type | Default | Summary |
|---|---|---|---|
elicitation | McpElicitationConfig | (see type) | MCP elicitation (RFC §11) — server-initiated prompt requests the gateway emits during pipeline execution. |
prompts | array<BackendConfig> | [] | Operator-declared prompts — the bindings that surface via prompts/list and prompts/get. Carry prompt_arguments. |
resource_templates | array<BackendConfig> | [] | Operator-declared resource templates — the bindings that surface via resources/templates/list and match resources/read URIs by template. Carry uri_template instead of uri. |
resources | array<BackendConfig> | [] | Operator-declared resources — the bindings that surface via resources/list and resources/read. Carry uri, mime_type, mcp_app_url, watch config. |
roots | McpRootsConfig | (see type) | MCP roots-list (RFC §13) — gateway requests roots from the client (e.g. for resource scoping). |
sampling | McpSamplingConfig | (see type) | MCP sampling (RFC §12) — server-initiated LLM completion requests forwarded back to the client. |
tasks | TasksConfig | (see type) | MCP Tasks (RFC §10) — task-augmented tool-call semantics. Carries the task store override, TTL/reaper tuning, and the task-supported tools list. |
tools | array<BackendConfig> | [] | Operator-declared tools — the bindings that surface via tools/list and tools/call. Each entry has its own implementation backend: (HTTP / SQL / NATS / LLM / pipeline / …) plus tool-specific MCP fields (annotations, task_support). |
McpConfig
Top-level mcp: block — the MCP protocol surface.
Two children that mirror MCP's own vocabulary: - capabilities: — what the server advertises in the initialize handshake (tools, prompts, resources, resource_templates, tasks, elicitation, sampling, roots). - configurations: — runtime-emergent state handling (sessions, pipelines, subscriptions, delivery, cancellation). Operator only tunes persistence + constraints; the items themselves are created by clients at runtime.
| Field | Type | Default | Summary |
|---|---|---|---|
capabilities | McpCapabilitiesConfig | (see type) | What this MCP server advertises in the initialize handshake. Mirrors the protocol spec's capabilities vocabulary one-to-one. |
configurations | McpConfigurationsConfig | (see type) | Runtime-emergent state handling. Operator only tunes persistence + constraints; the items themselves are created by clients at runtime. |
federations | array<FederationConfig> | [] | Upstream MCP servers federated through this gateway. Each entry is a capability source (1:N): MCPG connects to the upstream, imports its capabilities, and re-serves them under a prefix. See apps/gateway/docs/federation/. Default empty — existing configs are unaffected. |
McpConfigurationsConfig
mcp.configurations: — runtime-emergent state handling.
| Field | Type | Default | Summary |
|---|---|---|---|
apps | AppsConfig | (see type) | io.modelcontextprotocol/ui (SEP-1865 MCP Apps) extension config. Off by default; enabled: true lights up the capability advertisement (downstream + upstream) and the tighten-only CSP/permission egress policy. |
cancellation | CancellationConfig | {} | |
delivery | DeliveryConfig | {} | |
idempotency | IdempotencyConfig | (see type) | dev.mcpg/idempotency extension config. Off by default; flipping enabled: true lights up the SEP-2133 capability advertisement and the dispatcher dedupe path. |
pipelines | PipelinesConfig | {} | |
request_state | RequestStateConfig | {} | MRTR requestState codec configuration (DRAFT-2026-v1 / 2026-07-28 modern wire). Inert when no modern client connects; absent encryption_key the codec uses an ephemeral key at boot. |
sessions | SessionsConfig | {} | |
subscriptions | SubscriptionsConfig | (see type) |
McpElicitationConfig
mcp.elicitation: — gateway behavior for server-initiated elicitation prompts. Today carries only timeout_ms; future per-elicitation-type config can grow here.
| Field | Type | Default | Summary |
|---|---|---|---|
timeout_ms | integer | 60000 | Maximum time the gateway waits for the client's response to an elicitation prompt before giving up. Default 60 000. |
McpRootsConfig
mcp.roots: — gateway behavior for server-initiated roots-list requests forwarded to the client.
| Field | Type | Default | Summary |
|---|---|---|---|
timeout_ms | integer | 30000 | Maximum time the gateway waits for the client's roots-list response. Default 30 000. |
McpSamplingConfig
mcp.sampling: — gateway behavior for server-initiated sampling (LLM completion) requests forwarded to the client.
| Field | Type | Default | Summary |
|---|---|---|---|
timeout_ms | integer | 60000 | Maximum time the gateway waits for the client's sampling response. Default 60 000. |
MetricsConfig
observability.metrics: — the metrics signal.
Gateway internals (every metrics::counter!() / gauge!() / histogram!()) flow through the configured sink list. The canonical Prometheus exporter is a plugin: operators wire kind: dev.mcpg.observability.prometheus. The sinks: [] list otherwise carries plugin ids (dev.acme.observability.datadog, etc.) — there are no built-in factory kinds for metrics.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | true | Master enable for the metrics signal. When false, no metric recorders are installed. |
sinks | array<SinkConfig> | (see type) | Sink fan-out. Every entry's kind: is a plugin id (there is no kind: prometheus / kind: otlp shorthand). Default: one dev.mcpg.observability.prometheus sink at /metrics. |
NamingConfig
Prefixes applied to imported capability names / URIs.
| Field | Type | Default | Summary |
|---|---|---|---|
prompt_prefix | string (optional) | Phase 2. | |
resource_uri_prefix | string (optional) | Phase 2. | |
tool_prefix | string (optional) | Prepended to every imported tool name (e.g. "notion."). |
NotificationFilterConfig
Scoping filter for resource change notifications. Determines which subscribers receive notifications/resources/updated when the watch engine detects a change.
Variants:
-
(unnamed variant)— Fan-out to all subscribers (default, no filter). -
(unnamed variant)— Only notify subscribers whoseprincipal_idmatches the event's user context. -
(unnamed variant)— Only notify the originating session. -
(unnamed variant)— CEL expression evaluated per subscriber. Variables:subscriber.principal_id,subscriber.trust_level,subscriber.roles,subscriber.groups,subscriber.scopes,subscriber.attributes,event.uri.expression: stringscope: string
OAuthResourceMetadataConfig
Configuration for the OAuth Protected Resource Metadata endpoint (RFC 9728).
| Field | Type | Default | Summary |
|---|---|---|---|
authorization_servers | array<string> | [] | Authorization server URLs. If empty, derived from OIDC provider issuers. |
bearer_methods_supported | array<string> | (see type) | Bearer token presentation methods. Defaults to ["header"]. |
resource | string | The protected resource identifier (URL). Required. | |
scopes_supported | array<string> | [] | Scopes supported by this resource. |
ObservabilityConfig
Top-level observability: block — the OpenTelemetry signal triad (logs / metrics / traces) plus audit fan-out.
Each signal carries a sinks: [...] list of [SinkConfig] entries. Each entry's kind: field dispatches to either a built-in sink factory (stderr / stdout / file / otlp / prometheus) or a plugin id resolved against the gateway's plugin registry at boot.
Master switch. enabled: false (default true) silences every child regardless of their own enabled: flags — useful for embedded use cases where the host process owns observability or for minimal-footprint test runs. Each child also has its own enabled: for finer-grained control. The accessor helpers below (is_logs_on(), is_metrics_on(), is_traces_on(), is_audit_on()) implement the AND-fold so call sites can't forget either flag.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | true | Master kill switch. When false, every child is treated as disabled regardless of its own enabled: field — no logs emitted, no metrics endpoint registered, no traces pipeline started, no audit fan-out wired. Default true. |
logs | LogsConfig | (see type) | Logs signal — gateway internals + plugin-emitted log events fanned to the configured sink list. |
metrics | MetricsConfig | (see type) | Metrics signal — gateway internals + plugin-emitted metric events fanned to the configured sink list. |
plugin_call_sampling_rate | number (optional) | Per-call span sampling rate for native-plugin host-side spans (RFC 0018). Range [0.0, 1.0]; None inherits the global subscriber sampler (no extra dampening). | |
plugin_health_probe | HealthProbeConfig | (see type) | Plugin health probe. Lives under observability: because the probe is observability-shaped (it watches plugin liveness and writes PluginState::Degraded for monitoring consumers). |
traces | TracesConfig | (see type) | Traces signal — span lifecycle events fanned to the configured sink list. |
OidcOAuthConfig
| Field | Type | Default | Summary |
|---|---|---|---|
providers | array<OidcProviderConfig> | One or more identity providers. At least one is required. | |
token_source | TokenSourceConfig | (see type) | How to extract the bearer token from the request. |
OidcProviderConfig
| Field | Type | Default | Summary |
|---|---|---|---|
allow_private_issuer | boolean | false | Dev escape hatch: permit private/loopback ranges in OIDC URLs. Production MUST leave this false. |
allowed_issuer_hosts | array<string> | [] | Optional hostname allowlist for OIDC discovery and JWKS fetches. Empty means only the private-range blocklist applies. |
audiences | array<string> | [] | |
claim_mappings | ClaimMappingConfig | (see type) | |
clock_skew_secs | integer | 60 | |
discovery_uri | string (optional) | ||
issuer | string | ||
verification | VerificationConfig |
PipelineElicitationMode
Elicitation mode per MCP 2025-11-25. form collects a schema-driven response; url redirects the client to a URL and correlates the completion via notifications/elicitation/complete.
Allowed values:
formurl
PipelineSqlTxNestedStep
One SQL statement inside a sql_tx container. Mirrors the shape of a standalone binding's query block but scoped to the container's transaction.
| Field | Type | Default | Summary |
|---|---|---|---|
id | string | ||
input_transform | string (optional) | ||
params | array<string> | [] | Declared parameter names, in bind order if the statement uses positional placeholders. |
row_mode | string | "affected_rows" | Row-shape mode for this statement. Defaults to affected_rows since sql_tx steps are write-heavy in practice (INSERT / UPDATE / DELETE). |
sql | string | SQL body — either a literal string or sql_file path, following the same shape as standalone binding queries. |
PipelineStepConfig
Variants:
-
(unnamed variant)expected_status_codes: array<integer>headers: map<string, string>id: stringinput_transform: string (optional)kind: stringmax_response_bytes: integermethod:HttpBackendMethodrequire_json_response: booleantimeout_ms: integerurl: string
-
(unnamed variant)args: array<string>command: stringid: stringinput_transform: string (optional)kind: stringmax_output_bytes: integerrequire_json_stdout: booleantimeout_ms: integer
-
(unnamed variant)credentials_path: string (optional)id: stringinput_transform: string (optional)kind: stringmax_response_bytes: integersubject: stringtimeout_ms: integerurl: string
-
(unnamed variant)bootstrap_servers: stringgroup_id: stringid: stringinput_transform: string (optional)kind: stringmax_response_bytes: integerrequest_topic: stringresponse_topic: stringtimeout_ms: integer
-
(unnamed variant)headers: map<string, string>id: stringinput_transform: string (optional)kind: stringmax_response_bytes: integermethod: stringservice: stringtimeout_ms: integerurl: string
-
(unnamed variant)headers: map<string, string>id: stringinput_transform: string (optional)kind: stringmax_response_bytes: integeroperation: stringtimeout_ms: integerurl: string
-
(unnamed variant)delay_ms: integererror: booleanerror_message: string (optional)id: stringkind: stringpassthrough: booleanresponse: any
-
(unnamed variant)expression: stringid: stringkind: string
-
(unnamed variant)— Reshape the pipeline context by invoking a namedtransformplugin (RFC 0020). Generic bridge — works with any transform plugin; the first user isdev.mcpg.transform.jsonata. The plugin receives the full pipeline context (steps,arguments,context,tool_name) and itsconfig(e.g. a JSONataexpression); its output is the step result.config: anyid: stringkind: stringplugin: string
-
(unnamed variant)error_message: string (optional)expression: stringid: stringkind: string
-
(unnamed variant)correlation_token: string (optional)elicitation_id: string (optional)id: stringkind: stringmessage: stringmeta: anymode:PipelineElicitationModepresentation_hint: string (optional)requested_schema: anyskip_if_unsupported: booleantimeout_ms: integerurl: string (optional)
-
(unnamed variant)correlation_token: string (optional)id: stringinclude_context:SamplingIncludeContext(optional)kind: stringmax_tokens: integermessages: array<SamplingMessageConfig>meta: anymetadata: anymodel_preferences: anyskip_if_unsupported: booleanstop_sequences: array<string> (optional)system_prompt: string (optional)temperature: number (optional)timeout_ms: integertool_choice: anytools: array<any> (optional)
-
(unnamed variant)— Pipeline step that sendsroots/listto the client and suspends until the client responds with its root URIs. The result is stored in the pipeline context assteps.<id>.output.roots.correlation_token: string (optional)id: stringkind: stringskip_if_unsupported: booleantimeout_ms: integer
-
(unnamed variant)— SEP-2322 multi-entry MRTR. Emits several server-to-client input requests (elicitation / sampling / roots) in ONE suspension and resumes once the client answers them together. Distinct from listing the individual suspending steps in sequence (which suspends/resumes one at a time).id: stringinputs: array<GatherInputConfig>kind: string
-
(unnamed variant)— Emit anotifications/messageon the session's SSE channel. Non-suspending — pipeline continues immediately.data: anyid: stringkind: stringlevel: stringlogger: string (optional)
-
(unnamed variant)— Emit anotifications/progresson the session's SSE channel. Non-suspending. Skipped (silently) when the inbound request didn't include aprogressToken.id: stringkind: stringmessage: string (optional)progress: numbertotal: number (optional)
-
(unnamed variant)— Nested SQL container with transactional semantics. Each inner step runs against a pinned connection; any error rolls the whole group back.backend: stringid: stringinput_transform: string (optional)kind: stringsteps: array<PipelineSqlTxNestedStep>
-
(unnamed variant)— Fire-and-wait step. References an existing SQL binding whose profile declares[bindings.sql.await]. The plugin's inline await runtime is invoked: trigger query → poll-loop the check query → CEL predicate evaluation → matched row or timeout. Same machinery as the standalone SQL await binding, exposed for pipeline composability.backend: stringid: stringinput_transform: string (optional)kind: string
PipelinesConfig
pipelines: config — pipeline state store + per-capability store: override. When store is unset, the pipeline KV inherits from the cluster's key_value_store() primitive.
| Field | Type | Default | Summary |
|---|---|---|---|
store | StoreOverrideConfig (optional) |
PluginEntryConfig
Configuration for a single plugin entry.
| Field | Type | Default | Summary |
|---|---|---|---|
class | string | "tool_gate" | Plugin class — the snake_case PluginClass variant the plugin implements. Must match the class: field in the plugin's own plugin.yaml manifest. Determines which plugin chain / slot the plugin is registered into. Valid values: tool_gate, transform, identity_provider, backend, watch_strategy, http_route, audit_sink, store, cache, telemetry_sink, log_sink, metrics_sink, secret_provider, config_provider, transport, policy_engine, cluster, catalog_provider, credential_issuer, approval_notifier, content_store. |
config | any | Plugin-specific configuration passed to the plugin instance. | |
disabled | boolean | false | When true, the plugin entry is parsed + validated but not loaded at boot. Useful for keeping a plugin's config in source control while temporarily turning it off without removing the entry. Default false. |
enforce | boolean | true | When false, the plugin runs in shadow mode: evaluate and log, but override Deny/Challenge → Allow. Defaults to true (enforce). |
ffi_limits | PluginFfiLimitsConfig (optional) | Per-plugin FFI hardening overrides for native cdylib plugins (RFC 0018). None = inherit the spec defaults (1s lifecycle / 5s control / 30s data / 256 KiB payload). Ignored for Wasm plugins (those use limits.timeout_ms). | |
granted_capabilities | array<any> | Per-plugin typed host capability grants (RFC 0018). Each entry is one of [mcpg_plugin_protocol::capability::Capability]'s known variants. Two equivalent YAML shapes accepted: | |
http_route | PluginHttpRouteConfig (optional) | http_route-specific operator tuning. Ignored for non-http_route plugins. Absent = all defaults (enabled, namespaced mount, spec's own body cap + identity policy). | |
id | string | Operator alias for this entry — unique within the gateway's plugins[] array. Used as the registry key, audit attribution, and per-plugin observability target. When ref is omitted, the alias doubles as the artifact's manifest id (the simple, pre-v25 single-instance case). When ref is set, the alias is a separate operator-chosen label (multi-instance pattern; see RFC 0018 §6.1). | |
inline_dispatch | boolean | false | Inline fast-slot dispatch (ABI v38). When true, this plugin's Tier-1 slots are called via the typed/borrowed *_fast vtable path inline — without the spawn_blocking ferry or per-call timeout — cutting hot-path dispatch ~33× on ferried slots (tool_gate). This is an explicit operator-trust decision: the plugin's slots MUST be fast, non-blocking, and bounded, because a hung/blocking slot now wedges a runtime worker with no backstop. Defaults to false (the safe, ferried path). Only enable for trusted, pure-compute first-party plugins. See docs/plugin-protocol/fast-slot-rollout.md. |
integrity | PluginIntegrityConfig (optional) | Integrity verification for the plugin artifact. | |
kind | string | "native" | Plugin tier: "native" or "wasm". |
limits | PluginResourceLimitsConfig (optional) | Resource limits for Wasm plugins (ignored for native). | |
observability | PluginObservabilityToggle (optional) | Per-plugin observability triad override. inherit (default), replace, or tee semantics for each signal independently. Absent = all signals inherit the global observability.{logs,metrics,traces} config. Routing is keyed by module_path_prefix from the plugin manifest — events from this plugin's crate get the override; events from gateway code about a plugin call stay on the global path. | |
ref | string (optional) | Manifest id (artifact identity) — reverse-DNS, e.g. dev.mcpg.policy.cedar. Optional; defaults to id when absent. | |
signature | SignatureConfig (optional) | Plugin signature checks. Consolidates the content hash (was integrity.sha256), the per-plugin verification policy (was plugins.registry.signature_verification — now per-entry overridable), and the trusted Ed25519 keys this plugin's artifact must verify against (was plugins.trust.roots — now per-entry, no global trust pool). | |
source | PluginSourceConfig | (see type) | Source path or reference for the plugin artifact. |
PluginFfiLimitsConfig
Per-plugin FFI hardening overrides for native cdylib plugins (RFC 0018).
Native plugin calls are wrapped by the host in spawn_blocking + tokio::time::timeout and bounded RString returns. Defaults are the spec-level constants in mcpg_plugin_protocol::abi (FFI_{LIFECYCLE,CONTROL,DATA}_TIMEOUT_DEFAULT_MS, FFI_MAX_PAYLOAD_BYTES). Operators set per-plugin overrides here to widen the budget for a known-slow plugin (e.g. a backend that proxies an upstream multi-second API) or to tighten the cap on a plugin that has a stricter SLO.
None on any field means "inherit the spec default".
| Field | Type | Default | Summary |
|---|---|---|---|
control_timeout_ms | integer (optional) | Control slot timeout override (ms). Applies to config-set, snapshot, version, register-profile, refresh, describe, list-peers, list-catalog, etc. Default: FFI_CONTROL_TIMEOUT_DEFAULT_MS = 5_000. | |
data_timeout_ms | integer (optional) | Data slot timeout override (ms). Applies to execute, evaluate, transform, dispatch, http_route, sink-emit, etc. Default: FFI_DATA_TIMEOUT_DEFAULT_MS = 30_000. | |
lifecycle_timeout_ms | integer (optional) | Lifecycle slot timeout override (ms). Applies to make, manifest, shutdown, drop_instance, health probes. Default: FFI_LIFECYCLE_TIMEOUT_DEFAULT_MS = 1_000. | |
max_payload_bytes | integer (optional) | Max byte-length of any single RString returned by this plugin to the host. Overflow rejected with a slot-appropriate fallback + bumps mcpg_plugin_payload_oversize_total. Default: FFI_MAX_PAYLOAD_BYTES = 262144 (256 KiB). |
PluginHttpRouteConfig
Operator-side tuning for an http_route plugin entry. Every field is optional; the struct is omitted entirely for plugins that don't need any override.
| Field | Type | Default | Summary |
|---|---|---|---|
allow_path_override | boolean | false | When true, plugin routes mount at the top-level paths the plugin declared (override mode). Requires the plugin to declare cap.host.http_route_override AND the operator to grant it; missing either causes a startup refuse. Default false keeps the plugin on the namespaced /plugins/{id}/{entity}/ mount. Override-mode dispatch is not yet wired — this field is the gate the dispatcher will consult once that support lands. |
disabled | boolean | false | When true, the plugin is not registered at all. Operators use this to swap out a gateway built-in (e.g. the built-in dev.mcpg.builtin.http.status) for a custom implementation without patching the gateway. The gateway logs a warning if a disabled plugin also appears elsewhere in the plugins list with conflicting settings — disable is authoritative. |
max_body_bytes | integer (optional) | Per-entity override for RouteSpec.max_body_bytes. When set, the dispatcher uses this value instead of the plugin's declared cap — operator tightens (or relaxes) the plugin's spec without a plugin rebuild. None = use the plugin's declared value. | |
requires_identity | boolean (optional) | Per-entity override for RouteSpec.requires_identity. When set, the dispatcher enforces this instead of the plugin's declared value. Typical use: operator tightens an endpoint the plugin declared anonymous. None = use the plugin's declared value. |
PluginIntegrityConfig
Plugin artifact integrity verification.
| Field | Type | Default | Summary |
|---|---|---|---|
sha256 | string (optional) | Expected SHA-256 hex digest of the plugin artifact. |
PluginObservabilityToggle
Per-plugin observability toggle. Each signal is independent — operators can disable metrics for one plugin while leaving its logs and traces flowing. Events still route through the GLOBAL observability.{logs,metrics,traces}.sinks list when admitted; this struct only controls whether a plugin's events make it that far + at what level.
| Field | Type | Default | Summary |
|---|---|---|---|
logs | SignalToggle (optional) | Logs toggle. None = inherit globals. | |
metrics | SignalToggle (optional) | Metrics toggle. None = inherit globals. Note: metrics has no level (metrics-rs has no levels) — the field is accepted in YAML for forward compat but ignored today. | |
traces | SignalToggle (optional) | Traces toggle. None = inherit globals. |
PluginRegistryAuthConfig
Registry authentication configuration. At most one source of credentials is consulted at push/pull time: an explicit username+password pair (or env-interpolated variants), otherwise the docker config.json at docker_config_path, otherwise anonymous.
| Field | Type | Default | Summary |
|---|---|---|---|
docker_config_path | string (optional) | Path to a docker config.json for credential helpers. Defaults to ~/.docker/config.json when unset. | |
password | string (optional) | Literal password / bearer token (or $VAR / env:VAR). Wrapped in [mcpg_sensitive::Sensitive] so a stray ?config log renders this field as *** instead of the literal token. | |
username | string (optional) | Literal username (or $VAR / env:VAR for env-var interpolation). |
PluginRegistryConfig
Configuration for resolving plugin artifacts from OCI registries. Covers default registry, local cache, auth, TLS, and signature policy per docs/rfcs-archive/mcpg/mcp_gateway_oci_plugin_registry_rfc.md.
This section is only consulted when at least one plugin entry has source.oci set. For purely local deployments (every plugin loaded from source.path), all defaults apply and the registry subsystem does nothing.
| Field | Type | Default | Summary |
|---|---|---|---|
auth | PluginRegistryAuthConfig | (see type) | Registry authentication strategy. |
cache_dir | string (optional) | Local cache directory for pulled OCI artefacts. Keyed by manifest digest so digest-pinned references skip the network on subsequent boots. When unset, defaults to $XDG_CACHE_HOME/mcpg/plugins/oci (or /var/cache/mcpg/plugins/oci for system deployments). | |
default_registry | string | "ghcr.io/mcpg-dev/source-code/plugins" | Default registry when an oci: reference has no registry prefix. Example: ghcr.io/mcpg-dev/source-code/plugins. |
default_signature_policy | SignaturePolicy | "warn" | Default signature verification policy applied to every plugins[*] entry that doesn't carry its own signature.policy: override. Defaults to Warn (log but don't fail) for first-rollout safety; flip to Enforce once trusted keys are wired up across all entries. |
insecure_registries | array<string> | [] | Hostnames (optionally host:port) that the OCI client should reach over plain HTTP instead of HTTPS. localhost, 127.0.0.1, and ::1 are always implicit — operators only need to list this for other dev / air-gap registries. |
mirrors | array<PluginRegistryMirrorConfig> | [] | Mirror registries tried in order before the reference's source registry. Supports air-gap / pull-through caches. |
revocation_list_path | string (optional) | Optional path to a JSON revocation list. When set, the gateway loads the file at startup, indexes the revoked artefact SHA-256s, and refuses to load any plugin whose hash matches an entry — even if its Ed25519 signature is valid. Format documented in [mcpg_plugin_host::revocation::RevocationListFile]. Absent means "no revocation list" — every signed plugin is allowed. | |
tls | PluginRegistryTlsConfig | (see type) | TLS knobs for registry connections. |
PluginRegistryMirrorConfig
A mirror registry entry. Mirrors are consulted in order before the reference's source registry, matching the common pull-through cache / air-gap deployment pattern.
| Field | Type | Default | Summary |
|---|---|---|---|
auth | PluginRegistryAuthConfig (optional) | Optional auth override for this mirror. When absent, inherits the top-level plugin_registry.auth. | |
url | string | Mirror URL — a prefix that replaces the source registry in resolved pull URLs. Example: harbor.internal.corp/mcpg-plugins. |
PluginRegistryTlsConfig
TLS configuration for registry HTTPS connections.
| Field | Type | Default | Summary |
|---|---|---|---|
ca_cert | string (optional) | Path to a PEM bundle with extra trusted root CAs. Useful for internal registries with private CAs. | |
insecure | boolean | false | Skip all TLS certificate verification. DANGEROUS — development-only escape hatch, emits a WARN at boot. |
PluginResourceLimitsConfig
Resource limits for Wasm plugins.
These limits constrain the sandbox resources available to a Wasm plugin. If not specified, system defaults are used (64 MiB memory, 10M fuel, 100ms timeout).
| Field | Type | Default | Summary |
|---|---|---|---|
fuel | integer (optional) | Maximum fuel (instruction budget) per invocation (default: 10_000_000). | |
memory_mb | integer (optional) | Maximum linear memory in megabytes (default: 64). | |
timeout_ms | integer (optional) | Wall-clock timeout per invocation in milliseconds (default: 100). |
PluginSourceConfig
Plugin artifact source configuration.
Exactly one of path / oci must be set. Both unset is invalid; both set is invalid. The source type determines how the gateway resolves the artifact at boot time.
| Field | Type | Default | Summary |
|---|---|---|---|
oci | string (optional) | OCI reference (e.g. ghcr.io/mcpg-dev/plugins/audit:1.0.0 or plugins/audit@sha256:…). At boot the gateway pulls the artifact, verifies the manifest digest, caches it to plugin_registry.cache_dir, and loads it through the same sidecar / packaged-zip path path would have taken. When the reference is missing a registry prefix, the plugin_registry.default_registry value is prepended. | |
path | string (optional) | Path to the plugin artifact on the local filesystem. Accepts a raw .so / .wasm (with a sidecar plugin.yaml) or a packaged .zip. |
PolicyCacheConfig
Configuration for the policy decision cache (L1 process-local).
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | false | |
max_entries | integer | 10000 | |
ttl_ms | integer | 60000 |
PolicyConfig
| Field | Type | Default | Summary |
|---|---|---|---|
cache | PolicyCacheConfig | (see type) | |
engine | array<KindRef> | Ordered chain of policy engines consulted at every decision point (tool.call.pre, plugin.lifecycle.register, etc.). Each entry is a [KindRef] — kind: resolves to a built-in keyword (yaml-rules), a short alias (cedar, opa, casbin → dev.mcpg.policy.<alias>), or a full reverse-domain plugin id. Chain semantics: the host walks the list in order, short-circuiting on the first Allow / Deny; NotApplicable falls through to the next engine. An empty chain is equivalent to NotApplicable everywhere — callers (e.g. enforce_plugin_registration_policy) decide whether that means "allow" (default-allow gateway) or "fail-closed" per their own policy posture. | |
tool_access | ToolAccessPolicyConfig | (see type) |
PromptArgumentConfig
| Field | Type | Default | Summary |
|---|---|---|---|
completions | array<string> (optional) | ||
description | string (optional) | ||
name | string | ||
required | boolean | false |
QuotasConfig
governance.quotas: registry.
Three named-policy lists (rate_limits / budgets / concurrency) plus the storage backend that holds the runtime counters. Bindings opt into specific policies by id via their own per-binding quotas: block.
| Field | Type | Default | Summary |
|---|---|---|---|
budgets | array<BudgetPolicy> | Named cost / call-count / token-count budgets. Bindings reference by id. | |
concurrency | array<ConcurrencyPolicy> | Named concurrency caps. Bindings reference by id. | |
rate_limits | array<RateLimitPolicy> | Named rate-limit policies. Bindings reference by id. | |
store | KindRef | (see type) | Storage backend for quota counters / token-buckets / in-flight concurrency. Uses the standard KindRef discriminator. kind: cluster (default) routes through the cluster coordinator's KV role; kind: memory resets on restart (dev-only); kind: <plugin-id> pins to a loaded KV plugin. |
RateLimitPolicy
One named rate-limit policy.
| Field | Type | Default | Summary |
|---|---|---|---|
burst | integer (optional) | Bucket burst capacity — number of calls a caller can spend in quick succession before refill rate kicks in. Defaults to the per-second equivalent of rate (i.e., one second's worth). | |
id | string | Operator-chosen id. Bindings reference this via tools[].quotas.rate_limit: <id>. | |
identity_claim | string (optional) | JWT claim path used to key the bucket when scope: per_identity. Required for that scope; rejected for others. Common values: sub, org_id, email. | |
kind | string | "token_bucket" | Algorithm. v1.0 ships token_bucket only; leaky_bucket + sliding_window are open questions per the RFC. |
on_exceeded | string | "deny" | Action when the bucket runs dry. deny returns a 429-style error; queue is reserved (RFC q3 — currently aliases to deny for rate limits); shed_load drops silently. |
rate | RateLimitRate | Refill rate. Today only calls_per_minute is supported; future variants will land here. | |
scope | string | "per_identity" | Scope discriminator: how the bucket is keyed. per_identity keys by the JWT claim path in identity_claim; global shares one bucket across all callers; per_session, per_tool are also valid. |
RateLimitRate
| Field | Type | Default | Summary |
|---|---|---|---|
calls_per_minute | integer | Calls allowed per minute. Bucket refills at this rate. |
RequestStateConfig
request_state: config — the MRTR requestState codec used by the modern wire's suspending tools/call arm to encrypt pipeline-resumption blobs.
Inert until a modern client connects. Lives under mcp.configurations because the codec manages runtime-emergent resumption state alongside sessions / pipelines / subscriptions / delivery / cancellation / idempotency — operator tunes the encryption key, the runtime mints + serves the rest.
yaml mcp: configurations: request_state: # 32-byte ChaCha20-Poly1305 key, base64-encoded. # Generate via: head -c 32 /dev/urandom | base64 encryption_key: "<base64-32-byte-secret>"
Absent the key the gateway mints an ephemeral one at boot (with a WARN log) — pending resumptions issued before a gateway restart become undecodable after restart.
| Field | Type | Default | Summary |
|---|---|---|---|
encryption_key | string (optional) | Base64-encoded 32-byte ChaCha20-Poly1305 secret. None ⇒ ephemeral key (random per process; resumptions lost on restart). |
ResourceWatchConfig
Per-binding resource watch configuration. Defines how changes to a resource are detected for notifications/resources/updated.
| Field | Type | Default | Summary |
|---|---|---|---|
notification_filter | NotificationFilterConfig (optional) | Notification filter — controls which subscribers receive the notifications/resources/updated message when a change is detected. Defaults to fan-out to all subscribers when absent. | |
strategy | WatchStrategyConfig | (see type) | Strategy for detecting resource changes. |
ResponseCacheConfig
Operator-facing config for the gateway-managed LLM response cache. The cache backs BackendHost::cache_get / cache_put; chat + embedding bindings opt in per-binding via their own cache.enabled: true knob, the cache only exists at all if this config is non-disabled.
kind: in_process is the default — content-addressed BLAKE3 LRU cache with 64 MiB byte cap, lost on restart. kind: disabled turns the cache off gateway-wide; per-binding cache.enabled becomes a no-op.
Variants:
-
(unnamed variant)kind: stringmax_bytes: integer
-
(unnamed variant)
ResponseConfig
Per-call response limits.
| Field | Type | Default | Summary |
|---|---|---|---|
max_response_bytes | integer | 2097152 | Cap on a single upstream call's response, enforced gateway-side (RFC v1 §10.3). |
RetryConfig
Per-binding retry configuration. Only applies to HTTP, gRPC, GraphQL, NATS, and Kafka bindings.
| Field | Type | Default | Summary |
|---|---|---|---|
initial_backoff_ms | integer | 200 | Initial backoff delay in milliseconds. Doubled on each subsequent retry. |
max_attempts | integer | 3 | Maximum number of retry attempts (not counting the initial attempt). |
retry_on_status_codes | array<integer> | (see type) | HTTP status codes that trigger a retry (only applicable to HTTP/gRPC/GraphQL bindings). |
retry_on_transport_error | boolean | true | Whether to retry on transport/connection errors. |
SamplingIncludeContext
Sampling context-inclusion hint. MCP defines exactly three variants; any other value on the wire fails deserialization so a misspelled config cannot silently degrade to the default.
Controls which MCP server context the client should include when fulfilling a sampling/createMessage request. Serialized as camelCase on the wire ("none", "thisServer", "allServers").
Allowed values:
nonethisServerallServers
SamplingMessageConfig
| Field | Type | Default | Summary |
|---|---|---|---|
content | string | ||
role | string |
SchemaEntry
A named schema entry in the registry. Exactly one source must be provided.
| Field | Type | Default | Summary |
|---|---|---|---|
file | string (optional) | Path to a local JSON Schema file (relative to the config file). | |
inline | any | Inline JSON Schema definition. | |
url | string (optional) | URL to fetch the JSON Schema from at startup. |
ServerConfig
| Field | Type | Default | Summary |
|---|---|---|---|
allow_private_backends | boolean | false | Allow outbound connections to private/loopback/link-local IPs. Default false enables the DNS rebinding guard. Set true for container-network deployments where backends live on RFC 1918. |
allowed_origins | array<string> | [] | |
bind_address | string | "127.0.0.1:8787" | |
completion_rate_limit_per_sec | integer (optional) | Per-session rate limit on completion/complete requests (cap per second). None disables. Guards against broken autocomplete UIs. | |
extra_resource_uri_schemes | array<string> | [] | Extra resource-URI schemes (beyond the built-in allow-list) treated as first-class by the resource normalizer. Matched case-insensitively. |
health_check | HealthCheckConfig | (see type) | Periodic prober for every binding's backend (SQL server reachability, gRPC endpoint, REST upstream, ...). Distinct from health_path: above — that's the gateway's own liveness endpoint for load balancers; this prober actively pings each binding's underlying service and updates PluginState::{Active, Degraded} based on results. |
health_path | string | "/health" | |
max_request_body_mb | integer | 4 | Maximum POST body accepted on the MCP endpoint, in MiB. Defaults to 4 MiB. 0 falls back to the default — an unbounded body is never acceptable on a public endpoint. |
max_sessions_per_tenant | integer | 0 | Per-tenant session quota. 0 = unlimited. A "tenant" is the resolved principal id; anonymous callers share an anonymous bucket. The stricter of this and the global cap wins. |
mcp_path | string | "/mcp" | |
replay_window_limit | integer | 16 | |
request_timeout_ms | integer | 30000 | |
server_ping_interval_ms | integer (optional) | Emit a server-initiated ping to each active session's SSE stream on this cadence. None or 0 disables. Reasonable value: 30s. | |
session_idle_timeout_ms | integer | 900000 | |
shutdown_timeout_ms | integer | 30000 | |
tls | TlsConfig (optional) | ||
transport | TransportMode | "http" | |
transports | array<KindRef> | Additional plugin-supplied transports started at boot alongside the primary HTTP / stdio listener (which continues to be governed by transport: and bind_address:). Each entry is a [KindRef] — kind: resolves to either a built-in transport keyword (today only dev.mcpg.builtin.transport.memory is wired; builtin-http / builtin-stdio map to the in-tree HTTP / stdio paths and don't need a list entry) or a registered Transport plugin id. The plugin's Transport::start(config, dispatcher) runs once per list entry; transports that fail to start halt the boot. Empty list = no extra transports beyond the primary listener — today's default. |
SessionConfig
Upstream-session behaviour.
| Field | Type | Default | Summary |
|---|---|---|---|
idle_timeout_secs | integer | 600 | |
mode | SessionMode | "per_client" |
SessionMode
Upstream-session allocation strategy.
Variants:
-
per_client— One satellite session per MCPG client session (Phase 1; D5). -
shared— One shared upstream session for all clients. Not yet supported.
SessionsConfig
sessions: config — session lifecycle store + per-capability store: override. When store is unset, the session KV inherits from the cluster's key_value_store() primitive; when set, the override pins to an in-process backend (memory / file).
| Field | Type | Default | Summary |
|---|---|---|---|
store | StoreOverrideConfig (optional) |
SignalToggle
Per-plugin per-signal toggle. Four knobs:
enabled(defaulttrue): whenfalse, every event from this plugin's crate is dropped at the bridge before it reaches the sink fan-out — the "silence this noisy plugin" pattern. -level(logs / traces only): minimum severity an event must clear to be emitted. Composed into the bridge layer's permissive filter so per-plugin verbosity boosts AND suppressions both work. Accepted:trace/debug/info/warn/error(case-insensitive). -mode(defaultinherit): how to route events that pass the gate.inheritflows through the global sink list (the default behaviour).replaceroutes ONLY to the plugins listed undersinks— used for compliance carve-outs ("audit logs go to my SIEM, never to stdout").teefans out to BOTH the global sink list AND the per-pluginsinks. -sinks: plugin ids of the sink plugins to use undermode: replace | tee. Each id MUST match a registered sink plugin for the corresponding signal — log sink forlogs.sinks, metrics sink formetrics.sinks, span sink fortraces.sinks. If any id is unknown to the matching signal, the gateway refuses to boot (validated post-registration inapp::validate_per_plugin_sink_ids). Listing a real log sink id undermetrics.sinksis rejected — sink-kind crossover is a typo, not a feature.
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | true | |
level | string (optional) | ||
mode | SinkMode | ||
sinks | array<string> |
SignatureConfig
Per-plugin signature configuration.
Consolidates three signature concerns into one per-plugin block: - The content-hash pin (was integrity.sha256). - The verification policy — per-plugin overridable, with the global default in gateway.plugin_registry.default_signature_policy:. - The Ed25519 trusted keys this artifact must verify against — per-plugin so plugins from different vendors can carry different keys without pooling them in one trust anchor.
| Field | Type | Default | Summary |
|---|---|---|---|
policy | SignaturePolicy (optional) | Verification policy for this plugin. None = inherit gateway.plugin_registry.default_signature_policy:. | |
sha256 | string (optional) | SHA-256 content hash to pin (hex-encoded). When set, the gateway refuses to load the artifact if its computed hash doesn't match. Equivalent to the legacy integrity.sha256. | |
trusted_keys | array<TrustedKeyConfig> | Ed25519 verification keys this artifact's signature must verify against. Empty = inherit gateway-wide defaults (currently fall back to the deleted plugins.trust: block, removed once consumers fully migrate to per-plugin). |
SignaturePolicy
Signature verification policy for native plugin artefacts. The Ed25519 signature attached to the artefact (<artifact>.sig or the packaged plugin.sig) is the primary check; this policy governs behaviour when the signature is missing or invalid. Set per-plugin via plugins[*].signature.policy:, or as a gateway-wide default via gateway.plugin_registry.default_signature_policy:.
Variants:
-
disabled— Signature checks are skipped entirely. Development only; gateway emits agovernance.plugin.signature_policy_disabledaudit event for any entry that resolves to this policy so the choice is visible in the compliance trail. -
warn— Log a warning for missing or invalid signatures but proceed with the load. Default — safe for first rollout. -
enforce— Refuse to load any artefact whose signature is missing or does not verify against the configured trusted keys. Recommended for production.
SinkConfig
One sink in an observability signal's sinks: [...] list. The kind: field dispatches to a built-in factory (stderr, stdout, file, otlp, prometheus) or to a plugin id (any other value is looked up in the plugin registry at boot).
config: is the sink-kind-specific config object. Built-in kinds validate their own config: shape at boot; for plugin sinks, the plugin's own config schema applies.
level: is an optional per-sink severity floor. When None, the sink inherits the signal's level:. Useful for stderr: warn, file: debug setups where the console is quiet but a file captures everything. Per-sink level overrides are parsed but not yet enforced; today signal-level level: is the only enforced floor.
| Field | Type | Default | Summary |
|---|---|---|---|
config | any | Sink-specific config object. Schema depends on kind:. | |
kind | string | Sink kind. Built-in keywords: stderr, stdout, file, otlp, prometheus. Anything else is resolved as a plugin id at boot. | |
level | string (optional) | Per-sink severity floor. None = inherit signal-level level:. |
SinkMode
How to route events for a per-plugin signal toggle. Operator schema: mode: inherit | replace | tee.
Variants:
-
inherit— Inherit the global sink list — the same routing every other plugin's events use. Default. -
replace— Route admitted events ONLY to the per-pluginsinkslist. Skips the global sink fan-out entirely. Used for compliance carve-outs (audit logs stay inside the SIEM). -
tee— Tee — admitted events flow to BOTH the global sink list AND the per-pluginsinkslist. Useful when an operator wants to keep default routing but additionally mirror a noisy plugin's events to a debugging sink.
StorageConfig
Top-level storage: block. Holds the gateway's content-store providers + the LLM response cache.
| Field | Type | Default | Summary |
|---|---|---|---|
default | string (optional) | Provider id that bindings without an explicit content_storage: field route to. When unset, the gateway falls back to a provider with the conventional id default. Validated at boot — an unknown id fails fast. | |
providers | array<StorageProviderConfig> | [] | Content-store provider entries. Each entry produces an Arc<dyn ContentStore> registered under id in the gateway's runtime registry. Bindings reference providers by id via their own content_storage: field. |
response_cache | ResponseCacheConfig | (see type) | Gateway-managed LLM response cache. Lives here (rather than under plugins:) so all "where bytes go to live" config shares one home. |
StorageProviderConfig
One operator-declared content-store provider, an entry in storage.providers: [...]. The kind field selects the storage plugin (in_process / file_system / s3 / future plugins); config is the per-plugin configuration object whose schema is owned by the plugin (see each plugin's plugin.yaml).
| Field | Type | Default | Summary |
|---|---|---|---|
config | any | Plugin-specific configuration JSON. Validated by the plugin at build_profile time; gateway boot fails fast if the shape doesn't match. | |
id | string | Operator-chosen id. Bindings reference providers via this id (content_storage: <id> on the binding entry). The conventional default id is the fallback when a binding doesn't specify its own AND storage.default is unset. | |
kind | string | Storage plugin kind (e.g. in_process, file_system, s3). Resolved against the gateway's content-store plugin registry at boot. |
StoreOverrideConfig
<capability>.store: { kind, … } — produces an Arc<dyn mcpg_cluster_api::KeyValueStore> at boot.
Recognised kind values: cluster, memory, file. (redis and nats are not accepted here — set cluster.kind: redis | nats and use kind: cluster here, or omit the override entirely.)
| Field | Type | Default | Summary |
|---|---|---|---|
kind | string |
SubscriptionsConfig
subscriptions: config (resource subscriptions) — subscription store + per-capability store: override + per-session quota. When store is unset, the subscription KV inherits from the cluster's key_value_store() primitive.
| Field | Type | Default | Summary |
|---|---|---|---|
max_per_session | integer | 100 | Maximum subscriptions per session (0 = unlimited). |
store | StoreOverrideConfig (optional) |
TaggedVariableCompletionSource
Variants:
-
(unnamed variant)— Static list of completion values. Same shape as the shorthand bare-list but with explicitkindtag.kind: stringvalues: array<string>
-
(unnamed variant)— Dynamic dispatch: at completion time, the gateway calls [crate::backends::CapabilityRegistry::complete_argument], which routes to the named backend'sBackendPlugin::complete_template_variable(binding_name, variable_name, prefix, &config). The backend returns up to 100 completions matching the prefix.backend: stringconfig: anykind: string
TasksConfig
tasks: config (MCP 2025-11-25 tasks system) — task store + per-capability store: override + retention tuning. When store is unset, the task KV inherits from the cluster's key_value_store() primitive. Tuning fields (default_ttl_ms, reaper_interval_ms, max_tasks_per_session, result_wait_ms) are orthogonal and apply to whichever backend resolves.
| Field | Type | Default | Summary |
|---|---|---|---|
default_ttl_ms | integer | 1800000 | Default TTL applied to any task created without an explicit task.ttl from the client. Used by tasks/create and the reaper. |
max_tasks_per_session | integer | 256 | Maximum concurrent tasks per session. Creation above this quota is rejected with JSON-RPC -32603 Internal error rather than silently succeeding. 0 disables the quota. |
reaper_interval_ms | integer | 60000 | Background reaper sweep interval. The reaper deletes records whose created_at + ttl has elapsed. |
result_wait_ms | integer | 30000 | Upper bound on a single tasks/result HTTP blocking wait. Clients that need longer-running tasks reconnect via GET SSE and Last-Event-Id until the task goes terminal. |
store | StoreOverrideConfig (optional) |
TlsConfig
TLS configuration for the HTTP transport.
| Field | Type | Default | Summary |
|---|---|---|---|
cert_path | string | ||
client_ca_certs_path | string (optional) | Optional path to a PEM bundle of CA certs that gate-keep client cert acceptance for mTLS. Required whenever client_cert_required is "optional" or "mandatory"; must be empty / absent when "none". | |
client_cert_required | ClientCertMode | "none" | Client cert acceptance mode for mTLS connections: |
key_path | string | ||
min_tls_version | string | "1.2" | Minimum TLS version: "1.2" or "1.3". Default "1.2". |
TokenSourceConfig
| Field | Type | Default | Summary |
|---|---|---|---|
header_name | string (optional) | ||
header_prefix | string (optional) | ||
kind | TokenSourceKind | "authorization_bearer" |
TokenSourceKind
Allowed values:
authorization_bearercustom_header
ToolAccessPolicyConfig
| Field | Type | Default | Summary |
|---|---|---|---|
cel_allow_if | string (optional) | ||
default_minimum_trust | TrustLevelConfig | "header_asserted" | |
rules | array<ToolTrustRuleConfig> | [] |
ToolTrustRuleConfig
| Field | Type | Default | Summary |
|---|---|---|---|
cel_allow_if | string (optional) | ||
minimum_trust | TrustLevelConfig | ||
tool_name | string |
TracesConfig
observability.traces: — the traces signal.
Span lifecycle events (every tracing::info_span!() / debug_span!() and every plugin-emitted span) flow through the configured sink list. The canonical sink is otlp (exports to an OpenTelemetry Collector). Default: traces disabled (operators opt in by setting enabled: true and adding sinks).
| Field | Type | Default | Summary |
|---|---|---|---|
enabled | boolean | false | Master enable for the traces signal. Default false — tracing has non-trivial overhead so operators opt in. |
propagate_context | boolean | true | Propagate W3C trace context (traceparent / tracestate) headers to outbound binding calls. Defaults to true — downstream services join the same trace. |
service_name | string | "mcpg" | Service name advertised to OTel collectors. Default "mcpg". |
sinks | array<SinkConfig> | [] | Sink fan-out. Each entry's kind: resolves to a built-in factory (otlp) or plugin id. Default: empty — operators add an otlp sink to ship to a collector. |
TransportMode
Transport mode determines whether MCPG runs as an HTTP server or a stdio JSON-RPC process.
Allowed values:
httpstdio
TrustLevelConfig
Allowed values:
unauthenticatedheader_assertedverified
TrustedKeyConfig
One trusted-key entry inside SignatureConfig.trusted_keys.
| Field | Type | Default | Summary |
|---|---|---|---|
id | string | Operator-chosen id for the key (audit-trail label). | |
pem | string | PEM-encoded public key. Multi-line literal in YAML. |
UpstreamConfig
Upstream connection details.
| Field | Type | Default | Summary |
|---|---|---|---|
args | array<string> | [] | Arguments passed to the stdio command. |
auth | AuthConfig | (see type) | How MCPG authenticates to the upstream. |
command | string (optional) | Command to spawn for the stdio transport (ignored otherwise). | |
env | map<string, string> | {} | Extra environment for the stdio command. |
transport | UpstreamTransport | "streamable_http" | Wire transport. |
upstream_safety | UpstreamSafetyConfig | (see type) | SSRF / DNS-rebinding posture (http) + local-exec posture (stdio). |
url | string | "" | Base MCP endpoint URL (the upstream's /mcp). Required for the streamable_http transport; unused (empty) for stdio. |
UpstreamSafetyConfig
SSRF / DNS-rebinding posture for the upstream URL. Mirrors the HTTP binding's guard (runtime/safe_dns.rs).
| Field | Type | Default | Summary |
|---|---|---|---|
allow_insecure_http | boolean | false | Permit http:// (non-TLS) upstreams. |
allow_private_backends | boolean | false | Permit private / loopback upstream addresses. |
allow_stdio | boolean | false | Permit the stdio transport, which spawns a local child process (arbitrary local execution — default-deny). |
UpstreamTransport
Upstream wire transport.
Variants:
-
streamable_http— MCP Streamable HTTP (POST + SSE). Phase 1. -
stdio— Local stdio child process. Phase 4. -
legacy_sse— Legacy HTTP+SSE transport. Phase 4.
VariableCompletionSource
Per-template-variable completion source.
The bare-list shorthand stays valid (post-launch shipping shape): variable_completions: { region: ["us-east-1", "us-west-2"] } is read by the BareList arm and treated as if the operator had written { kind: static, values: [...] }. The tagged form is the new shape — kind: dynamic introduces backend dispatch.
Type: array<string> | TaggedVariableCompletionSource
VerificationConfig
Variants:
-
(unnamed variant)allow_hmac: booleanallowed_algs: array<string>kind: stringmax_staleness_ms: integerrefresh_interval_secs: integertimeout_ms: integer
-
(unnamed variant)client_id: stringclient_secret_ref: stringintrospection_url: stringkind: stringtimeout_ms: integer
-
(unnamed variant)allow_hmac: booleanallowed_algs: array<string>client_id: stringclient_secret_ref: stringintrospection_timeout_ms: integerintrospection_url: stringkind: stringmax_staleness_ms: integerrefresh_interval_secs: integertimeout_ms: integer
WatchStrategyConfig
Variants:
-
poll— Poll the resource periodically and compare SHA-256 hash.interval_ms: integer
-
nats_topic— Subscribe to a NATS subject — any message means the resource changed.subject: string
-
kafka_topic— Subscribe to a Kafka topic — any message means the resource changed.group_id: stringtopic: string
-
webhook— Receive webhook POSTs from 3rd-party systems. MCPG exposes/webhooks/resource-updated/{token}and triggersnotifications/resources/updatedwhen a POST is received.token: string
-
sql_polling— SQL polling watch —dev.mcpg.watch.sql_pollingplugin runs a scalar tracking query on a cadence and emits an event when the returned scalar advances. Spec mirrors the[bindings.sql]shape (driver,url, optionalpool/session_vars, requiredqueryblock,interval_ms); see the SQL binding plugin docs for the full field list. Pass-through here keeps the spec the single source of truth in the plugin crate. -
postgres_listen_notify— Postgres LISTEN/NOTIFY watch —dev.mcpg.watch.postgres_listen_notifyplugin holds one dedicated connection per watch and re-emits NOTIFY payloads. Far lower overhead than polling for change-feed-style sources.channel: stringurl: string