Detailed Reference¶
This page is generated from
config.yaml.template. Do not edit it by hand.
What you'll learn here: the full supported config surface, rendered as a structured reference from the commented YAML template.
Use Configuration for a guided overview and the scenario pages for opinionated production profiles.
How to read this page¶
- The tables below are the generated reference view.
- The full commented YAML template is still included at the end as an appendix.
- Change
config.yaml.template, then regenerate this page.
Sections¶
| Section | Summary |
|---|---|
core | HTTP server, logging, runtime behaviour |
telemetry | OpenTelemetry export (metrics + optional logs) |
state_persistence | adapter metadata durability |
storage | shared filesystem layout and file-write behaviour |
sessions | lifecycle and concurrency limits |
uploads | multipart file staging |
artifacts | tool-produced file persistence |
servers | upstream MCP server registrations (REQUIRED, at least one entry) |
core¶
HTTP server, logging, runtime behaviour
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
host | string | optional | "0.0.0.0" | - | - | IP address the HTTP server binds to. |
port | number | optional | 8932 | 1-65535 | - | TCP port the HTTP server listens on. |
log_level | string | optional | "warning" | "debug", "info", "warning", "error", "critical" | - | Minimum log level for the adapter process. |
max_start_wait_seconds | number | optional | 60 | >= 0 | - | Maximum seconds to wait during startup for all upstream MCP servers to become reachable before the application starts accepting traffic. |
cleanup_interval_seconds | number | optional | 60 | > 0 or null | - | How often (in seconds) the background cleanup loop runs to remove expired uploads, expired artifacts, and idle sessions. |
public_base_url | null | optional | null | - | - | External base URL used when creating upload endpoint URLs that are returned to MCP clients (e.g., in server-prefixed "<server_id>_get_upload_url" tools). |
allow_artifacts_download | boolean | optional | false | - | - | When true the adapter registers: GET /artifacts/{server_id}/{session_id}/{artifact_id} This lets clients download raw artifact bytes over HTTP using an Mcp-Session-Id header for session validation. |
code_mode_enabled | boolean | optional | false | - | servers[].code_mode_enabled | When true, the server exposes FastMCP Code Mode instead of the full direct tool list. |
shorten_descriptions | boolean | optional | false | - | servers[].shorten_descriptions | When true, adapter-wrapped upload_consumer tools keep only a short semantic summary from the upstream description, then append the adapter workflow instructions. |
short_description_max_tokens | number | optional | 16 | > 0 | servers[].short_description_max_tokens | Maximum token budget used when core.shorten_descriptions=true or when a server override enables shortened descriptions. |
tool_metadata_sanitization | object | - | - | - | servers[].tool_metadata_sanitization | Apply a conservative sanitization pass to model-visible tool metadata before it reaches the client. |
tool_metadata_sanitization.mode | string | optional | "sanitize" | "off", "sanitize", "block" | - | core.tool_metadata_sanitization.mode |
tool_metadata_sanitization.normalize_unicode | boolean | optional | true | - | - | Apply Unicode NFKC normalization to model-visible metadata text. |
tool_metadata_sanitization.remove_invisible_characters | boolean | optional | true | - | - | Remove zero-width / invisible formatting characters from model-visible tool metadata text. |
tool_metadata_sanitization.max_tool_title_chars | number | optional | 256 | > 0 or null | - | Maximum forwarded length for tool titles. |
tool_metadata_sanitization.max_tool_description_chars | number | optional | 2000 | > 0 or null | - | Maximum forwarded length for top-level tool descriptions. |
tool_metadata_sanitization.max_schema_text_chars | number | optional | 1000 | > 0 or null | - | Maximum forwarded length for schema title/description text fields. |
tool_description_policy | object | - | - | - | servers[].tool_description_policy | Control how much description prose from upstream tools should be forwarded to the client. |
tool_description_policy.mode | string | optional | "preserve" | "preserve", "truncate", "strip" | - | core.tool_description_policy.mode |
tool_description_policy.max_tool_description_chars | number | optional | 280 | > 0 or null | - | Maximum forwarded length for top-level tool descriptions when mode="truncate". |
tool_description_policy.max_schema_description_chars | number | optional | 280 | > 0 or null | - | Maximum forwarded length for schema description fields when mode="truncate". |
tool_definition_pinning | object | - | - | - | servers[].tool_definition_pinning.mode | Protect the client-visible tool catalog from mid-session definition drift. |
tool_definition_pinning.mode | string | optional | "warn" | "off", "warn", "block" | - | How the adapter should react when a later tool catalog differs from the pinned baseline for the same session. |
tool_definition_pinning.block_strategy | string | optional | "error" | "error", "baseline_subset" | - | What "block" mode should do after drift is detected. |
tool_definition_pinning.block_error_session_action | string | optional | "invalidate" | "keep", "invalidate" | - | When block_strategy="error", decide whether the adapter should keep the current session alive or invalidate it immediately after drift is detected. |
upload_path | string | optional | "/upload" | - | - | Base HTTP path for the multipart file upload endpoint. |
upstream_metadata_cache_ttl_seconds | number | optional | 300 | >= 0 | - | TTL in seconds for cached upstream metadata list calls (list_tools, list_resources, list_resource_templates, list_prompts) on each session-pinned upstream client. |
auth | object | - | - | - | - | Adapter-level authentication |
auth.enabled | boolean | optional | false | - | - | Whether to enforce token-based authentication on every inbound HTTP request to the adapter. |
auth.header_name | string | optional | "X-Mcp-Adapter-Auth-Token" | - | - | Name of the HTTP header that clients must include on every request. |
auth.token | null | conditional | null | - | - | The secret token value that clients must send in the auth header. |
auth.signed_upload_ttl_seconds | number | optional | 120 | > 0 | - | How long (in seconds) a signed upload URL stays valid after being issued by the <server_id>_get_upload_url MCP tool. |
auth.signing_secret | null | optional | null | - | - | Optional dedicated secret used to compute HMAC-SHA256 signatures on signed upload URLs (see signed_upload_ttl_seconds above). |
cors | object | - | - | - | - | Only relevant when JavaScript clients in browsers call the adapter directly. |
cors.enabled | boolean | optional | false | - | - | Whether to add CORS response headers at all. |
cors.allowed_origins | array | optional | [] | - | - | List of origins allowed to make cross-origin requests. |
cors.allowed_methods | array | optional | ["POST", "GET", "OPTIONS"] | - | - | HTTP methods permitted in CORS pre-flight responses. |
cors.allowed_headers | array | optional | ["*"] | - | - | Headers permitted in cross-origin requests. |
cors.allow_credentials | boolean | optional | false | - | - | Whether to allow cookies or credentials in cross-origin requests. |
defaults | object | - | - | - | - | These values apply to every proxied tool call unless overridden at the server (servers[].tool_defaults) or adapter level (adapters[].overrides). |
defaults.tool_call_timeout_seconds | number | optional | 60 | > 0 or null | servers[].tool_defaults.tool_call_timeout_seconds; servers[].adapters[].overrides.tool_call_timeout_seconds | Timeout in seconds for upstream tool calls. |
defaults.allow_raw_output | boolean | optional | false | - | servers[].tool_defaults.allow_raw_output; servers[].adapters[].overrides.allow_raw_output; servers[].adapters[].allow_raw_output | When true, artifact_producer adapters include the raw file bytes (base64-encoded) directly inside the MCP tool response. |
upstream_ping | object | - | - | - | servers[].upstream_ping | Active upstream health monitoring and circuit breaker |
upstream_ping.enabled | boolean | optional | true | - | - | Whether to run the ping loop at all. |
upstream_ping.interval_seconds | number | optional | 15 | > 0 | - | Seconds between consecutive upstream ping attempts. |
upstream_ping.timeout_seconds | number | optional | 5 | > 0 | - | Seconds to wait for an upstream ping response before counting it a failure. |
upstream_ping.failure_threshold | number | optional | 3 | > 0 | - | Number of consecutive ping failures required to open the circuit breaker. |
upstream_ping.open_cooldown_seconds | number | optional | 30 | > 0 | - | Seconds the breaker stays in "open" (blocking) state before attempting recovery probes in "half_open" state. |
upstream_ping.half_open_probe_allowance | number | optional | 2 | > 0 | - | Number of consecutive successful probe requests needed in "half_open" state before the breaker returns to fully "closed" (healthy). |
Show example snippet
core:
# ---------------------------------------------------------------------------
# Network binding
# ---------------------------------------------------------------------------
# IP address the HTTP server binds to.
# Use "0.0.0.0" to listen on all interfaces (common in containers).
# Use "127.0.0.1" to restrict to localhost only (recommended in production
# behind a reverse proxy).
# Also used as the fallback host when determining public_base_url.
# Optional. Default: "0.0.0.0"
host: "0.0.0.0"
# TCP port the HTTP server listens on.
# Optional. Default: 8932. Allowed: 1-65535.
port: 8932
# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
# Minimum log level for the adapter process.
# Passed directly to uvicorn and Python's logging system.
# Optional. Default: "warning".
# Allowed: "debug", "info", "warning", "error", "critical"
log_level: "warning"
# ---------------------------------------------------------------------------
# Startup readiness wait
# ---------------------------------------------------------------------------
# Maximum seconds to wait during startup for all upstream MCP servers to
# become reachable before the application starts accepting traffic.
# The adapter retries upstream probes with exponential backoff (capped at 5s)
# until either all upstreams respond or this limit is exhausted.
# When the limit is exhausted, the adapter starts anyway in "degraded" mode;
# the /healthz endpoint will report "degraded" until all upstreams recover.
# Set to 0 to skip the wait altogether and start immediately.
# Optional. Default: 60. Allowed: >= 0.
max_start_wait_seconds: 60
# ---------------------------------------------------------------------------
# Background cleanup
# ---------------------------------------------------------------------------
# How often (in seconds) the background cleanup loop runs to remove
# expired uploads, expired artifacts, and idle sessions.
# Set to null to disable background cleanup entirely (manual or external GC).
# The cleanup loop is supervisor-managed and restarts itself on unexpected
# failures.
# Optional. Default: 60. Allowed: > 0 or null.
cleanup_interval_seconds: 60
# ---------------------------------------------------------------------------
# Public base URL
# ---------------------------------------------------------------------------
# External base URL used when creating upload endpoint URLs that are
# returned to MCP clients (e.g., in server-prefixed
# "<server_id>_get_upload_url" tools).
# Derivation order when this is null:
# 1. X-Forwarded-Proto + X-Forwarded-Host headers on the incoming request.
# 2. request.base_url from the current HTTP request.
# 3. http://{core.host}:{core.port} (replacing 0.0.0.0 with 127.0.0.1).
# Always set this explicitly when running behind a reverse proxy or in k8s
# with an ingress so that returned URLs are externally reachable.
# Optional. Default: null.
public_base_url: null
# public_base_url: "https://mcp-adapter.example.com"
# ---------------------------------------------------------------------------
# HTTP artifact download endpoint
# ---------------------------------------------------------------------------
# When true the adapter registers:
# GET /artifacts/{server_id}/{session_id}/{artifact_id}
# This lets clients download raw artifact bytes over HTTP using an
# Mcp-Session-Id header for session validation. The artifact's metadata
# in tool responses will also include a download_url field.
# When false (default) artifacts are only accessible via MCP resources
# (if artifacts.expose_as_resources is true).
# Optional. Default: false.
allow_artifacts_download: false
# ---------------------------------------------------------------------------
# Experimental Code Mode
# ---------------------------------------------------------------------------
# When true, the server exposes FastMCP Code Mode instead of the full direct
# tool list. Clients see a compact meta-surface such as `search`,
# `get_schema`, and `execute`, and use those meta-tools to discover and call
# the real tool catalog on demand.
#
# The underlying tools still exist behind the Code Mode layer. Adapter-
# wrapped tools remain the source of truth, and once an upload_consumer or
# artifact_producer override is registered, the upstream original with the
# same name is hidden so clients do not see duplicate entries.
#
# This is the global default. Individual servers can override it with
# servers[].code_mode_enabled.
#
# Optional. Default: false.
code_mode_enabled: false
# ---------------------------------------------------------------------------
# Tool description shaping
# ---------------------------------------------------------------------------
# When true, adapter-wrapped upload_consumer tools keep only a short semantic
# summary from the upstream description, then append the adapter workflow
# instructions. This keeps descriptions smaller for weaker models while still
# preserving enough signal to distinguish similar tools.
#
# When false, the full upstream description is kept and the adapter guidance
# is appended after it.
#
# Individual servers can override this with servers[].shorten_descriptions.
#
# Optional. Default: false.
shorten_descriptions: false
# Maximum token budget used when core.shorten_descriptions=true or when a
# server override enables shortened descriptions. Only the first upstream
# sentence is considered, then it is trimmed to this many tokens.
#
# Individual servers can override this with
# servers[].short_description_max_tokens.
#
# Optional. Default: 16. Allowed: > 0.
short_description_max_tokens: 16
# ---------------------------------------------------------------------------
# Tool metadata sanitization
# ---------------------------------------------------------------------------
# Apply a conservative sanitization pass to model-visible tool metadata
# before it reaches the client. This affects tool title, description text and
# schema title, description fields that models can actually read.
#
# "off" -> forward metadata as-is.
# "sanitize" -> normalize/sanitize the visible text fields and log when
# changes were required.
# "block" -> hide tools whose visible metadata would have required
# sanitization instead of forwarding the modified version.
#
# Individual servers can override this with
# servers[].tool_metadata_sanitization.*.
tool_metadata_sanitization:
# Optional. Default: "sanitize".
# Allowed: "off", "sanitize", "block"
mode: "sanitize"
# Apply Unicode NFKC normalization to model-visible metadata text.
#
# Optional. Default: true.
normalize_unicode: true
# Remove zero-width / invisible formatting characters from model-visible
# tool metadata text.
#
# Optional. Default: true.
remove_invisible_characters: true
# Maximum forwarded length for tool titles.
#
# Optional. Default: 256. Allowed: > 0 or null.
max_tool_title_chars: 256
# Maximum forwarded length for top-level tool descriptions.
#
# Optional. Default: 2000. Allowed: > 0 or null.
max_tool_description_chars: 2000
# Maximum forwarded length for schema title/description text fields.
#
# Optional. Default: 1000. Allowed: > 0 or null.
max_schema_text_chars: 1000
# ---------------------------------------------------------------------------
# Tool description policy
# ---------------------------------------------------------------------------
# Control how much description prose from upstream tools should be forwarded
# to the client. This applies to top-level tool descriptions and schema
# description fields across the whole visible tool catalog.
#
# The policy runs before Code Mode. If Code Mode is enabled, its discovery
# and execute tools inherit the same description surface instead of bypassing
# this policy.
#
# This is intentionally separate from tool_metadata_sanitization:
#
# - tool_metadata_sanitization cleans suspicious text
# - tool_description_policy decides how much description prose is forwarded
#
# "preserve" -> keep descriptions after earlier sanitization passes.
# "truncate" -> keep only the first N characters.
# "strip" -> remove description text entirely.
#
# Individual servers can override this with
# servers[].tool_description_policy.*.
tool_description_policy:
# Optional. Default: "preserve".
# Allowed: "preserve", "truncate", "strip"
mode: "preserve"
# Maximum forwarded length for top-level tool descriptions when
# mode="truncate".
#
# Optional. Default: 280. Allowed: > 0 or null.
max_tool_description_chars: 280
# Maximum forwarded length for schema description fields when
# mode="truncate".
#
# Optional. Default: 280. Allowed: > 0 or null.
max_schema_description_chars: 280
# ---------------------------------------------------------------------------
# Tool-definition pinning
# ---------------------------------------------------------------------------
# Protect the client-visible tool catalog from mid-session definition drift.
# On the first catalog exposure for a given Mcp-Session-Id, the adapter pins
# the visible tool definitions for that session. Later changes from the
# upstream server are then detected and handled according to the selected
# policy.
#
# This is useful when you do not want a tool to look harmless during initial
# review and then quietly change description or schema mid-session.
#
# Legitimate upstream upgrades are still allowed, but they require a fresh
# adapter session (a new Mcp-Session-Id). The adapter does not auto-repin in
# the middle of an existing session.
#
# Individual servers can override this with
# servers[].tool_definition_pinning.mode and
# servers[].tool_definition_pinning.block_strategy and
# servers[].tool_definition_pinning.block_error_session_action.
tool_definition_pinning:
# How the adapter should react when a later tool catalog differs from the
# pinned baseline for the same session.
#
# "off" -> do not pin or compare tool definitions.
# "warn" -> allow the new catalog, but annotate returned tool descriptions
# with a session-wide warning and more specific warnings for
# changed/new tools.
# "block" -> detect drift and then either return an MCP error or only the
# still-trusted unchanged subset (see block_strategy below).
#
# Optional. Default: "warn".
# Allowed: "off", "warn", "block"
mode: "warn"
# What "block" mode should do after drift is detected.
#
# "error" -> fail the catalog request and fail direct calls to drifted
# tools with an explicit error.
# "baseline_subset" -> keep serving only unchanged pinned tools and hide
# changed/new/removed tools from that session.
#
# Optional. Default: "error".
# Allowed: "error", "baseline_subset"
block_strategy: "error"
# When block_strategy="error", decide whether the adapter should keep the
# current session alive or invalidate it immediately after drift is
# detected.
#
# "keep" -> return the blocking error, but leave the session alive so the
# client can keep receiving the same error until it reconnects.
# "invalidate" -> turn the session into a terminal tombstone immediately.
# Any later reuse of the same Mcp-Session-Id is rejected
# until the tombstone expires, which forces the client to
# start a fresh adapter session.
#
# "invalidate" is the safer default because it turns legitimate upstream
# upgrades into an explicit session-boundary event instead of leaving a
# half-trusted session around.
#
# Optional. Default: "invalidate".
# Allowed: "keep", "invalidate"
block_error_session_action: "invalidate"
# ---------------------------------------------------------------------------
# Upload endpoint path
# ---------------------------------------------------------------------------
# Base HTTP path for the multipart file upload endpoint.
# The actual per-server route is: {upload_path}/{server_id}
# For example with upload_path="/upload" and server id "playwright":
# POST /upload/playwright (with Mcp-Session-Id header)
# A leading slash is added automatically if omitted. Trailing slash will be removed.
# Cannot be blank.
# Optional. Default: "/upload".
upload_path: "/upload"
# ---------------------------------------------------------------------------
# Upstream metadata cache
# ---------------------------------------------------------------------------
# TTL in seconds for cached upstream metadata list calls
# (`list_tools`, `list_resources`, `list_resource_templates`, `list_prompts`)
# on each session-pinned upstream client.
#
# Why this exists:
# - MCP clients often open resource/tool browsers repeatedly.
# - FastMCP aggregate providers can trigger multiple provider lookups for a
# single read/list operation.
# - Without a short cache, repeated upstream roundtrips can add noticeable UI
# latency even on localhost.
#
# Set to 0 to disable metadata caching entirely.
# Optional. Default: 300. Allowed: >= 0.
upstream_metadata_cache_ttl_seconds: 300
# ---------------------------------------------------------------------------
# Adapter-level authentication
# ---------------------------------------------------------------------------
auth:
# Whether to enforce token-based authentication on every inbound HTTP request
# to the adapter. When true, each request must include the configured header
# (see header_name below) whose value must exactly match the configured token.
# Requests that omit the header or send the wrong value are rejected with HTTP 401.
# When false, all requests are accepted with zero auth checks — only safe on
# localhost or in fully private, trusted networks.
# Strongly recommended to enable in any environment reachable over a network.
# Optional. Default: false.
enabled: false
# Name of the HTTP header that clients must include on every request.
# The adapter looks up this header (case-insensitive name match) and then
# compares its value exactly (case-sensitive) against auth.token.
# Example: with the default name, clients send:
# X-Mcp-Adapter-Auth-Token: <your-secret-token>
# Optional. Default: "X-Mcp-Adapter-Auth-Token".
header_name: "X-Mcp-Adapter-Auth-Token"
# The secret token value that clients must send in the auth header.
# The incoming header value is compared exactly (case-sensitive) to this string.
# Required when auth.enabled is true — the adapter refuses to start if
# enabled=true and this is blank or null.
# Never commit the actual token to source control; use env interpolation instead.
# Optional (required when enabled=true). Default: null.
token: null
# token: "${MCP_ADAPTER_TOKEN}"
# How long (in seconds) a signed upload URL stays valid after being issued by
# the `<server_id>_get_upload_url` MCP tool.
# When auth is enabled, the `get_upload_url` tool embeds a short-lived
# HMAC-SHA256 signature in the upload URL. The /upload/{server_id} endpoint
# validates this signature, rejecting expired or tampered URLs with HTTP 401.
# Each signed URL is one-time use; after it is consumed or expired it cannot
# be reused. This lets MCP clients upload files without needing to know or pass
# the main auth token themselves.
# Optional. Default: 120. Allowed: > 0.
signed_upload_ttl_seconds: 120
# Optional dedicated secret used to compute HMAC-SHA256 signatures on signed
# upload URLs (see signed_upload_ttl_seconds above).
# When null, auth.token is used as the signing secret — no separate value needed.
# Set this to a different random secret when you want to rotate upload-URL
# signatures independently of the main auth token, or to invalidate all
# outstanding signed upload URLs without changing the main token.
# Cannot be blank when set (use null to fall back to auth.token instead).
# Never commit the actual secret to source control; use env interpolation instead.
# Optional. Default: null.
signing_secret: null
# signing_secret: "${MCP_ADAPTER_SIGNING_SECRET}"
# ---------------------------------------------------------------------------
# CORS
# ---------------------------------------------------------------------------
# Only relevant when JavaScript clients in browsers call the adapter directly.
# If clients are server-to-server or go through a proxy that handles CORS,
# leave this disabled.
cors:
# Whether to add CORS response headers at all.
# Optional. Default: false.
enabled: false
# List of origins allowed to make cross-origin requests.
# An empty list combined with enabled=true effectively blocks all origins.
# Use ["*"] to allow any origin (not recommended with allow_credentials=true).
# Optional. Default: [].
allowed_origins: []
# allowed_origins: ["https://app.example.com", "https://staging.example.com"]
# HTTP methods permitted in CORS pre-flight responses.
# Optional. Default: ["POST", "GET", "OPTIONS"].
allowed_methods: ["POST", "GET", "OPTIONS"]
# Headers permitted in cross-origin requests.
# ["*"] allows any header.
# Optional. Default: ["*"].
allowed_headers: ["*"]
# Whether to allow cookies or credentials in cross-origin requests.
# Must be false when allowed_origins contains "*".
# Optional. Default: false.
allow_credentials: false
# ---------------------------------------------------------------------------
# Global tool-call defaults
# ---------------------------------------------------------------------------
# These values apply to every proxied tool call unless overridden at the
# server (servers[].tool_defaults) or adapter level (adapters[].overrides).
# Precedence: adapter.overrides > server.tool_defaults > core.defaults
defaults:
# Timeout in seconds for upstream tool calls.
# null means no timeout (waits indefinitely -- not recommended).
# Optional. Default: 60. Allowed: > 0 or null.
tool_call_timeout_seconds: 60
# When true, artifact_producer adapters include the raw file bytes
# (base64-encoded) directly inside the MCP tool response.
# This is bandwidth-intensive and memory-heavy for large files; prefer
# MCP resource access (artifact://) and/or HTTP download instead.
# Can be overridden per-server and per-adapter.
# Optional. Default: false.
allow_raw_output: false
# ---------------------------------------------------------------------------
# Active upstream health monitoring and circuit breaker
# ---------------------------------------------------------------------------
# The adapter runs a background ping loop for each configured upstream server.
# Failed pings increase a consecutive-failure counter. When the counter
# reaches failure_threshold the circuit breaker goes to "open" state and all
# proxy requests to that upstream are rejected immediately with HTTP 503.
# After open_cooldown_seconds, the breaker moves to "half_open" and lets
# half_open_probe_allowance probe requests through. If those probes succeed
# the breaker closes; if they fail, it reopens.
# Per-server overrides are under servers[].upstream_ping.
upstream_ping:
# Whether to run the ping loop at all.
# When false, no background pinging occurs and the circuit breaker is
# always "closed" (requests are never blocked by health state).
# Optional. Default: true.
enabled: true
# Seconds between consecutive upstream ping attempts.
# Lower values detect failures faster but add more upstream load.
# Optional. Default: 15. Allowed: > 0.
interval_seconds: 15
# Seconds to wait for an upstream ping response before counting it a failure.
# Should be well below interval_seconds.
# Optional. Default: 5. Allowed: > 0.
timeout_seconds: 5
# Number of consecutive ping failures required to open the circuit breaker.
# A value of 1 opens the breaker on the first failure (aggressive).
# A value of 3 (default) tolerates transient blips.
# Optional. Default: 3. Allowed: > 0.
failure_threshold: 3
# Seconds the breaker stays in "open" (blocking) state before attempting
# recovery probes in "half_open" state.
# Optional. Default: 30. Allowed: > 0.
open_cooldown_seconds: 30
# Number of consecutive successful probe requests needed in "half_open"
# state before the breaker returns to fully "closed" (healthy).
# Optional. Default: 2. Allowed: > 0.
half_open_probe_allowance: 2
telemetry¶
OpenTelemetry export (metrics + optional logs)
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
enabled | boolean | optional | false | - | - | Master switch for all telemetry export. |
transport | string | optional | "grpc" | "grpc", "http" | - | OTLP transport protocol. |
endpoint | null | optional | null (protocol-specific default) | null or non-empty URL string | - | Metrics OTLP endpoint. |
logs_endpoint | null | optional | null | null or non-empty URL string | - | Optional dedicated OTLP endpoint for logs when emit_logs=true and transport="http". |
insecure | boolean | optional | true | - | - | TLS behavior for OTLP/gRPC transport. |
headers | object | optional | {} | object map of string->string | - | Extra OTLP headers sent on every export request. |
export_interval_seconds | number | optional | 15 | > 0 | - | Export cadence for metrics reader. |
export_timeout_seconds | number | optional | 10 | > 0 | - | Export timeout for OTLP exporter operations. |
max_queue_size | number | optional | 5000 | > 0 | - | Internal async queue sizing for telemetry events. |
queue_batch_size | number | optional | 256 | > 0 | - | Max telemetry events processed per worker drain cycle. |
periodic_flush_seconds | number | optional | 5 | > 0 | - | Periodic force-flush cadence (seconds) for telemetry providers. |
shutdown_drain_timeout_seconds | number | optional | 10 | > 0 | - | Grace period for draining queued telemetry events during app shutdown. |
drop_on_queue_full | boolean | optional | true | - | - | When true and queue is full, telemetry events are dropped instead of blocking request processing. |
flush_on_shutdown | boolean | optional | true | - | - | Force flush telemetry providers during normal app shutdown. |
flush_on_terminate | boolean | optional | true | - | - | Register a best-effort interpreter termination hook that drains pending telemetry events and force-flushes providers. |
emit_logs | boolean | optional | false | - | - | Whether application logs should also be exported as OTel log records. |
log_batch_max_queue_size | null | optional | null (SDK default) | > 0 or null | - | Optional BatchLogRecordProcessor tuning when emit_logs=true. |
log_batch_max_export_batch_size | null | optional | null (SDK default) | > 0 or null | - | Maximum number of log records exported in one OTel log batch. |
log_batch_schedule_delay_millis | null | optional | null (SDK default) | > 0 or null | - | Delay (milliseconds) between scheduled OTel log batch exports. |
log_batch_export_timeout_millis | null | optional | null (SDK default) | > 0 or null | - | Timeout (milliseconds) allowed for one OTel log export operation. |
service_name | string | optional | "remote-mcp-adapter" | - | - | OTel resource attributes for service identity. |
service_namespace | null | optional | null | - | - | Optional namespace for service grouping in observability backends. |
Show example snippet
telemetry:
# Master switch for all telemetry export. When false, no telemetry providers
# are initialized and no OTLP traffic is emitted.
# Optional. Default: false.
enabled: false
# OTLP transport protocol.
# - grpc: OTLP/gRPC exporter (default)
# - http: OTLP/HTTP protobuf exporter
# Optional. Default: "grpc".
# Allowed: "grpc", "http"
transport: "grpc"
# Metrics OTLP endpoint.
# Defaults when null:
# - grpc: http://localhost:4317
# - http: http://localhost:4318/v1/metrics
# Use https://... for TLS endpoints.
# Cannot be blank when set.
# Optional. Default: null (protocol-specific default).
# Allowed: null or non-empty URL string.
endpoint: null
# Optional dedicated OTLP endpoint for logs when emit_logs=true and
# transport="http". If null, defaults to http://localhost:4318/v1/logs.
# Ignored for grpc transport (grpc uses telemetry.endpoint).
# Use https://... for TLS endpoints.
# Cannot be blank when set.
# Optional. Default: null.
# Allowed: null or non-empty URL string.
logs_endpoint: null
# TLS behavior for OTLP/gRPC transport.
# - true -> insecure/plaintext gRPC channel (no TLS)
# - false -> secure/TLS gRPC channel
# Ignored for transport="http" (HTTP exporter TLS is controlled by using
# https:// endpoint URLs).
# Note: custom CA/client certificate files are not currently exposed as
# adapter config knobs; exporter uses runtime/system trust configuration.
# Optional. Default: true.
insecure: true
# Extra OTLP headers sent on every export request.
# Commonly used for vendor auth tokens and tenant scoping headers.
# Example:
# headers:
# Authorization: "Bearer ${OTEL_TOKEN}"
# Optional. Default: {}.
# Allowed: object map of string->string.
headers: {}
# Export cadence for metrics reader.
# Optional. Default: 15. Allowed: > 0.
export_interval_seconds: 15
# Export timeout for OTLP exporter operations.
# Optional. Default: 10. Allowed: > 0.
export_timeout_seconds: 10
# Internal async queue sizing for telemetry events.
# Optional. Default: 5000. Allowed: > 0.
max_queue_size: 5000
# Max telemetry events processed per worker drain cycle.
# Higher values reduce per-event overhead; lower values reduce event-loop
# monopolization under burst load.
# This controls only the adapter's internal telemetry event queue drain
# behavior, not OTLP exporter batch size.
# Optional. Default: 256. Allowed: > 0.
queue_batch_size: 256
# Periodic force-flush cadence (seconds) for telemetry providers.
# Also acts as the worker wake interval while idle.
# This does not replace metrics export_interval_seconds; that is still the
# reader's collection/export schedule.
# Optional. Default: 5. Allowed: > 0.
periodic_flush_seconds: 5
# Grace period for draining queued telemetry events during app shutdown.
# Optional. Default: 10. Allowed: > 0.
shutdown_drain_timeout_seconds: 10
# When true and queue is full, telemetry events are dropped instead of
# blocking request processing.
# Optional. Default: true.
drop_on_queue_full: true
# Force flush telemetry providers during normal app shutdown.
# Optional. Default: true.
flush_on_shutdown: true
# Register a best-effort interpreter termination hook that drains pending
# telemetry events and force-flushes providers.
# Optional. Default: true.
flush_on_terminate: true
# Whether application logs should also be exported as OTel log records.
# Off by default: logs remain local-only unless enabled here.
# Optional. Default: false.
emit_logs: false
# Optional BatchLogRecordProcessor tuning when emit_logs=true.
# Leave null to use OpenTelemetry SDK defaults.
# Max in-memory queue size for the OTel log batch processor itself.
# Increase for very bursty logging to reduce drop risk, at the cost of RAM.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_max_queue_size: null
# Maximum number of log records exported in one OTel log batch.
# Larger batches can improve throughput; smaller batches can reduce burst
# latency and per-export payload size.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_max_export_batch_size: null
# Delay (milliseconds) between scheduled OTel log batch exports.
# Lower values push logs out sooner; higher values batch more aggressively.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_schedule_delay_millis: null
# Timeout (milliseconds) allowed for one OTel log export operation.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_export_timeout_millis: null
# OTel resource attributes for service identity.
# Cannot be blank.
# Optional. Default: "remote-mcp-adapter".
service_name: "remote-mcp-adapter"
# Optional namespace for service grouping in observability backends.
# Blank/empty values are normalized to null.
# Optional. Default: null.
service_namespace: null
state_persistence¶
adapter metadata durability
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
type | string | conditional | "disk" | "memory", "disk", "redis" | - | Storage backend for adapter metadata, including session records, upload handles, and artifact descriptors. |
refresh_on_startup | boolean | optional | false | - | - | When true, any saved metadata is discarded at startup, and the adapter starts with an entirely empty in-memory state. |
snapshot_interval_seconds | number | optional | 30 | greater than 0 | - | How often (in seconds) the running in-memory state is saved to disk. |
unavailable_policy | string | optional | "fail_closed" | "fail_closed", "exit", "fallback_memory" | - | Behavior when the configured persistence backend becomes unreachable or fails during runtime after the adapter has started successfully. |
reconciliation | object | - | - | - | - | Startup reconciliation - scan storage.root for files that lack matching metadata entries. |
reconciliation.mode | string | optional | "if_empty" | "disabled", "if_empty", "always" | - | "disabled" - never reconcile from the filesystem at startup. |
reconciliation.legacy_server_id | null | optional | null | - | - | Server ID used to attribute legacy files when there's not enough information to automatically determine ownership. |
disk | object | - | - | - | - | Disk backend (relevant when type is "disk" or "memory") |
disk.local_path | null | optional | null (automatically derived from storage.root) | - | - | Path to the SQLite metadata database on the local filesystem. |
disk.wal | object | optional | true | - | - | SQLite WAL mode for the disk backend. |
disk.wal.enabled | boolean | - | - | - | - | state_persistence.disk.wal.enabled |
redis | object | - | - | - | - | Redis backend (relevant when type is "redis") |
redis.host | null | conditional | null | - | - | Hostname or IP address of the Redis server. |
redis.port | number | optional | 6379 | 1 to 65535 | - | TCP port of the Redis server. |
redis.db | number | optional | 0 | greater than or equal to 0 | - | Redis logical database index. |
redis.username | null | optional | null | - | - | Redis ACL username for Redis version 6 and above. |
redis.password | null | optional | null | - | - | Redis AUTH password. |
redis.tls_insecure | boolean | optional | false | - | - | When true, TLS certificate verification is bypassed for the Redis connection. |
redis.key_base | string | optional | "mcp_remote_adapter" | - | - | Key namespace prefix for all Redis keys created by this adapter. |
redis.ping_seconds | number | optional | 5 | > 0 | - | Seconds between Redis PING health-check calls made by the Redis client. |
Show example snippet
state_persistence:
# Storage backend for adapter metadata, including session records, upload handles,
# and artifact descriptors. This does not affect where actual file bytes are stored.
# Files are always located on the filesystem under storage.root.
#
# "memory" - in-process dictionary. Fastest option; no durability. All state is lost
# on process restart. Suitable for temporary development and testing only.
# Combine with disk.local_path and snapshot_interval_seconds to
# periodically save state so planned restarts can reload it.
# "disk" - SQLite database stored on the local filesystem (default). Durable
# across single-node restarts. Not safe for concurrent writes
# from multiple hosts; use "redis" for multi-pod setups.
# "redis" - Shared Redis store. Required when multiple adapter replicas
# share a single session namespace. Set redis.host.
# Optional. Default: "disk".
# Allowed: "memory", "disk", "redis"
type: "disk"
# When true, any saved metadata is discarded at startup, and the adapter
# starts with an entirely empty in-memory state. Existing files under
# storage.root are not deleted; only the metadata mappings are cleared.
# When false (default), the adapter restores in-memory state from the
# configured backend, allowing sessions and artifacts to survive planned restarts.
# Note: if reconciliation.mode is set to "always," the reconciliation backfill runs
# even when refresh_on_startup is true.
# Optional. Default: false.
refresh_on_startup: false
# How often (in seconds) the running in-memory state is saved to disk.
# Only relevant when type is "memory" and disk.local_path is configured.
# In that case, the adapter writes a SQLite snapshot at this interval
# to enable recovery after a planned restart.
# For type "disk" and type "redis," changes are written synchronously on every mutation
# and do not use this interval.
# Optional. Default: 30. Allowed: greater than 0.
snapshot_interval_seconds: 30
# Behavior when the configured persistence backend becomes unreachable or
# fails during runtime after the adapter has started successfully.
#
# "fail_closed" - keep the process running but reject all stateful
# operations (tool calls, uploads, artifact reads) that need the persistence layer.
# /healthz reports "degraded." This is a safe default, posing no risk of data corruption,
# requiring the operator to fix the backend.
#
# "exit" - terminate the process immediately so an orchestrator
# (Kubernetes, systemd, Docker restart policy) can restart it. Use this option when hard restarts are preferred
# over a degraded service window.
#
# "fallback_memory" - silently continue serving traffic using the last
# known in-memory state. New changes are not saved while the backend is down;
# restarting the process during an outage will lose those changes.
# This option should be used only when maximum availability is prioritized over durability.
#
# Optional. Default: "fail_closed".
# Allowed: "fail_closed", "exit", "fallback_memory"
unavailable_policy: "fail_closed"
# Startup reconciliation - scan storage.root for files that lack matching
# metadata entries. This is useful when moving from an in-memory-only setup
# (where metadata was never saved) or recovering from a crash when a file was
# written but the metadata commit did not finish.
reconciliation:
# "disabled" - never reconcile from the filesystem at startup.
# "if_empty" - reconcile only when the backend has zero sessions and zero
# tombstones (this is a safe default that prevents re-import on normal
# restarts where the backend already has data).
# "always" - reconcile on every startup, adding newly discovered
# orphan files without removing existing metadata entries.
# This runs even when refresh_on_startup is true.
# Optional. Default: "if_empty".
# Allowed: "disabled", "if_empty", "always"
mode: "if_empty"
# Server ID used to attribute legacy files when there's not enough information to
# automatically determine ownership. This is common in multi-server
# setups where legacy file paths do not include a server-id component.
# When null:
# • If exactly one server is configured, that server is the fallback owner.
# • If multiple servers are configured, ambiguous sessions are skipped.
# Must match one of the configured servers[].id values when set.
# Optional. Default: null.
legacy_server_id: null
# ---------------------------------------------------------------------------
# Disk backend (relevant when type is "disk" or "memory")
# ---------------------------------------------------------------------------
disk:
# Path to the SQLite metadata database on the local filesystem.
# type="disk" → primary durable store; all changes committed here.
# type="memory" → target for periodic snapshots; loaded at startup if present.
# When null, defaults to: {storage.root}/state/adapter_state.sqlite3
# The parent directory is created automatically if it is missing.
# Optional. Default: null (automatically derived from storage.root).
local_path: null
# local_path: "/data/shared/state/adapter_state.sqlite3"
# SQLite WAL mode for the disk backend.
# When true, SQLite uses WAL journaling, allowing concurrent readers
# alongside a writer and improving throughput under mixed read/write load.
# Set to false only on filesystems that do not support SQLite WAL mode
# (for example, some NFS/SMB mounts), which will force DELETE journal mode.
# Optional. Default: true.
wal:
enabled: true
# ---------------------------------------------------------------------------
# Redis backend (relevant when type is "redis")
# ---------------------------------------------------------------------------
redis:
# Hostname or IP address of the Redis server.
# Required when state_persistence.type="redis".
# Optional otherwise. Default: null.
host: null
# host: "redis"
# host: "${REDIS_HOST:-redis}"
# TCP port of the Redis server.
# Optional. Default: 6379. Allowed: 1 to 65535.
port: 6379
# Redis logical database index. Use a dedicated index (e.g., 1 or 2) to
# separate adapter keys from other applications sharing the same Redis instance.
# Optional. Default: 0. Allowed: greater than or equal to 0.
db: 0
# Redis ACL username for Redis version 6 and above.
# Leave null if using the legacy requirepass-only setup.
# Optional. Default: null.
username: null
# username: "${REDIS_USERNAME}"
# Redis AUTH password. Works with both legacy requirepass and ACL authentication.
# Optional. Default: null.
password: null
# password: "${REDIS_PASSWORD}"
# When true, TLS certificate verification is bypassed for the Redis
# connection. Use this only in development with self-signed certificates.
# Never enable in production, as this exposes all adapter state to potential attacks.
# Optional. Default: false.
tls_insecure: false
# Key namespace prefix for all Redis keys created by this adapter.
# This prevents key collisions when multiple adapter instances or other
# services share the same Redis instance or database index.
# Change this to a unique value for each independent adapter deployment.
# Cannot be blank.
# Optional. Default: "mcp_remote_adapter".
key_base: "mcp_remote_adapter"
# Seconds between Redis PING health-check calls made by the Redis client.
# A failing ping triggers the unavailable_policy response if it persists.
# Optional. Default: 5. Allowed: > 0.
ping_seconds: 5
storage¶
shared filesystem layout and file-write behaviour. This section governs where uploaded and artifact files are physically stored, how large the store can grow, how concurrent writes are coordinated, and how orphan files are identified and cleaned up.
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
root | string | optional | "/data/shared" | - | - | Root directory on a persistent or shared volume. |
max_size | null | optional | null | - | - | Maximum total byte footprint allowed across all files under storage.root (uploads plus artifacts combined). |
atomic_writes | boolean | optional | true | - | - | When true, every file write follows write-to-temp, then fsync, and finally atomic rename. |
orphan_sweeper_enabled | boolean | optional | true | - | - | Whether the background cleanup loop should remove orphan files. |
orphan_sweeper_grace_seconds | number | optional | 300 | >= 0 | - | Minimum file age in seconds before an unreferenced file can be deleted as an orphan. |
lock_mode | string | optional | "auto" | "none" | "process" | "file" | "redis" | "auto" | - | Cross-process write concurrency strategy for file operations. |
artifact_locator_policy | string | optional | "storage_only" | "storage_only" | "allow_configured_roots" | - | Controls which filesystem paths the artifact_producer adapter can use as the source when copying or moving files into the artifact store (applies to output_locator modes "structured" and "regex"). |
artifact_locator_allowed_roots | array | conditional | [] | - | - | Additional filesystem root prefixes the artifact locator can read source files from. |
Show example snippet
storage:
# Root directory on a persistent or shared volume.
# Must survive container restarts. In containerized deployments, mount a
# persistent volume here. For multi-replica and multi-pod deployments, use a
# shared network volume such as NFS, CephFS, AWS EFS, or GCS FUSE so all
# replicas read and write the same storage tree.
# Optional. Default: "/data/shared".
root: "/data/shared"
# Maximum total byte footprint allowed across all files under storage.root
# (uploads plus artifacts combined). When a new write would exceed this limit,
# the adapter rejects the operation with a quota error instead of filling the
# volume and causing an out-of-disk crash.
# Null means no software-enforced limit; rely on the filesystem or block
# storage quota instead.
# Accepts integer bytes or a human-readable byte-size string.
# Optional. Default: null.
max_size: null
# max_size: "50Gi"
# When true, every file write follows write-to-temp, then fsync, and finally atomic rename.
# The destination path isn't touched until the rename completes, so
# readers always see either the previous complete file or the new complete
# file, never a partial write. If the process crashes mid-write, the temp
# file is left behind and cleaned up by the orphan sweeper.
# Disabling this makes writes slightly faster but risks torn files during crashes.
# Only disable in temporary development environments with no durability requirement.
# Optional. Default: true.
atomic_writes: true
# Whether the background cleanup loop should remove orphan files.
# An orphan is any file under uploads or artifacts that has no matching
# record in the adapter's persistence metadata. Orphans accumulate after
# crashes where the file was written but the metadata commit didn't finish
# or when atomic_writes is true and leaves a temp file after a mid-write crash.
# The sweeper only deletes files older than orphan_sweeper_grace_seconds
# to prevent racing with in-progress writes not yet committed to metadata.
# Optional. Default: true.
orphan_sweeper_enabled: true
# Minimum file age in seconds before an unreferenced file can be deleted as an orphan.
# This grace period ensures the sweeper doesn't delete files actively being written
# by a concurrent request that hasn't yet committed its metadata record.
# Set to 0 for immediate orphan cleanup (safe only in single-worker setups
# with synchronous metadata commits and atomic_writes set to true).
# Optional. Default: 300. Allowed: >= 0.
orphan_sweeper_grace_seconds: 300
# Cross-process write concurrency strategy for file operations.
# Choose the mode that matches your deployment setup:
#
# "none" -- No locking. Safe only for a single uvicorn worker process
# with no concurrent write operations that can collide. Highest
# raw throughput.
#
# "process" -- asyncio-level in-process lock keyed on file path. Safe for
# a single uvicorn worker running many coroutines at once.
# Does not protect across separate OS processes.
#
# "file" -- OS-level fcntl/flock advisory lock (default). Safe for
# multiple uvicorn workers on the same host (with --workers N).
# Not safe across separate hosts; each host locks its own
# local file descriptor rather than a shared resource.
#
# "redis" -- Distributed lock stored in Redis. Safe for multi-host or
# multi-pod deployments sharing the same storage volume.
# Requires state_persistence.type set to "redis". The adapter will not
# start with lock_mode set to "redis" if type is not "redis".
#
# "auto" -- Resolved at startup: "redis" when state_persistence.type is
# "redis", otherwise "file". Recommended when you want the
# lock strategy to automatically follow the persistence choice.
#
# Optional. Default: "auto".
# Allowed: "none" | "process" | "file" | "redis" | "auto"
lock_mode: "auto"
# Controls which filesystem paths the artifact_producer adapter can use
# as the source when copying or moving files into the artifact store
# (applies to output_locator modes "structured" and "regex").
#
# "storage_only" -- Source paths must already be under storage.root.
# Use this when the upstream tool writes files
# to a path inside the shared storage volume.
# "allow_configured_roots" -- Source paths may also be under any path listed
# in artifact_locator_allowed_roots. Use this
# when the upstream tool writes files to a known
# path outside storage.root (for example, /tmp or a
# tool-specific working directory).
#
# Optional. Default: "storage_only".
# Allowed: "storage_only" | "allow_configured_roots"
artifact_locator_policy: "storage_only"
# Additional filesystem root prefixes the artifact locator can read source files from.
# Only meaningful when artifact_locator_policy is "allow_configured_roots".
# The adapter will not start if the policy requires this list but it is empty.
# Optional (required when policy is "allow_configured_roots"). Default: [].
artifact_locator_allowed_roots: []
# artifact_locator_allowed_roots:
# - "/tmp"
# - "/app/tool-outputs"
sessions¶
lifecycle and concurrency limits
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
max_active | null | optional | null | > 0 or null | - | Maximum number of concurrent active sessions across all servers. |
max_in_flight_per_session | null | optional | null | > 0 or null | - | Maximum number of in-flight tool calls allowed simultaneously within a single session. |
idle_ttl_seconds | null | optional | null | > 0 or null | - | Seconds of inactivity after which a session is considered idle and eligible for expiry by the cleanup loop. |
allow_revival | boolean | optional | true | - | - | When a session expires due to idle_ttl_seconds, two behaviours are possible: |
tombstone_ttl_seconds | number | optional | 86400 (1 day) | > 0 | - | How long (in seconds) a tombstoned session's metadata is retained before the session and all its files are permanently deleted. |
upstream_session_termination_retries | number | optional | 1 | 0–5 | - | How many times the adapter automatically retries an upstream tool call after the upstream MCP server signals "Session terminated" — for example when a stateful upstream process (Playwright, a long-running container) was restarted and lost its own internal session. |
max_total_session_size | null | optional | null | - | - | Per-session combined storage quota (uploads + artifacts together). |
eviction_policy | string | optional | "lru_uploads_then_artifacts" | "lru_uploads_then_artifacts" | "lru_artifacts_then_uploads" | - | Determines which files are evicted first when max_total_session_size is reached. |
Show example snippet
sessions:
# Maximum number of concurrent active sessions across all servers.
# A "session" maps 1-to-1 to an MCP client connection (identified by the
# Mcp-Session-Id header). Once the limit is reached, new sessions receive
# HTTP 429 until an existing session expires or is cleaned up.
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_active: null
# Maximum number of in-flight tool calls allowed simultaneously within a
# single session. Excess requests receive HTTP 429.
# Useful to prevent a single session from monopolising upstream workers.
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_in_flight_per_session: null
# Seconds of inactivity after which a session is considered idle and
# eligible for expiry by the cleanup loop. "Activity" is any tool call or
# upload that touches the session.
# A session is only expired when in_flight == 0 (no active requests).
# null disables idle expiry entirely (sessions live until process restart).
# Optional. Default: null. Allowed: > 0 or null.
idle_ttl_seconds: null
# idle_ttl_seconds: 21600 # 6 hours
# When a session expires due to idle_ttl_seconds, two behaviours are possible:
#
# allow_revival: true (default)
# The session is "tombstoned" -- its in-memory metadata is preserved in a
# lightweight tombstone for tombstone_ttl_seconds. If the same client
# reconnects within that window the session is revived transparently
# (uploads/artifacts still accessible if not yet expired by their own TTLs).
# After tombstone_ttl_seconds the tombstone is purged and all session files
# are deleted from disk.
#
# allow_revival: false
# The session is deleted immediately on expiry along with all its files.
# Reconnecting clients get a fresh empty session.
#
# Optional. Default: true.
allow_revival: true
# How long (in seconds) a tombstoned session's metadata is retained before
# the session and all its files are permanently deleted.
# Only used when allow_revival is true.
# Optional. Default: 86400 (1 day). Allowed: > 0.
tombstone_ttl_seconds: 86400
# How many times the adapter automatically retries an upstream tool call
# after the upstream MCP server signals "Session terminated" — for example
# when a stateful upstream process (Playwright, a long-running container)
# was restarted and lost its own internal session. Each retry first fully
# reconnects the upstream client and then re-issues the original call.
# 0 disables retry entirely; the termination error is returned directly.
# Caution: retrying non-idempotent tools (e.g. form submissions) may cause
# duplicate side-effects. Keep the value low (1-2) for most workloads.
# Optional. Default: 1. Allowed: 0–5.
upstream_session_termination_retries: 1
# Per-session combined storage quota (uploads + artifacts together).
# When adding a new upload or artifact would exceed this limit, the adapter
# first tries to free space by evicting files according to eviction_policy.
# If the quota still cannot be satisfied after eviction the operation fails
# with a clear quota error.
# null disables per-session quota (storage.max_size is the only guard).
# Accepts integer bytes or human-readable string (bytes).
# Optional. Default: null.
max_total_session_size: null
# max_total_session_size: "512Mi"
# Determines which files are evicted first when max_total_session_size is
# reached. Within each category the LRU (least recently accessed) file is
# evicted first.
#
# "lru_uploads_then_artifacts" -- evict uploads first (conservative; uploads
# are typically short-lived staging files). Fall through to artifacts only
# if evicting all uploads is still not enough.
# "lru_artifacts_then_uploads" -- evict artifacts first (useful when artifacts
# are cheap to regenerate but uploads are precious).
#
# Optional. Default: "lru_uploads_then_artifacts".
# Allowed: "lru_uploads_then_artifacts" | "lru_artifacts_then_uploads"
eviction_policy: "lru_uploads_then_artifacts"
uploads¶
multipart file staging
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
enabled | boolean | optional | true | - | - | Master switch. |
max_file_bytes | string | optional | "10Mi" (10 MiB = 10,485,760 bytes). Must be > 0 | - | - | Maximum allowed size of a single uploaded file. |
ttl_seconds | number | optional | 120 | > 0 or null | - | How long (in seconds) uploaded files are retained after their last access before the cleanup loop deletes them. |
require_sha256 | boolean | optional | false | - | - | When true, the client must include a sha256 form field containing the hex-encoded SHA-256 checksum of the file. |
uri_scheme | string | optional | "upload://" | - | - | URI scheme prefix used in the upload handles returned to clients. |
Show example snippet
uploads:
# Master switch. When false the upload endpoint returns 400 for every
# request and upload_consumer adapters will error immediately.
# Optional. Default: true.
enabled: true
# Maximum allowed size of a single uploaded file.
# The adapter streams the upload and aborts with an error if the byte count
# exceeds this limit before the file is fully written.
# Accepts integer bytes or human-readable string (bytes).
# Optional. Default: "10Mi" (10 MiB = 10,485,760 bytes). Must be > 0.
max_file_bytes: "10Mi"
# How long (in seconds) uploaded files are retained after their last
# access before the cleanup loop deletes them. The TTL resets each time
# the upload handle is resolved by an upload_consumer adapter.
# null disables upload expiry (files persist until the session itself expires
# or is manually cleaned up).
# Optional. Default: 120. Allowed: > 0 or null.
ttl_seconds: 120
# When true, the client must include a sha256 form field containing the
# hex-encoded SHA-256 checksum of the file. The adapter verifies it after
# writing and rejects the upload on mismatch.
# Recommended on untrusted networks or when end-to-end integrity matters.
# Optional. Default: false.
require_sha256: false
# URI scheme prefix used in the upload handles returned to clients.
# Clients pass these handles verbatim to upload_consumer-wrapped tools.
# Full handle format: {uri_scheme}sessions/{session_id}/{upload_id}
# Must end with "://". Change only if you need to avoid scheme collisions
# with another system.
# Optional. Default: "upload://".
uri_scheme: "upload://"
artifacts¶
tool-produced file persistence
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
enabled | boolean | optional | true | - | - | Master switch for artifact persistence and resource exposure. |
ttl_seconds | number | optional | 600 (10 minutes) | > 0 or null | - | How long (in seconds) artifact files are retained after their last access before the cleanup loop deletes them. |
max_per_session | null | optional | null | > 0 or null | - | Maximum number of artifact files retained per session. |
expose_as_resources | boolean | optional | true | - | adapters[].expose_as_resource; servers[].adapters[].expose_as_resource | When true, the adapter registers a session-scoped MCP resource provider so clients can list and read artifact files via standard MCP resource operations. |
uri_scheme | string | optional | "artifact://" | - | - | URI scheme prefix for artifact resource URIs. |
Show example snippet
artifacts:
# Master switch for artifact persistence and resource exposure.
# When false, artifact_producer adapters skip persistence entirely and
# return the raw upstream tool result unchanged.
# Optional. Default: true.
enabled: true
# How long (in seconds) artifact files are retained after their last
# access before the cleanup loop deletes them. The TTL resets each time
# the artifact is read via MCP resource or HTTP download.
# null disables artifact expiry (files persist until the session expires).
# Optional. Default: 600 (10 minutes). Allowed: > 0 or null.
ttl_seconds: 600
# Maximum number of artifact files retained per session.
# When a new artifact would exceed this count the allocation fails with
# a clear quota error (no silent eviction; the caller must free space).
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_per_session: null
# When true, the adapter registers a session-scoped MCP resource provider
# so clients can list and read artifact files via standard MCP resource
# operations. Resource URIs have the form:
# {uri_scheme}sessions/{session_id}/{artifact_id}/{filename}
# Resource reads are session-validated; a client can only read its own
# session's artifacts.
# Can be overridden per adapter via adapters[].expose_as_resource.
# Optional. Default: true.
expose_as_resources: true
# URI scheme prefix for artifact resource URIs.
# Full URI format: {uri_scheme}sessions/{session_id}/{artifact_id}/{filename}
# Must end with "://".
# Optional. Default: "artifact://".
uri_scheme: "artifact://"
# Artifact naming/layout behavior is fixed in runtime (not configurable):
# - Layout is always by artifact id:
# {storage.root}/artifacts/sessions/{session_id}/{artifact_id}/{filename}
# - Filenames are always sanitised for filesystem safety.
servers¶
upstream MCP server registrations (REQUIRED, at least one entry). Each entry registers one upstream MCP server. The adapter creates an independent FastMCP proxy for each server, mounted at its mount_path. All server ids must be unique. All mount_paths must be unique and cannot be "/".
| Field | Type | Required | Default | Allowed | Common Overrides | Summary |
|---|---|---|---|---|---|---|
[].id | string | yes | - | - | - | Unique identifier for this server entry. |
[].mount_path | string | yes | - | - | - | HTTP path where this server's MCP proxy is mounted in the adapter. |
[].upstream | object | - | - | - | - | connection to the actual MCP server |
[].upstream.transport | string | optional | "streamable_http" | "streamable_http" | "sse" | - | Transport protocol the upstream MCP server speaks. |
[].upstream.url | string | yes | - | - | - | Full URL of the upstream MCP endpoint. |
[].upstream.insecure_tls | boolean | optional | false | - | - | When true, TLS certificate verification is skipped for upstream connections. |
[].upstream.static_headers | object | optional | {} | - | - | Static HTTP headers injected into every upstream request. |
[].upstream.client_headers | object | - | - | - | - | Client request header policy. |
[].upstream.client_headers.required | array | optional | [] | - | - | Headers the client MUST include on every request to the adapter. |
[].upstream.client_headers.passthrough | array | optional | [] | - | - | Client headers that MAY be forwarded to the upstream server. |
[].tool_defaults | object | - | - | - | - | tool_defaults -- server-level tool-call defaults These values override core.defaults for tools on this upstream server, and can themselves be overridden per adapter via adapters[].overrides. |
[].tool_defaults.tool_call_timeout_seconds | null | optional | null | > 0 or null | inherits core.defaults.tool_call_timeout_seconds | Timeout in seconds for all tool calls on this server. |
[].tool_defaults.allow_raw_output | null | optional | null | - | inherits core.defaults.allow_raw_output | Raw output flag for all adapter-wrapped tools on this server. |
[].code_mode_enabled | null | optional | null | - | inherits core.code_mode_enabled | per-server Code Mode override |
[].shorten_descriptions | null | optional | null | - | inherits core.shorten_descriptions | per-server description-shaping override |
[].short_description_max_tokens | null | optional | null | > 0 or null | inherits core.short_description_max_tokens | Maximum token budget for the first-sentence summary when shortened descriptions are enabled for this server. |
[].tool_description_policy | object | - | - | - | - | per-server description-forwarding override |
[].tool_description_policy.mode | null | optional | null | "preserve", "truncate", "strip", or null | inherits core.tool_description_policy.mode | Override how this server forwards tool and schema descriptions. |
[].tool_description_policy.max_tool_description_chars | null | optional | null | > 0 or null | inherits core.tool_description_policy.max_tool_description_chars | Override the top-level tool description cap for this server. |
[].tool_description_policy.max_schema_description_chars | null | optional | null | > 0 or null | inherits core.tool_description_policy.max_schema_description_chars | Override the schema description cap for this server. |
[].tool_metadata_sanitization | object | - | - | - | - | per-server metadata-sanitization override |
[].tool_metadata_sanitization.mode | null | optional | null | "off", "sanitize", "block", or null | inherits core.tool_metadata_sanitization.mode | Override how this server sanitizes model-visible tool metadata. |
[].tool_metadata_sanitization.normalize_unicode | null | optional | null | - | inherits core.tool_metadata_sanitization.normalize_unicode | Override Unicode normalization for this server. |
[].tool_metadata_sanitization.remove_invisible_characters | null | optional | null | - | inherits core.tool_metadata_sanitization.remove_invisible_characters | Override invisible-character removal for this server. |
[].tool_metadata_sanitization.max_tool_title_chars | null | optional | null | > 0 or null | inherits core.tool_metadata_sanitization.max_tool_title_chars | Override the tool title length cap for this server. |
[].tool_metadata_sanitization.max_tool_description_chars | null | optional | null | > 0 or null | inherits core.tool_metadata_sanitization.max_tool_description_chars | Override the tool description length cap for this server. |
[].tool_metadata_sanitization.max_schema_text_chars | null | optional | null | > 0 or null | inherits core.tool_metadata_sanitization.max_schema_text_chars | Override the schema text length cap for this server. |
[].tool_definition_pinning | object | - | - | - | - | per-server trust-policy override |
[].tool_definition_pinning.mode | null | optional | null | "off", "warn", "block", or null | inherits core.tool_definition_pinning.mode | Override whether this server pins tool definitions for each adapter session. |
[].tool_definition_pinning.block_strategy | null | optional | null | "error", "baseline_subset", or null | inherits core.tool_definition_pinning.block_strategy | Override how block mode behaves for this server. |
[].tool_definition_pinning.block_error_session_action | null | optional | null | "keep", "invalidate", or null | inherits core.tool_definition_pinning.block_error_session_action | Override what block_strategy="error" should do for this server. |
[].disabled_tools | array | optional | [] | - | - | tool-level suppression list |
[].upstream_ping | object | - | - | - | - | upstream_ping -- per-server overrides for the health/circuit-breaker loop Any field set to null (or omitted) falls back to core.upstream_ping. |
[].upstream_ping.enabled | null | optional | null | - | inherits core.upstream_ping.enabled | Override whether ping monitoring is active for this server. |
[].upstream_ping.interval_seconds | null | optional | null | > 0 or null | inherits core.upstream_ping.interval_seconds | Override the ping interval for this server (seconds). |
[].upstream_ping.timeout_seconds | null | optional | null | > 0 or null | inherits core.upstream_ping.timeout_seconds | Override the ping timeout for this server (seconds). |
[].upstream_ping.failure_threshold | null | optional | null | > 0 or null | inherits core.upstream_ping.failure_threshold | Override how many consecutive failures trip the breaker. |
[].upstream_ping.open_cooldown_seconds | null | optional | null | > 0 or null | inherits core.upstream_ping.open_cooldown_seconds | Override how long the breaker stays open before moving to half_open. |
[].upstream_ping.half_open_probe_allowance | null | optional | null | > 0 or null | inherits core.upstream_ping.half_open_probe_allowance | Override how many successful half_open probes close the breaker. |
[].adapters | array | - | - | - | - | request/response interception pipeline for this server |
[].adapters[].type | string | - | - | - | - | upload_consumer adapter Intercepts tool calls whose arguments contain upload:// file handles (returned by the /upload/{server_id} endpoint) and rewrites them to real absolute filesystem paths before forwarding the call upstream. |
[].adapters[].tools | array | yes | - | - | - | Tool names on this server that this adapter should intercept. |
[].adapters[].file_path_argument | string | yes | - | - | - | Argument name (or dot-path for nested objects) that holds the upload:// URI. |
[].adapters[].uri_scheme | string | optional | "upload://". Must end with "://" | - | - | URI scheme the adapter expects in file_path_argument values. |
[].adapters[].uri_prefix | null | optional | null | true, false, or null | - | When true, resolved local filesystem paths are converted to file:// URIs before forwarding to the upstream tool. |
[].adapters[].overrides | object | - | - | - | - | Per-adapter tool-call behaviour overrides. |
[].adapters[].overrides.tool_call_timeout_seconds | null | optional | null (inherit) | > 0 or null | - | servers[].adapters[].overrides.tool_call_timeout_seconds |
[].adapters[].overrides.allow_raw_output | null | optional | null (inherit) | - | - | servers[].adapters[].overrides.allow_raw_output |
[].adapters[].type | string | - | - | - | - | artifact_producer adapter Intercepts tool calls that produce output files (screenshots, PDFs, exports ...) and ensures those files are: 1. |
[].adapters[].tools | array | yes | - | - | - | Tool names on this server that this adapter should intercept. |
[].adapters[].output_path_argument | string | optional | null | - | - | Name of the tool argument that accepts an output file path. |
[].adapters[].output_locator | object | - | - | - | - | How to locate the produced file when output_path_argument is null OR when the tool ignores the supplied path and writes elsewhere. |
[].adapters[].output_locator.mode | string | optional | "none" | "structured" | "regex" | "embedded" | "none" | - | servers[].adapters[].output_locator.mode |
[].adapters[].output_locator.output_path_key | null | conditional | null | - | - | Dot-path into structured_content to extract a filesystem path from. |
[].adapters[].output_locator.output_path_regexes | array | optional | [] | - | - | List of Python regex patterns applied to joined TextContent output. |
[].adapters[].persist | boolean | optional | true | - | - | Whether to persist the located/embedded file into the artifact store. |
[].adapters[].expose_as_resource | boolean | optional | true | - | artifacts.expose_as_resources | Whether to register this artifact as a session-scoped MCP resource, allowing MCP clients to read file bytes via resources/read. |
[].adapters[].allow_raw_output | null | optional | null | - | the | Whether to embed raw file bytes (base64) directly in the tool result alongside the artifact_uri metadata. |
[].adapters[].overrides | object | - | - | - | - | Per-adapter tool-call behaviour overrides. |
[].adapters[].overrides.tool_call_timeout_seconds | null | optional | null (inherit) | > 0 or null | - | servers[].adapters[].overrides.tool_call_timeout_seconds |
[].adapters[].overrides.allow_raw_output | null | optional | null (inherit) | - | - | servers[].adapters[].overrides.allow_raw_output |
Show example snippet
servers:
- # Unique identifier for this server entry.
# Used in upload endpoint paths, health checks, logging, and error messages.
# Cannot be blank. Must be unique across all server entries.
# Required.
id: "playwright"
# HTTP path where this server's MCP proxy is mounted in the adapter.
# MCP clients connect to: http://{host}:{port}{mount_path}
# Cannot be "/". Leading slash added automatically if omitted.
# Trailing slash stripped. Must be unique across all server entries.
# Required.
mount_path: "/mcp/playwright"
# -------------------------------------------------------------------------
# upstream -- connection to the actual MCP server
# -------------------------------------------------------------------------
upstream:
# Transport protocol the upstream MCP server speaks.
# "streamable_http" -- MCP Streamable HTTP (2025-03-26 spec); the modern
# default. Supports SSE streaming within a single
# HTTP endpoint.
# "sse" -- Legacy HTTP+SSE transport (2024-11-05 spec). Use
# only for older servers that have not been updated.
# Optional. Default: "streamable_http".
# Allowed: "streamable_http" | "sse"
transport: "streamable_http"
# Full URL of the upstream MCP endpoint.
# For streamable_http this is the single endpoint that handles both
# POST and GET (e.g. http://host:8931/mcp).
# For sse this is the SSE endpoint URL.
# Required.
url: "http://playwright-mcp:8931/mcp"
# url: "${PLAYWRIGHT_MCP_URL:-http://localhost:8931/mcp}"
# When true, TLS certificate verification is skipped for upstream
# connections. Use only in development / private networks where the
# upstream uses a self-signed certificate. Never use in production.
# Optional. Default: false.
insecure_tls: false
# Static HTTP headers injected into every upstream request.
# Useful for upstream authentication (API keys, bearer tokens).
# Values are sent verbatim; use env interpolation for secrets.
# Optional. Default: {}.
static_headers: {}
# static_headers:
# Authorization: "Bearer ${UPSTREAM_API_KEY}"
# X-Internal-Service: "mcp-adapter"
# Client request header policy.
client_headers:
# Headers the client MUST include on every request to the adapter.
# If any listed header is absent or empty the adapter rejects the
# request with HTTP 400 before forwarding upstream.
# Case-insensitive comparison.
# Optional. Default: [].
required: []
# required: ["X-User-Id"]
# Client headers that MAY be forwarded to the upstream server.
# By default no client headers are forwarded (deny-all policy).
# Adding a header name here allows it to pass through when the
# client sends it. Only explicitly listed headers are forwarded.
# Case-insensitive matching.
# Optional. Default: [].
passthrough: []
# passthrough: ["X-User-Id", "X-Trace-Id"]
# -------------------------------------------------------------------------
# tool_defaults -- server-level tool-call defaults
# -------------------------------------------------------------------------
# These values override core.defaults for tools on this upstream server,
# and can themselves be overridden per adapter via adapters[].overrides.
# Precedence: adapter.overrides > tool_defaults > core.defaults
# A null value means "inherit from the next level up".
tool_defaults:
# Timeout in seconds for all tool calls on this server.
# null inherits from core.defaults.tool_call_timeout_seconds.
# Optional. Default: null. Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Raw output flag for all adapter-wrapped tools on this server.
# null inherits from core.defaults.allow_raw_output.
# Optional. Default: null.
allow_raw_output: null
# -------------------------------------------------------------------------
# code_mode_enabled -- per-server Code Mode override
# -------------------------------------------------------------------------
# null inherits core.code_mode_enabled.
# true collapses this server's visible tool surface into FastMCP Code Mode
# discovery and execute tools only.
# false forces normal direct tool listing for this server even if the
# global core default is enabled.
#
# Optional. Default: null.
code_mode_enabled: null
# -------------------------------------------------------------------------
# shorten_descriptions -- per-server description-shaping override
# -------------------------------------------------------------------------
# null inherits core.shorten_descriptions.
# true keeps only a short semantic summary from upstream descriptions for
# upload_consumer overrides, then appends the adapter workflow guidance.
# false keeps the full upstream description and appends the adapter
# workflow guidance after it.
#
# Optional. Default: null.
shorten_descriptions: null
# Maximum token budget for the first-sentence summary when shortened
# descriptions are enabled for this server.
#
# null inherits core.short_description_max_tokens.
#
# Optional. Default: null. Allowed: > 0 or null.
short_description_max_tokens: null
# -------------------------------------------------------------------------
# tool_description_policy -- per-server description-forwarding override
# -------------------------------------------------------------------------
tool_description_policy:
# Override how this server forwards tool and schema descriptions.
#
# null inherits core.tool_description_policy.mode.
#
# Optional. Default: null.
# Allowed: "preserve", "truncate", "strip", or null.
mode: null
# Override the top-level tool description cap for this server.
#
# null inherits core.tool_description_policy.max_tool_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_description_chars: null
# Override the schema description cap for this server.
#
# null inherits core.tool_description_policy.max_schema_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_schema_description_chars: null
# -------------------------------------------------------------------------
# tool_metadata_sanitization -- per-server metadata-sanitization override
# -------------------------------------------------------------------------
tool_metadata_sanitization:
# Override how this server sanitizes model-visible tool metadata.
#
# null inherits core.tool_metadata_sanitization.mode.
#
# Optional. Default: null.
# Allowed: "off", "sanitize", "block", or null.
mode: null
# Override Unicode normalization for this server.
#
# null inherits core.tool_metadata_sanitization.normalize_unicode.
#
# Optional. Default: null.
normalize_unicode: null
# Override invisible-character removal for this server.
#
# null inherits core.tool_metadata_sanitization.remove_invisible_characters.
#
# Optional. Default: null.
remove_invisible_characters: null
# Override the tool title length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_tool_title_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_title_chars: null
# Override the tool description length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_tool_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_description_chars: null
# Override the schema text length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_schema_text_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_schema_text_chars: null
# -------------------------------------------------------------------------
# tool_definition_pinning -- per-server trust-policy override
# -------------------------------------------------------------------------
tool_definition_pinning:
# Override whether this server pins tool definitions for each adapter
# session.
#
# null inherits core.tool_definition_pinning.mode.
#
# Optional. Default: null.
# Allowed: "off", "warn", "block", or null.
mode: null
# Override how block mode behaves for this server.
#
# null inherits core.tool_definition_pinning.block_strategy.
#
# Optional. Default: null.
# Allowed: "error", "baseline_subset", or null.
block_strategy: null
# Override what block_strategy="error" should do for this server.
#
# null inherits core.tool_definition_pinning.block_error_session_action.
#
# Optional. Default: null.
# Allowed: "keep", "invalidate", or null.
block_error_session_action: null
# -------------------------------------------------------------------------
# disabled_tools -- tool-level suppression list
# -------------------------------------------------------------------------
# A list of tool names or Python regex patterns (re.fullmatch) to exclude
# from this server's MCP proxy. Matched tools are never registered and
# never appear in list_tools responses returned to clients.
#
# Each entry is first compared as a plain exact string; if that does not
# match, it is compiled and applied as a regex. Invalid regex patterns are
# skipped with a warning log and do not prevent the adapter from starting.
#
# Use cases:
# - Remove internal/debug tools exposed by an upstream server.
# - Restrict a sensitive tool in a shared multi-tenant deployment.
# - Suppress the auto-injected upload helper (e.g. "playwright_get_upload_url").
#
# Optional. Default: [].
disabled_tools: []
# disabled_tools:
# - "dangerous_exec_tool" # exact name
# - "^internal_.*" # suppress any tool starting with "internal_"
# - "playwright_get_upload_url" # suppress the auto-injected upload helper
# -------------------------------------------------------------------------
# upstream_ping -- per-server overrides for the health/circuit-breaker loop
# -------------------------------------------------------------------------
# Any field set to null (or omitted) falls back to core.upstream_ping.
# Provide only the fields you want to differ from the global defaults.
upstream_ping:
# Override whether ping monitoring is active for this server.
# null inherits core.upstream_ping.enabled.
# Optional. Default: null.
enabled: null
# Override the ping interval for this server (seconds).
# null inherits core.upstream_ping.interval_seconds.
# Optional. Default: null. Allowed: > 0 or null.
interval_seconds: null
# Override the ping timeout for this server (seconds).
# null inherits core.upstream_ping.timeout_seconds.
# Optional. Default: null. Allowed: > 0 or null.
timeout_seconds: null
# Override how many consecutive failures trip the breaker.
# null inherits core.upstream_ping.failure_threshold.
# Optional. Default: null. Allowed: > 0 or null.
failure_threshold: null
# Override how long the breaker stays open before moving to half_open.
# null inherits core.upstream_ping.open_cooldown_seconds.
# Optional. Default: null. Allowed: > 0 or null.
open_cooldown_seconds: null
# Override how many successful half_open probes close the breaker.
# null inherits core.upstream_ping.half_open_probe_allowance.
# Optional. Default: null. Allowed: > 0 or null.
half_open_probe_allowance: null
# -------------------------------------------------------------------------
# adapters -- request/response interception pipeline for this server
# -------------------------------------------------------------------------
# Each entry wraps one or more upstream tools with adapter logic that runs
# before and/or after the upstream call. Two types are available.
# A tool may appear in only one adapter entry; duplicate registrations for
# the same tool name are silently skipped (first wins).
adapters:
# -----------------------------------------------------------------------
# upload_consumer adapter
# -----------------------------------------------------------------------
# Intercepts tool calls whose arguments contain upload:// file handles
# (returned by the /upload/{server_id} endpoint) and rewrites them to
# real absolute filesystem paths before forwarding the call upstream.
# The upstream tool receives a normal path string and never sees the
# upload:// URI scheme.
#
# Typical use-case: browser_file_upload needs a real on-disk path; client
# stages the file via the upload endpoint and passes the handle as an arg.
# -----------------------------------------------------------------------
- type: "upload_consumer"
# Tool names on this server that this adapter should intercept.
# At least one name is required. Names must match exactly.
# Required.
tools: ["browser_file_upload"]
# Argument name (or dot-path for nested objects) that holds the
# upload:// URI. The adapter reads this argument, resolves the handle,
# and replaces the value with the absolute path before forwarding.
# Supports a single string value OR a list of strings (the adapter
# preserves the shape: string in -> string out, list in -> list out).
# Dot-path example: "options.file" resolves arguments["options"]["file"].
# Required.
file_path_argument: "paths"
# URI scheme the adapter expects in file_path_argument values.
# Must match uploads.uri_scheme. Change if you customised that setting.
# Optional. Default: "upload://". Must end with "://".
uri_scheme: "upload://"
# When true, resolved local filesystem paths are converted to file://
# URIs before forwarding to the upstream tool.
# Use this for upstream tools that require URI-style inputs instead of
# raw absolute paths.
# When false or null, the adapter forwards plain absolute paths.
# Optional. Default: null. Allowed: true, false, or null.
uri_prefix: null
# Per-adapter tool-call behaviour overrides.
# null values inherit the next level up (server then core).
overrides:
# Optional. Default: null (inherit). Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Optional. Default: null (inherit).
allow_raw_output: null
# -----------------------------------------------------------------------
# artifact_producer adapter
# -----------------------------------------------------------------------
# Intercepts tool calls that produce output files (screenshots, PDFs,
# exports ...) and ensures those files are:
# 1. Written into the adapter's managed artifact store.
# 2. Registered with the session under a stable artifact_id.
# 3. Exposed as a session-scoped MCP resource (if expose_as_resource=true).
# 4. Referenced in the tool result metadata via artifact_uri.
#
# Two strategies for capturing the file are available and can be combined:
#
# output_path_argument (preferred when supported by the upstream tool)
# The adapter allocates an artifact path in the store, injects it as
# the value of the specified tool argument, calls the tool, and the
# tool writes its output directly to that path.
#
# output_locator (fallback when the tool cannot accept an output path)
# After the tool returns, the adapter searches the result for the
# file using one of the locator modes below.
# -----------------------------------------------------------------------
- type: "artifact_producer"
# Tool names on this server that this adapter should intercept.
# At least one name is required.
# Required.
tools: ["browser_take_screenshot", "browser_pdf_save"]
# Name of the tool argument that accepts an output file path.
# When set, the adapter:
# 1. Allocates a path under the artifact store.
# 2. Sets arguments[output_path_argument] = <allocated path>.
# 3. Calls the tool (which writes the file to that path).
# 4. Finalises the artifact record.
# Set to null if the upstream tool cannot accept an explicit output path
# and use output_locator instead.
# Optional. Default: null.
output_path_argument: "filename"
# How to locate the produced file when output_path_argument is null
# OR when the tool ignores the supplied path and writes elsewhere.
#
# mode: "none" -- Do not attempt to persist; pass through raw output.
# Use when you only want the tool result unmodified.
#
# mode: "structured" -- Read a filesystem path from the structured output
# using output_path_key as a dot-path into the
# result's structured_content (JSON) dict.
# Example: output_path_key "result.file.path"
# reads structured_content["result"]["file"]["path"]
# Requires output_path_key to be set (non-empty).
#
# mode: "regex" -- Search all TextContent blocks in the tool result
# for a filesystem path using the first matching
# pattern in output_path_regexes. The first capture
# group (if any) is used; otherwise the full match.
# If output_path_regexes is empty, built-in default
# path regexes are used.
#
# mode: "embedded" -- Extract raw bytes directly from the tool result
# content blocks. Checks ImageContent (base64 PNG)
# and EmbeddedResource (BlobResourceContents or
# TextResourceContents) blocks in that order.
# Use when the upstream tool returns file content
# inline rather than writing to disk.
#
# Mode resolution when output_path_argument is also set:
# The adapter first checks whether the tool actually wrote to the
# injected path. If not (tool ignored it), it falls back to the
# output_locator. mode="none" disables this fallback.
#
output_locator:
# Optional. Default: "none".
# Allowed: "structured" | "regex" | "embedded" | "none"
mode: "structured"
# Dot-path into structured_content to extract a filesystem path from.
# Required when mode="structured" and output_path_argument is null.
# Optional otherwise. Default: null.
output_path_key: null
# output_path_key: "path"
# output_path_key: "result.file.path"
# List of Python regex patterns applied to joined TextContent output.
# Patterns are tried in order; the first match wins.
# If the pattern has a capture group, group(1) is used; else group(0).
# Optional. Default: [].
# If empty in regex mode, built-in default path regexes are used.
output_path_regexes: []
# output_path_regexes:
# - "Saved to: (.+\\.pdf)"
# - "/data/shared/\\S+"
# Whether to persist the located/embedded file into the artifact store.
# When false the tool result is returned as-is with no artifact stored.
# Useful when you want the adapter for its timeout/override behaviour
# only, without artifact side-effects.
# Optional. Default: true.
persist: true
# Whether to register this artifact as a session-scoped MCP resource,
# allowing MCP clients to read file bytes via resources/read.
# Overrides artifacts.expose_as_resources on a per-adapter basis.
# Has no effect when artifacts.enabled is false.
# Optional. Default: true.
expose_as_resource: true
# Whether to embed raw file bytes (base64) directly in the tool result
# alongside the artifact_uri metadata.
# Overrides the allow_raw_output chain specifically for this adapter.
# Also accepted as "include_raw_output" (legacy alias).
# null falls through to overrides.allow_raw_output -> server -> core.
# Warning: large files produce very large responses and high memory
# pressure; prefer MCP resource access or HTTP download.
# Optional. Default: null.
allow_raw_output: null
# Per-adapter tool-call behaviour overrides.
# null values inherit the next level up (server then core).
overrides:
# Optional. Default: null (inherit). Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Optional. Default: null (inherit).
allow_raw_output: null
Full template appendix¶
The exact commented YAML template is still included here for copy-paste use and for comments that are too detailed for a table cell.Show full commented template
# =============================================================================
# Remote MCP Adapter - Reference Configuration Template
# =============================================================================
#
# USAGE
# Copy this file to config.yaml and adjust values.
# Run: python -m remote_mcp_adapter [--config config.yaml]
# Or: MCP_ADAPTER_CONFIG=config.yaml python -m remote_mcp_adapter
#
# ENV INTERPOLATION
# Any string value supports ${ENV_VAR} and ${ENV_VAR:-default}.
# Examples:
# token: "${MCP_ADAPTER_TOKEN}"
# url: "${UPSTREAM_HOST:-http://localhost:8931}/mcp"
# The loader will fail with a clear error if the variable is unset and
# no default is provided. There are no silent fallbacks.
#
# OVERRIDE PRECEDENCE (most specific wins)
# adapter.overrides > server.tool_defaults > core.defaults
#
# REQUIRED FIELDS
# The only section that is strictly required is servers[]. Each server entry
# must include id, mount_path, and upstream.url. All other fields have
# safe defaults and can be left out entirely.
#
# BYTE-SIZE VALUES
# Fields marked (bytes) accept an integer (raw bytes) or a human-readable
# string with SI or IEC units. Examples:
# 1000 10K 10KB 10Ki 10KiB
# 5M 50Mi 100Gi 2T
# Units are case-insensitive. SI (K=1000) and IEC (Ki=1024) are
# both supported.
#
# =============================================================================
# =============================================================================
# core -- HTTP server, logging, runtime behaviour
# =============================================================================
core:
# ---------------------------------------------------------------------------
# Network binding
# ---------------------------------------------------------------------------
# IP address the HTTP server binds to.
# Use "0.0.0.0" to listen on all interfaces (common in containers).
# Use "127.0.0.1" to restrict to localhost only (recommended in production
# behind a reverse proxy).
# Also used as the fallback host when determining public_base_url.
# Optional. Default: "0.0.0.0"
host: "0.0.0.0"
# TCP port the HTTP server listens on.
# Optional. Default: 8932. Allowed: 1-65535.
port: 8932
# ---------------------------------------------------------------------------
# Logging
# ---------------------------------------------------------------------------
# Minimum log level for the adapter process.
# Passed directly to uvicorn and Python's logging system.
# Optional. Default: "warning".
# Allowed: "debug", "info", "warning", "error", "critical"
log_level: "warning"
# ---------------------------------------------------------------------------
# Startup readiness wait
# ---------------------------------------------------------------------------
# Maximum seconds to wait during startup for all upstream MCP servers to
# become reachable before the application starts accepting traffic.
# The adapter retries upstream probes with exponential backoff (capped at 5s)
# until either all upstreams respond or this limit is exhausted.
# When the limit is exhausted, the adapter starts anyway in "degraded" mode;
# the /healthz endpoint will report "degraded" until all upstreams recover.
# Set to 0 to skip the wait altogether and start immediately.
# Optional. Default: 60. Allowed: >= 0.
max_start_wait_seconds: 60
# ---------------------------------------------------------------------------
# Background cleanup
# ---------------------------------------------------------------------------
# How often (in seconds) the background cleanup loop runs to remove
# expired uploads, expired artifacts, and idle sessions.
# Set to null to disable background cleanup entirely (manual or external GC).
# The cleanup loop is supervisor-managed and restarts itself on unexpected
# failures.
# Optional. Default: 60. Allowed: > 0 or null.
cleanup_interval_seconds: 60
# ---------------------------------------------------------------------------
# Public base URL
# ---------------------------------------------------------------------------
# External base URL used when creating upload endpoint URLs that are
# returned to MCP clients (e.g., in server-prefixed
# "<server_id>_get_upload_url" tools).
# Derivation order when this is null:
# 1. X-Forwarded-Proto + X-Forwarded-Host headers on the incoming request.
# 2. request.base_url from the current HTTP request.
# 3. http://{core.host}:{core.port} (replacing 0.0.0.0 with 127.0.0.1).
# Always set this explicitly when running behind a reverse proxy or in k8s
# with an ingress so that returned URLs are externally reachable.
# Optional. Default: null.
public_base_url: null
# public_base_url: "https://mcp-adapter.example.com"
# ---------------------------------------------------------------------------
# HTTP artifact download endpoint
# ---------------------------------------------------------------------------
# When true the adapter registers:
# GET /artifacts/{server_id}/{session_id}/{artifact_id}
# This lets clients download raw artifact bytes over HTTP using an
# Mcp-Session-Id header for session validation. The artifact's metadata
# in tool responses will also include a download_url field.
# When false (default) artifacts are only accessible via MCP resources
# (if artifacts.expose_as_resources is true).
# Optional. Default: false.
allow_artifacts_download: false
# ---------------------------------------------------------------------------
# Experimental Code Mode
# ---------------------------------------------------------------------------
# When true, the server exposes FastMCP Code Mode instead of the full direct
# tool list. Clients see a compact meta-surface such as `search`,
# `get_schema`, and `execute`, and use those meta-tools to discover and call
# the real tool catalog on demand.
#
# The underlying tools still exist behind the Code Mode layer. Adapter-
# wrapped tools remain the source of truth, and once an upload_consumer or
# artifact_producer override is registered, the upstream original with the
# same name is hidden so clients do not see duplicate entries.
#
# This is the global default. Individual servers can override it with
# servers[].code_mode_enabled.
#
# Optional. Default: false.
code_mode_enabled: false
# ---------------------------------------------------------------------------
# Tool description shaping
# ---------------------------------------------------------------------------
# When true, adapter-wrapped upload_consumer tools keep only a short semantic
# summary from the upstream description, then append the adapter workflow
# instructions. This keeps descriptions smaller for weaker models while still
# preserving enough signal to distinguish similar tools.
#
# When false, the full upstream description is kept and the adapter guidance
# is appended after it.
#
# Individual servers can override this with servers[].shorten_descriptions.
#
# Optional. Default: false.
shorten_descriptions: false
# Maximum token budget used when core.shorten_descriptions=true or when a
# server override enables shortened descriptions. Only the first upstream
# sentence is considered, then it is trimmed to this many tokens.
#
# Individual servers can override this with
# servers[].short_description_max_tokens.
#
# Optional. Default: 16. Allowed: > 0.
short_description_max_tokens: 16
# ---------------------------------------------------------------------------
# Tool metadata sanitization
# ---------------------------------------------------------------------------
# Apply a conservative sanitization pass to model-visible tool metadata
# before it reaches the client. This affects tool title, description text and
# schema title, description fields that models can actually read.
#
# "off" -> forward metadata as-is.
# "sanitize" -> normalize/sanitize the visible text fields and log when
# changes were required.
# "block" -> hide tools whose visible metadata would have required
# sanitization instead of forwarding the modified version.
#
# Individual servers can override this with
# servers[].tool_metadata_sanitization.*.
tool_metadata_sanitization:
# Optional. Default: "sanitize".
# Allowed: "off", "sanitize", "block"
mode: "sanitize"
# Apply Unicode NFKC normalization to model-visible metadata text.
#
# Optional. Default: true.
normalize_unicode: true
# Remove zero-width / invisible formatting characters from model-visible
# tool metadata text.
#
# Optional. Default: true.
remove_invisible_characters: true
# Maximum forwarded length for tool titles.
#
# Optional. Default: 256. Allowed: > 0 or null.
max_tool_title_chars: 256
# Maximum forwarded length for top-level tool descriptions.
#
# Optional. Default: 2000. Allowed: > 0 or null.
max_tool_description_chars: 2000
# Maximum forwarded length for schema title/description text fields.
#
# Optional. Default: 1000. Allowed: > 0 or null.
max_schema_text_chars: 1000
# ---------------------------------------------------------------------------
# Tool description policy
# ---------------------------------------------------------------------------
# Control how much description prose from upstream tools should be forwarded
# to the client. This applies to top-level tool descriptions and schema
# description fields across the whole visible tool catalog.
#
# The policy runs before Code Mode. If Code Mode is enabled, its discovery
# and execute tools inherit the same description surface instead of bypassing
# this policy.
#
# This is intentionally separate from tool_metadata_sanitization:
#
# - tool_metadata_sanitization cleans suspicious text
# - tool_description_policy decides how much description prose is forwarded
#
# "preserve" -> keep descriptions after earlier sanitization passes.
# "truncate" -> keep only the first N characters.
# "strip" -> remove description text entirely.
#
# Individual servers can override this with
# servers[].tool_description_policy.*.
tool_description_policy:
# Optional. Default: "preserve".
# Allowed: "preserve", "truncate", "strip"
mode: "preserve"
# Maximum forwarded length for top-level tool descriptions when
# mode="truncate".
#
# Optional. Default: 280. Allowed: > 0 or null.
max_tool_description_chars: 280
# Maximum forwarded length for schema description fields when
# mode="truncate".
#
# Optional. Default: 280. Allowed: > 0 or null.
max_schema_description_chars: 280
# ---------------------------------------------------------------------------
# Tool-definition pinning
# ---------------------------------------------------------------------------
# Protect the client-visible tool catalog from mid-session definition drift.
# On the first catalog exposure for a given Mcp-Session-Id, the adapter pins
# the visible tool definitions for that session. Later changes from the
# upstream server are then detected and handled according to the selected
# policy.
#
# This is useful when you do not want a tool to look harmless during initial
# review and then quietly change description or schema mid-session.
#
# Legitimate upstream upgrades are still allowed, but they require a fresh
# adapter session (a new Mcp-Session-Id). The adapter does not auto-repin in
# the middle of an existing session.
#
# Individual servers can override this with
# servers[].tool_definition_pinning.mode and
# servers[].tool_definition_pinning.block_strategy and
# servers[].tool_definition_pinning.block_error_session_action.
tool_definition_pinning:
# How the adapter should react when a later tool catalog differs from the
# pinned baseline for the same session.
#
# "off" -> do not pin or compare tool definitions.
# "warn" -> allow the new catalog, but annotate returned tool descriptions
# with a session-wide warning and more specific warnings for
# changed/new tools.
# "block" -> detect drift and then either return an MCP error or only the
# still-trusted unchanged subset (see block_strategy below).
#
# Optional. Default: "warn".
# Allowed: "off", "warn", "block"
mode: "warn"
# What "block" mode should do after drift is detected.
#
# "error" -> fail the catalog request and fail direct calls to drifted
# tools with an explicit error.
# "baseline_subset" -> keep serving only unchanged pinned tools and hide
# changed/new/removed tools from that session.
#
# Optional. Default: "error".
# Allowed: "error", "baseline_subset"
block_strategy: "error"
# When block_strategy="error", decide whether the adapter should keep the
# current session alive or invalidate it immediately after drift is
# detected.
#
# "keep" -> return the blocking error, but leave the session alive so the
# client can keep receiving the same error until it reconnects.
# "invalidate" -> turn the session into a terminal tombstone immediately.
# Any later reuse of the same Mcp-Session-Id is rejected
# until the tombstone expires, which forces the client to
# start a fresh adapter session.
#
# "invalidate" is the safer default because it turns legitimate upstream
# upgrades into an explicit session-boundary event instead of leaving a
# half-trusted session around.
#
# Optional. Default: "invalidate".
# Allowed: "keep", "invalidate"
block_error_session_action: "invalidate"
# ---------------------------------------------------------------------------
# Upload endpoint path
# ---------------------------------------------------------------------------
# Base HTTP path for the multipart file upload endpoint.
# The actual per-server route is: {upload_path}/{server_id}
# For example with upload_path="/upload" and server id "playwright":
# POST /upload/playwright (with Mcp-Session-Id header)
# A leading slash is added automatically if omitted. Trailing slash will be removed.
# Cannot be blank.
# Optional. Default: "/upload".
upload_path: "/upload"
# ---------------------------------------------------------------------------
# Upstream metadata cache
# ---------------------------------------------------------------------------
# TTL in seconds for cached upstream metadata list calls
# (`list_tools`, `list_resources`, `list_resource_templates`, `list_prompts`)
# on each session-pinned upstream client.
#
# Why this exists:
# - MCP clients often open resource/tool browsers repeatedly.
# - FastMCP aggregate providers can trigger multiple provider lookups for a
# single read/list operation.
# - Without a short cache, repeated upstream roundtrips can add noticeable UI
# latency even on localhost.
#
# Set to 0 to disable metadata caching entirely.
# Optional. Default: 300. Allowed: >= 0.
upstream_metadata_cache_ttl_seconds: 300
# ---------------------------------------------------------------------------
# Adapter-level authentication
# ---------------------------------------------------------------------------
auth:
# Whether to enforce token-based authentication on every inbound HTTP request
# to the adapter. When true, each request must include the configured header
# (see header_name below) whose value must exactly match the configured token.
# Requests that omit the header or send the wrong value are rejected with HTTP 401.
# When false, all requests are accepted with zero auth checks — only safe on
# localhost or in fully private, trusted networks.
# Strongly recommended to enable in any environment reachable over a network.
# Optional. Default: false.
enabled: false
# Name of the HTTP header that clients must include on every request.
# The adapter looks up this header (case-insensitive name match) and then
# compares its value exactly (case-sensitive) against auth.token.
# Example: with the default name, clients send:
# X-Mcp-Adapter-Auth-Token: <your-secret-token>
# Optional. Default: "X-Mcp-Adapter-Auth-Token".
header_name: "X-Mcp-Adapter-Auth-Token"
# The secret token value that clients must send in the auth header.
# The incoming header value is compared exactly (case-sensitive) to this string.
# Required when auth.enabled is true — the adapter refuses to start if
# enabled=true and this is blank or null.
# Never commit the actual token to source control; use env interpolation instead.
# Optional (required when enabled=true). Default: null.
token: null
# token: "${MCP_ADAPTER_TOKEN}"
# How long (in seconds) a signed upload URL stays valid after being issued by
# the `<server_id>_get_upload_url` MCP tool.
# When auth is enabled, the `get_upload_url` tool embeds a short-lived
# HMAC-SHA256 signature in the upload URL. The /upload/{server_id} endpoint
# validates this signature, rejecting expired or tampered URLs with HTTP 401.
# Each signed URL is one-time use; after it is consumed or expired it cannot
# be reused. This lets MCP clients upload files without needing to know or pass
# the main auth token themselves.
# Optional. Default: 120. Allowed: > 0.
signed_upload_ttl_seconds: 120
# Optional dedicated secret used to compute HMAC-SHA256 signatures on signed
# upload URLs (see signed_upload_ttl_seconds above).
# When null, auth.token is used as the signing secret — no separate value needed.
# Set this to a different random secret when you want to rotate upload-URL
# signatures independently of the main auth token, or to invalidate all
# outstanding signed upload URLs without changing the main token.
# Cannot be blank when set (use null to fall back to auth.token instead).
# Never commit the actual secret to source control; use env interpolation instead.
# Optional. Default: null.
signing_secret: null
# signing_secret: "${MCP_ADAPTER_SIGNING_SECRET}"
# ---------------------------------------------------------------------------
# CORS
# ---------------------------------------------------------------------------
# Only relevant when JavaScript clients in browsers call the adapter directly.
# If clients are server-to-server or go through a proxy that handles CORS,
# leave this disabled.
cors:
# Whether to add CORS response headers at all.
# Optional. Default: false.
enabled: false
# List of origins allowed to make cross-origin requests.
# An empty list combined with enabled=true effectively blocks all origins.
# Use ["*"] to allow any origin (not recommended with allow_credentials=true).
# Optional. Default: [].
allowed_origins: []
# allowed_origins: ["https://app.example.com", "https://staging.example.com"]
# HTTP methods permitted in CORS pre-flight responses.
# Optional. Default: ["POST", "GET", "OPTIONS"].
allowed_methods: ["POST", "GET", "OPTIONS"]
# Headers permitted in cross-origin requests.
# ["*"] allows any header.
# Optional. Default: ["*"].
allowed_headers: ["*"]
# Whether to allow cookies or credentials in cross-origin requests.
# Must be false when allowed_origins contains "*".
# Optional. Default: false.
allow_credentials: false
# ---------------------------------------------------------------------------
# Global tool-call defaults
# ---------------------------------------------------------------------------
# These values apply to every proxied tool call unless overridden at the
# server (servers[].tool_defaults) or adapter level (adapters[].overrides).
# Precedence: adapter.overrides > server.tool_defaults > core.defaults
defaults:
# Timeout in seconds for upstream tool calls.
# null means no timeout (waits indefinitely -- not recommended).
# Optional. Default: 60. Allowed: > 0 or null.
tool_call_timeout_seconds: 60
# When true, artifact_producer adapters include the raw file bytes
# (base64-encoded) directly inside the MCP tool response.
# This is bandwidth-intensive and memory-heavy for large files; prefer
# MCP resource access (artifact://) and/or HTTP download instead.
# Can be overridden per-server and per-adapter.
# Optional. Default: false.
allow_raw_output: false
# ---------------------------------------------------------------------------
# Active upstream health monitoring and circuit breaker
# ---------------------------------------------------------------------------
# The adapter runs a background ping loop for each configured upstream server.
# Failed pings increase a consecutive-failure counter. When the counter
# reaches failure_threshold the circuit breaker goes to "open" state and all
# proxy requests to that upstream are rejected immediately with HTTP 503.
# After open_cooldown_seconds, the breaker moves to "half_open" and lets
# half_open_probe_allowance probe requests through. If those probes succeed
# the breaker closes; if they fail, it reopens.
# Per-server overrides are under servers[].upstream_ping.
upstream_ping:
# Whether to run the ping loop at all.
# When false, no background pinging occurs and the circuit breaker is
# always "closed" (requests are never blocked by health state).
# Optional. Default: true.
enabled: true
# Seconds between consecutive upstream ping attempts.
# Lower values detect failures faster but add more upstream load.
# Optional. Default: 15. Allowed: > 0.
interval_seconds: 15
# Seconds to wait for an upstream ping response before counting it a failure.
# Should be well below interval_seconds.
# Optional. Default: 5. Allowed: > 0.
timeout_seconds: 5
# Number of consecutive ping failures required to open the circuit breaker.
# A value of 1 opens the breaker on the first failure (aggressive).
# A value of 3 (default) tolerates transient blips.
# Optional. Default: 3. Allowed: > 0.
failure_threshold: 3
# Seconds the breaker stays in "open" (blocking) state before attempting
# recovery probes in "half_open" state.
# Optional. Default: 30. Allowed: > 0.
open_cooldown_seconds: 30
# Number of consecutive successful probe requests needed in "half_open"
# state before the breaker returns to fully "closed" (healthy).
# Optional. Default: 2. Allowed: > 0.
half_open_probe_allowance: 2
# =============================================================================
# telemetry -- OpenTelemetry export (metrics + optional logs)
# =============================================================================
telemetry:
# Master switch for all telemetry export. When false, no telemetry providers
# are initialized and no OTLP traffic is emitted.
# Optional. Default: false.
enabled: false
# OTLP transport protocol.
# - grpc: OTLP/gRPC exporter (default)
# - http: OTLP/HTTP protobuf exporter
# Optional. Default: "grpc".
# Allowed: "grpc", "http"
transport: "grpc"
# Metrics OTLP endpoint.
# Defaults when null:
# - grpc: http://localhost:4317
# - http: http://localhost:4318/v1/metrics
# Use https://... for TLS endpoints.
# Cannot be blank when set.
# Optional. Default: null (protocol-specific default).
# Allowed: null or non-empty URL string.
endpoint: null
# Optional dedicated OTLP endpoint for logs when emit_logs=true and
# transport="http". If null, defaults to http://localhost:4318/v1/logs.
# Ignored for grpc transport (grpc uses telemetry.endpoint).
# Use https://... for TLS endpoints.
# Cannot be blank when set.
# Optional. Default: null.
# Allowed: null or non-empty URL string.
logs_endpoint: null
# TLS behavior for OTLP/gRPC transport.
# - true -> insecure/plaintext gRPC channel (no TLS)
# - false -> secure/TLS gRPC channel
# Ignored for transport="http" (HTTP exporter TLS is controlled by using
# https:// endpoint URLs).
# Note: custom CA/client certificate files are not currently exposed as
# adapter config knobs; exporter uses runtime/system trust configuration.
# Optional. Default: true.
insecure: true
# Extra OTLP headers sent on every export request.
# Commonly used for vendor auth tokens and tenant scoping headers.
# Example:
# headers:
# Authorization: "Bearer ${OTEL_TOKEN}"
# Optional. Default: {}.
# Allowed: object map of string->string.
headers: {}
# Export cadence for metrics reader.
# Optional. Default: 15. Allowed: > 0.
export_interval_seconds: 15
# Export timeout for OTLP exporter operations.
# Optional. Default: 10. Allowed: > 0.
export_timeout_seconds: 10
# Internal async queue sizing for telemetry events.
# Optional. Default: 5000. Allowed: > 0.
max_queue_size: 5000
# Max telemetry events processed per worker drain cycle.
# Higher values reduce per-event overhead; lower values reduce event-loop
# monopolization under burst load.
# This controls only the adapter's internal telemetry event queue drain
# behavior, not OTLP exporter batch size.
# Optional. Default: 256. Allowed: > 0.
queue_batch_size: 256
# Periodic force-flush cadence (seconds) for telemetry providers.
# Also acts as the worker wake interval while idle.
# This does not replace metrics export_interval_seconds; that is still the
# reader's collection/export schedule.
# Optional. Default: 5. Allowed: > 0.
periodic_flush_seconds: 5
# Grace period for draining queued telemetry events during app shutdown.
# Optional. Default: 10. Allowed: > 0.
shutdown_drain_timeout_seconds: 10
# When true and queue is full, telemetry events are dropped instead of
# blocking request processing.
# Optional. Default: true.
drop_on_queue_full: true
# Force flush telemetry providers during normal app shutdown.
# Optional. Default: true.
flush_on_shutdown: true
# Register a best-effort interpreter termination hook that drains pending
# telemetry events and force-flushes providers.
# Optional. Default: true.
flush_on_terminate: true
# Whether application logs should also be exported as OTel log records.
# Off by default: logs remain local-only unless enabled here.
# Optional. Default: false.
emit_logs: false
# Optional BatchLogRecordProcessor tuning when emit_logs=true.
# Leave null to use OpenTelemetry SDK defaults.
# Max in-memory queue size for the OTel log batch processor itself.
# Increase for very bursty logging to reduce drop risk, at the cost of RAM.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_max_queue_size: null
# Maximum number of log records exported in one OTel log batch.
# Larger batches can improve throughput; smaller batches can reduce burst
# latency and per-export payload size.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_max_export_batch_size: null
# Delay (milliseconds) between scheduled OTel log batch exports.
# Lower values push logs out sooner; higher values batch more aggressively.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_schedule_delay_millis: null
# Timeout (milliseconds) allowed for one OTel log export operation.
# Optional. Default: null (SDK default). Allowed: > 0 or null.
log_batch_export_timeout_millis: null
# OTel resource attributes for service identity.
# Cannot be blank.
# Optional. Default: "remote-mcp-adapter".
service_name: "remote-mcp-adapter"
# Optional namespace for service grouping in observability backends.
# Blank/empty values are normalized to null.
# Optional. Default: null.
service_namespace: null
# =============================================================================
# state_persistence -- adapter metadata durability
# =============================================================================
state_persistence:
# Storage backend for adapter metadata, including session records, upload handles,
# and artifact descriptors. This does not affect where actual file bytes are stored.
# Files are always located on the filesystem under storage.root.
#
# "memory" - in-process dictionary. Fastest option; no durability. All state is lost
# on process restart. Suitable for temporary development and testing only.
# Combine with disk.local_path and snapshot_interval_seconds to
# periodically save state so planned restarts can reload it.
# "disk" - SQLite database stored on the local filesystem (default). Durable
# across single-node restarts. Not safe for concurrent writes
# from multiple hosts; use "redis" for multi-pod setups.
# "redis" - Shared Redis store. Required when multiple adapter replicas
# share a single session namespace. Set redis.host.
# Optional. Default: "disk".
# Allowed: "memory", "disk", "redis"
type: "disk"
# When true, any saved metadata is discarded at startup, and the adapter
# starts with an entirely empty in-memory state. Existing files under
# storage.root are not deleted; only the metadata mappings are cleared.
# When false (default), the adapter restores in-memory state from the
# configured backend, allowing sessions and artifacts to survive planned restarts.
# Note: if reconciliation.mode is set to "always," the reconciliation backfill runs
# even when refresh_on_startup is true.
# Optional. Default: false.
refresh_on_startup: false
# How often (in seconds) the running in-memory state is saved to disk.
# Only relevant when type is "memory" and disk.local_path is configured.
# In that case, the adapter writes a SQLite snapshot at this interval
# to enable recovery after a planned restart.
# For type "disk" and type "redis," changes are written synchronously on every mutation
# and do not use this interval.
# Optional. Default: 30. Allowed: greater than 0.
snapshot_interval_seconds: 30
# Behavior when the configured persistence backend becomes unreachable or
# fails during runtime after the adapter has started successfully.
#
# "fail_closed" - keep the process running but reject all stateful
# operations (tool calls, uploads, artifact reads) that need the persistence layer.
# /healthz reports "degraded." This is a safe default, posing no risk of data corruption,
# requiring the operator to fix the backend.
#
# "exit" - terminate the process immediately so an orchestrator
# (Kubernetes, systemd, Docker restart policy) can restart it. Use this option when hard restarts are preferred
# over a degraded service window.
#
# "fallback_memory" - silently continue serving traffic using the last
# known in-memory state. New changes are not saved while the backend is down;
# restarting the process during an outage will lose those changes.
# This option should be used only when maximum availability is prioritized over durability.
#
# Optional. Default: "fail_closed".
# Allowed: "fail_closed", "exit", "fallback_memory"
unavailable_policy: "fail_closed"
# Startup reconciliation - scan storage.root for files that lack matching
# metadata entries. This is useful when moving from an in-memory-only setup
# (where metadata was never saved) or recovering from a crash when a file was
# written but the metadata commit did not finish.
reconciliation:
# "disabled" - never reconcile from the filesystem at startup.
# "if_empty" - reconcile only when the backend has zero sessions and zero
# tombstones (this is a safe default that prevents re-import on normal
# restarts where the backend already has data).
# "always" - reconcile on every startup, adding newly discovered
# orphan files without removing existing metadata entries.
# This runs even when refresh_on_startup is true.
# Optional. Default: "if_empty".
# Allowed: "disabled", "if_empty", "always"
mode: "if_empty"
# Server ID used to attribute legacy files when there's not enough information to
# automatically determine ownership. This is common in multi-server
# setups where legacy file paths do not include a server-id component.
# When null:
# • If exactly one server is configured, that server is the fallback owner.
# • If multiple servers are configured, ambiguous sessions are skipped.
# Must match one of the configured servers[].id values when set.
# Optional. Default: null.
legacy_server_id: null
# ---------------------------------------------------------------------------
# Disk backend (relevant when type is "disk" or "memory")
# ---------------------------------------------------------------------------
disk:
# Path to the SQLite metadata database on the local filesystem.
# type="disk" → primary durable store; all changes committed here.
# type="memory" → target for periodic snapshots; loaded at startup if present.
# When null, defaults to: {storage.root}/state/adapter_state.sqlite3
# The parent directory is created automatically if it is missing.
# Optional. Default: null (automatically derived from storage.root).
local_path: null
# local_path: "/data/shared/state/adapter_state.sqlite3"
# SQLite WAL mode for the disk backend.
# When true, SQLite uses WAL journaling, allowing concurrent readers
# alongside a writer and improving throughput under mixed read/write load.
# Set to false only on filesystems that do not support SQLite WAL mode
# (for example, some NFS/SMB mounts), which will force DELETE journal mode.
# Optional. Default: true.
wal:
enabled: true
# ---------------------------------------------------------------------------
# Redis backend (relevant when type is "redis")
# ---------------------------------------------------------------------------
redis:
# Hostname or IP address of the Redis server.
# Required when state_persistence.type="redis".
# Optional otherwise. Default: null.
host: null
# host: "redis"
# host: "${REDIS_HOST:-redis}"
# TCP port of the Redis server.
# Optional. Default: 6379. Allowed: 1 to 65535.
port: 6379
# Redis logical database index. Use a dedicated index (e.g., 1 or 2) to
# separate adapter keys from other applications sharing the same Redis instance.
# Optional. Default: 0. Allowed: greater than or equal to 0.
db: 0
# Redis ACL username for Redis version 6 and above.
# Leave null if using the legacy requirepass-only setup.
# Optional. Default: null.
username: null
# username: "${REDIS_USERNAME}"
# Redis AUTH password. Works with both legacy requirepass and ACL authentication.
# Optional. Default: null.
password: null
# password: "${REDIS_PASSWORD}"
# When true, TLS certificate verification is bypassed for the Redis
# connection. Use this only in development with self-signed certificates.
# Never enable in production, as this exposes all adapter state to potential attacks.
# Optional. Default: false.
tls_insecure: false
# Key namespace prefix for all Redis keys created by this adapter.
# This prevents key collisions when multiple adapter instances or other
# services share the same Redis instance or database index.
# Change this to a unique value for each independent adapter deployment.
# Cannot be blank.
# Optional. Default: "mcp_remote_adapter".
key_base: "mcp_remote_adapter"
# Seconds between Redis PING health-check calls made by the Redis client.
# A failing ping triggers the unavailable_policy response if it persists.
# Optional. Default: 5. Allowed: > 0.
ping_seconds: 5
# =============================================================================
# storage -- shared filesystem layout and file-write behaviour
# =============================================================================
#
# This section governs where uploaded and artifact files are physically stored,
# how large the store can grow, how concurrent writes are coordinated, and how
# orphan files are identified and cleaned up.
#
# Directory structure created automatically under `root`:
# {root}/uploads/sessions/{session_id}/{upload_id}/{original_filename}
# {root}/artifacts/sessions/{session_id}/{artifact_id}/{sanitized_filename}
# {root}/state/adapter_state.sqlite3 (default disk persistence database)
#
storage:
# Root directory on a persistent or shared volume.
# Must survive container restarts. In containerized deployments, mount a
# persistent volume here. For multi-replica and multi-pod deployments, use a
# shared network volume such as NFS, CephFS, AWS EFS, or GCS FUSE so all
# replicas read and write the same storage tree.
# Optional. Default: "/data/shared".
root: "/data/shared"
# Maximum total byte footprint allowed across all files under storage.root
# (uploads plus artifacts combined). When a new write would exceed this limit,
# the adapter rejects the operation with a quota error instead of filling the
# volume and causing an out-of-disk crash.
# Null means no software-enforced limit; rely on the filesystem or block
# storage quota instead.
# Accepts integer bytes or a human-readable byte-size string.
# Optional. Default: null.
max_size: null
# max_size: "50Gi"
# When true, every file write follows write-to-temp, then fsync, and finally atomic rename.
# The destination path isn't touched until the rename completes, so
# readers always see either the previous complete file or the new complete
# file, never a partial write. If the process crashes mid-write, the temp
# file is left behind and cleaned up by the orphan sweeper.
# Disabling this makes writes slightly faster but risks torn files during crashes.
# Only disable in temporary development environments with no durability requirement.
# Optional. Default: true.
atomic_writes: true
# Whether the background cleanup loop should remove orphan files.
# An orphan is any file under uploads or artifacts that has no matching
# record in the adapter's persistence metadata. Orphans accumulate after
# crashes where the file was written but the metadata commit didn't finish
# or when atomic_writes is true and leaves a temp file after a mid-write crash.
# The sweeper only deletes files older than orphan_sweeper_grace_seconds
# to prevent racing with in-progress writes not yet committed to metadata.
# Optional. Default: true.
orphan_sweeper_enabled: true
# Minimum file age in seconds before an unreferenced file can be deleted as an orphan.
# This grace period ensures the sweeper doesn't delete files actively being written
# by a concurrent request that hasn't yet committed its metadata record.
# Set to 0 for immediate orphan cleanup (safe only in single-worker setups
# with synchronous metadata commits and atomic_writes set to true).
# Optional. Default: 300. Allowed: >= 0.
orphan_sweeper_grace_seconds: 300
# Cross-process write concurrency strategy for file operations.
# Choose the mode that matches your deployment setup:
#
# "none" -- No locking. Safe only for a single uvicorn worker process
# with no concurrent write operations that can collide. Highest
# raw throughput.
#
# "process" -- asyncio-level in-process lock keyed on file path. Safe for
# a single uvicorn worker running many coroutines at once.
# Does not protect across separate OS processes.
#
# "file" -- OS-level fcntl/flock advisory lock (default). Safe for
# multiple uvicorn workers on the same host (with --workers N).
# Not safe across separate hosts; each host locks its own
# local file descriptor rather than a shared resource.
#
# "redis" -- Distributed lock stored in Redis. Safe for multi-host or
# multi-pod deployments sharing the same storage volume.
# Requires state_persistence.type set to "redis". The adapter will not
# start with lock_mode set to "redis" if type is not "redis".
#
# "auto" -- Resolved at startup: "redis" when state_persistence.type is
# "redis", otherwise "file". Recommended when you want the
# lock strategy to automatically follow the persistence choice.
#
# Optional. Default: "auto".
# Allowed: "none" | "process" | "file" | "redis" | "auto"
lock_mode: "auto"
# Controls which filesystem paths the artifact_producer adapter can use
# as the source when copying or moving files into the artifact store
# (applies to output_locator modes "structured" and "regex").
#
# "storage_only" -- Source paths must already be under storage.root.
# Use this when the upstream tool writes files
# to a path inside the shared storage volume.
# "allow_configured_roots" -- Source paths may also be under any path listed
# in artifact_locator_allowed_roots. Use this
# when the upstream tool writes files to a known
# path outside storage.root (for example, /tmp or a
# tool-specific working directory).
#
# Optional. Default: "storage_only".
# Allowed: "storage_only" | "allow_configured_roots"
artifact_locator_policy: "storage_only"
# Additional filesystem root prefixes the artifact locator can read source files from.
# Only meaningful when artifact_locator_policy is "allow_configured_roots".
# The adapter will not start if the policy requires this list but it is empty.
# Optional (required when policy is "allow_configured_roots"). Default: [].
artifact_locator_allowed_roots: []
# artifact_locator_allowed_roots:
# - "/tmp"
# - "/app/tool-outputs"
# =============================================================================
# sessions -- lifecycle and concurrency limits
# =============================================================================
sessions:
# Maximum number of concurrent active sessions across all servers.
# A "session" maps 1-to-1 to an MCP client connection (identified by the
# Mcp-Session-Id header). Once the limit is reached, new sessions receive
# HTTP 429 until an existing session expires or is cleaned up.
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_active: null
# Maximum number of in-flight tool calls allowed simultaneously within a
# single session. Excess requests receive HTTP 429.
# Useful to prevent a single session from monopolising upstream workers.
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_in_flight_per_session: null
# Seconds of inactivity after which a session is considered idle and
# eligible for expiry by the cleanup loop. "Activity" is any tool call or
# upload that touches the session.
# A session is only expired when in_flight == 0 (no active requests).
# null disables idle expiry entirely (sessions live until process restart).
# Optional. Default: null. Allowed: > 0 or null.
idle_ttl_seconds: null
# idle_ttl_seconds: 21600 # 6 hours
# When a session expires due to idle_ttl_seconds, two behaviours are possible:
#
# allow_revival: true (default)
# The session is "tombstoned" -- its in-memory metadata is preserved in a
# lightweight tombstone for tombstone_ttl_seconds. If the same client
# reconnects within that window the session is revived transparently
# (uploads/artifacts still accessible if not yet expired by their own TTLs).
# After tombstone_ttl_seconds the tombstone is purged and all session files
# are deleted from disk.
#
# allow_revival: false
# The session is deleted immediately on expiry along with all its files.
# Reconnecting clients get a fresh empty session.
#
# Optional. Default: true.
allow_revival: true
# How long (in seconds) a tombstoned session's metadata is retained before
# the session and all its files are permanently deleted.
# Only used when allow_revival is true.
# Optional. Default: 86400 (1 day). Allowed: > 0.
tombstone_ttl_seconds: 86400
# How many times the adapter automatically retries an upstream tool call
# after the upstream MCP server signals "Session terminated" — for example
# when a stateful upstream process (Playwright, a long-running container)
# was restarted and lost its own internal session. Each retry first fully
# reconnects the upstream client and then re-issues the original call.
# 0 disables retry entirely; the termination error is returned directly.
# Caution: retrying non-idempotent tools (e.g. form submissions) may cause
# duplicate side-effects. Keep the value low (1-2) for most workloads.
# Optional. Default: 1. Allowed: 0–5.
upstream_session_termination_retries: 1
# Per-session combined storage quota (uploads + artifacts together).
# When adding a new upload or artifact would exceed this limit, the adapter
# first tries to free space by evicting files according to eviction_policy.
# If the quota still cannot be satisfied after eviction the operation fails
# with a clear quota error.
# null disables per-session quota (storage.max_size is the only guard).
# Accepts integer bytes or human-readable string (bytes).
# Optional. Default: null.
max_total_session_size: null
# max_total_session_size: "512Mi"
# Determines which files are evicted first when max_total_session_size is
# reached. Within each category the LRU (least recently accessed) file is
# evicted first.
#
# "lru_uploads_then_artifacts" -- evict uploads first (conservative; uploads
# are typically short-lived staging files). Fall through to artifacts only
# if evicting all uploads is still not enough.
# "lru_artifacts_then_uploads" -- evict artifacts first (useful when artifacts
# are cheap to regenerate but uploads are precious).
#
# Optional. Default: "lru_uploads_then_artifacts".
# Allowed: "lru_uploads_then_artifacts" | "lru_artifacts_then_uploads"
eviction_policy: "lru_uploads_then_artifacts"
# =============================================================================
# uploads -- multipart file staging
# =============================================================================
uploads:
# Master switch. When false the upload endpoint returns 400 for every
# request and upload_consumer adapters will error immediately.
# Optional. Default: true.
enabled: true
# Maximum allowed size of a single uploaded file.
# The adapter streams the upload and aborts with an error if the byte count
# exceeds this limit before the file is fully written.
# Accepts integer bytes or human-readable string (bytes).
# Optional. Default: "10Mi" (10 MiB = 10,485,760 bytes). Must be > 0.
max_file_bytes: "10Mi"
# How long (in seconds) uploaded files are retained after their last
# access before the cleanup loop deletes them. The TTL resets each time
# the upload handle is resolved by an upload_consumer adapter.
# null disables upload expiry (files persist until the session itself expires
# or is manually cleaned up).
# Optional. Default: 120. Allowed: > 0 or null.
ttl_seconds: 120
# When true, the client must include a sha256 form field containing the
# hex-encoded SHA-256 checksum of the file. The adapter verifies it after
# writing and rejects the upload on mismatch.
# Recommended on untrusted networks or when end-to-end integrity matters.
# Optional. Default: false.
require_sha256: false
# URI scheme prefix used in the upload handles returned to clients.
# Clients pass these handles verbatim to upload_consumer-wrapped tools.
# Full handle format: {uri_scheme}sessions/{session_id}/{upload_id}
# Must end with "://". Change only if you need to avoid scheme collisions
# with another system.
# Optional. Default: "upload://".
uri_scheme: "upload://"
# =============================================================================
# artifacts -- tool-produced file persistence
# =============================================================================
artifacts:
# Master switch for artifact persistence and resource exposure.
# When false, artifact_producer adapters skip persistence entirely and
# return the raw upstream tool result unchanged.
# Optional. Default: true.
enabled: true
# How long (in seconds) artifact files are retained after their last
# access before the cleanup loop deletes them. The TTL resets each time
# the artifact is read via MCP resource or HTTP download.
# null disables artifact expiry (files persist until the session expires).
# Optional. Default: 600 (10 minutes). Allowed: > 0 or null.
ttl_seconds: 600
# Maximum number of artifact files retained per session.
# When a new artifact would exceed this count the allocation fails with
# a clear quota error (no silent eviction; the caller must free space).
# null means unlimited.
# Optional. Default: null. Allowed: > 0 or null.
max_per_session: null
# When true, the adapter registers a session-scoped MCP resource provider
# so clients can list and read artifact files via standard MCP resource
# operations. Resource URIs have the form:
# {uri_scheme}sessions/{session_id}/{artifact_id}/{filename}
# Resource reads are session-validated; a client can only read its own
# session's artifacts.
# Can be overridden per adapter via adapters[].expose_as_resource.
# Optional. Default: true.
expose_as_resources: true
# URI scheme prefix for artifact resource URIs.
# Full URI format: {uri_scheme}sessions/{session_id}/{artifact_id}/{filename}
# Must end with "://".
# Optional. Default: "artifact://".
uri_scheme: "artifact://"
# Artifact naming/layout behavior is fixed in runtime (not configurable):
# - Layout is always by artifact id:
# {storage.root}/artifacts/sessions/{session_id}/{artifact_id}/{filename}
# - Filenames are always sanitised for filesystem safety.
# =============================================================================
# servers -- upstream MCP server registrations (REQUIRED, at least one entry)
# =============================================================================
# Each entry registers one upstream MCP server. The adapter creates an
# independent FastMCP proxy for each server, mounted at its mount_path.
# All server ids must be unique. All mount_paths must be unique and cannot
# be "/".
servers:
- # Unique identifier for this server entry.
# Used in upload endpoint paths, health checks, logging, and error messages.
# Cannot be blank. Must be unique across all server entries.
# Required.
id: "playwright"
# HTTP path where this server's MCP proxy is mounted in the adapter.
# MCP clients connect to: http://{host}:{port}{mount_path}
# Cannot be "/". Leading slash added automatically if omitted.
# Trailing slash stripped. Must be unique across all server entries.
# Required.
mount_path: "/mcp/playwright"
# -------------------------------------------------------------------------
# upstream -- connection to the actual MCP server
# -------------------------------------------------------------------------
upstream:
# Transport protocol the upstream MCP server speaks.
# "streamable_http" -- MCP Streamable HTTP (2025-03-26 spec); the modern
# default. Supports SSE streaming within a single
# HTTP endpoint.
# "sse" -- Legacy HTTP+SSE transport (2024-11-05 spec). Use
# only for older servers that have not been updated.
# Optional. Default: "streamable_http".
# Allowed: "streamable_http" | "sse"
transport: "streamable_http"
# Full URL of the upstream MCP endpoint.
# For streamable_http this is the single endpoint that handles both
# POST and GET (e.g. http://host:8931/mcp).
# For sse this is the SSE endpoint URL.
# Required.
url: "http://playwright-mcp:8931/mcp"
# url: "${PLAYWRIGHT_MCP_URL:-http://localhost:8931/mcp}"
# When true, TLS certificate verification is skipped for upstream
# connections. Use only in development / private networks where the
# upstream uses a self-signed certificate. Never use in production.
# Optional. Default: false.
insecure_tls: false
# Static HTTP headers injected into every upstream request.
# Useful for upstream authentication (API keys, bearer tokens).
# Values are sent verbatim; use env interpolation for secrets.
# Optional. Default: {}.
static_headers: {}
# static_headers:
# Authorization: "Bearer ${UPSTREAM_API_KEY}"
# X-Internal-Service: "mcp-adapter"
# Client request header policy.
client_headers:
# Headers the client MUST include on every request to the adapter.
# If any listed header is absent or empty the adapter rejects the
# request with HTTP 400 before forwarding upstream.
# Case-insensitive comparison.
# Optional. Default: [].
required: []
# required: ["X-User-Id"]
# Client headers that MAY be forwarded to the upstream server.
# By default no client headers are forwarded (deny-all policy).
# Adding a header name here allows it to pass through when the
# client sends it. Only explicitly listed headers are forwarded.
# Case-insensitive matching.
# Optional. Default: [].
passthrough: []
# passthrough: ["X-User-Id", "X-Trace-Id"]
# -------------------------------------------------------------------------
# tool_defaults -- server-level tool-call defaults
# -------------------------------------------------------------------------
# These values override core.defaults for tools on this upstream server,
# and can themselves be overridden per adapter via adapters[].overrides.
# Precedence: adapter.overrides > tool_defaults > core.defaults
# A null value means "inherit from the next level up".
tool_defaults:
# Timeout in seconds for all tool calls on this server.
# null inherits from core.defaults.tool_call_timeout_seconds.
# Optional. Default: null. Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Raw output flag for all adapter-wrapped tools on this server.
# null inherits from core.defaults.allow_raw_output.
# Optional. Default: null.
allow_raw_output: null
# -------------------------------------------------------------------------
# code_mode_enabled -- per-server Code Mode override
# -------------------------------------------------------------------------
# null inherits core.code_mode_enabled.
# true collapses this server's visible tool surface into FastMCP Code Mode
# discovery and execute tools only.
# false forces normal direct tool listing for this server even if the
# global core default is enabled.
#
# Optional. Default: null.
code_mode_enabled: null
# -------------------------------------------------------------------------
# shorten_descriptions -- per-server description-shaping override
# -------------------------------------------------------------------------
# null inherits core.shorten_descriptions.
# true keeps only a short semantic summary from upstream descriptions for
# upload_consumer overrides, then appends the adapter workflow guidance.
# false keeps the full upstream description and appends the adapter
# workflow guidance after it.
#
# Optional. Default: null.
shorten_descriptions: null
# Maximum token budget for the first-sentence summary when shortened
# descriptions are enabled for this server.
#
# null inherits core.short_description_max_tokens.
#
# Optional. Default: null. Allowed: > 0 or null.
short_description_max_tokens: null
# -------------------------------------------------------------------------
# tool_description_policy -- per-server description-forwarding override
# -------------------------------------------------------------------------
tool_description_policy:
# Override how this server forwards tool and schema descriptions.
#
# null inherits core.tool_description_policy.mode.
#
# Optional. Default: null.
# Allowed: "preserve", "truncate", "strip", or null.
mode: null
# Override the top-level tool description cap for this server.
#
# null inherits core.tool_description_policy.max_tool_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_description_chars: null
# Override the schema description cap for this server.
#
# null inherits core.tool_description_policy.max_schema_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_schema_description_chars: null
# -------------------------------------------------------------------------
# tool_metadata_sanitization -- per-server metadata-sanitization override
# -------------------------------------------------------------------------
tool_metadata_sanitization:
# Override how this server sanitizes model-visible tool metadata.
#
# null inherits core.tool_metadata_sanitization.mode.
#
# Optional. Default: null.
# Allowed: "off", "sanitize", "block", or null.
mode: null
# Override Unicode normalization for this server.
#
# null inherits core.tool_metadata_sanitization.normalize_unicode.
#
# Optional. Default: null.
normalize_unicode: null
# Override invisible-character removal for this server.
#
# null inherits core.tool_metadata_sanitization.remove_invisible_characters.
#
# Optional. Default: null.
remove_invisible_characters: null
# Override the tool title length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_tool_title_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_title_chars: null
# Override the tool description length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_tool_description_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_tool_description_chars: null
# Override the schema text length cap for this server.
#
# null inherits core.tool_metadata_sanitization.max_schema_text_chars.
#
# Optional. Default: null. Allowed: > 0 or null.
max_schema_text_chars: null
# -------------------------------------------------------------------------
# tool_definition_pinning -- per-server trust-policy override
# -------------------------------------------------------------------------
tool_definition_pinning:
# Override whether this server pins tool definitions for each adapter
# session.
#
# null inherits core.tool_definition_pinning.mode.
#
# Optional. Default: null.
# Allowed: "off", "warn", "block", or null.
mode: null
# Override how block mode behaves for this server.
#
# null inherits core.tool_definition_pinning.block_strategy.
#
# Optional. Default: null.
# Allowed: "error", "baseline_subset", or null.
block_strategy: null
# Override what block_strategy="error" should do for this server.
#
# null inherits core.tool_definition_pinning.block_error_session_action.
#
# Optional. Default: null.
# Allowed: "keep", "invalidate", or null.
block_error_session_action: null
# -------------------------------------------------------------------------
# disabled_tools -- tool-level suppression list
# -------------------------------------------------------------------------
# A list of tool names or Python regex patterns (re.fullmatch) to exclude
# from this server's MCP proxy. Matched tools are never registered and
# never appear in list_tools responses returned to clients.
#
# Each entry is first compared as a plain exact string; if that does not
# match, it is compiled and applied as a regex. Invalid regex patterns are
# skipped with a warning log and do not prevent the adapter from starting.
#
# Use cases:
# - Remove internal/debug tools exposed by an upstream server.
# - Restrict a sensitive tool in a shared multi-tenant deployment.
# - Suppress the auto-injected upload helper (e.g. "playwright_get_upload_url").
#
# Optional. Default: [].
disabled_tools: []
# disabled_tools:
# - "dangerous_exec_tool" # exact name
# - "^internal_.*" # suppress any tool starting with "internal_"
# - "playwright_get_upload_url" # suppress the auto-injected upload helper
# -------------------------------------------------------------------------
# upstream_ping -- per-server overrides for the health/circuit-breaker loop
# -------------------------------------------------------------------------
# Any field set to null (or omitted) falls back to core.upstream_ping.
# Provide only the fields you want to differ from the global defaults.
upstream_ping:
# Override whether ping monitoring is active for this server.
# null inherits core.upstream_ping.enabled.
# Optional. Default: null.
enabled: null
# Override the ping interval for this server (seconds).
# null inherits core.upstream_ping.interval_seconds.
# Optional. Default: null. Allowed: > 0 or null.
interval_seconds: null
# Override the ping timeout for this server (seconds).
# null inherits core.upstream_ping.timeout_seconds.
# Optional. Default: null. Allowed: > 0 or null.
timeout_seconds: null
# Override how many consecutive failures trip the breaker.
# null inherits core.upstream_ping.failure_threshold.
# Optional. Default: null. Allowed: > 0 or null.
failure_threshold: null
# Override how long the breaker stays open before moving to half_open.
# null inherits core.upstream_ping.open_cooldown_seconds.
# Optional. Default: null. Allowed: > 0 or null.
open_cooldown_seconds: null
# Override how many successful half_open probes close the breaker.
# null inherits core.upstream_ping.half_open_probe_allowance.
# Optional. Default: null. Allowed: > 0 or null.
half_open_probe_allowance: null
# -------------------------------------------------------------------------
# adapters -- request/response interception pipeline for this server
# -------------------------------------------------------------------------
# Each entry wraps one or more upstream tools with adapter logic that runs
# before and/or after the upstream call. Two types are available.
# A tool may appear in only one adapter entry; duplicate registrations for
# the same tool name are silently skipped (first wins).
adapters:
# -----------------------------------------------------------------------
# upload_consumer adapter
# -----------------------------------------------------------------------
# Intercepts tool calls whose arguments contain upload:// file handles
# (returned by the /upload/{server_id} endpoint) and rewrites them to
# real absolute filesystem paths before forwarding the call upstream.
# The upstream tool receives a normal path string and never sees the
# upload:// URI scheme.
#
# Typical use-case: browser_file_upload needs a real on-disk path; client
# stages the file via the upload endpoint and passes the handle as an arg.
# -----------------------------------------------------------------------
- type: "upload_consumer"
# Tool names on this server that this adapter should intercept.
# At least one name is required. Names must match exactly.
# Required.
tools: ["browser_file_upload"]
# Argument name (or dot-path for nested objects) that holds the
# upload:// URI. The adapter reads this argument, resolves the handle,
# and replaces the value with the absolute path before forwarding.
# Supports a single string value OR a list of strings (the adapter
# preserves the shape: string in -> string out, list in -> list out).
# Dot-path example: "options.file" resolves arguments["options"]["file"].
# Required.
file_path_argument: "paths"
# URI scheme the adapter expects in file_path_argument values.
# Must match uploads.uri_scheme. Change if you customised that setting.
# Optional. Default: "upload://". Must end with "://".
uri_scheme: "upload://"
# When true, resolved local filesystem paths are converted to file://
# URIs before forwarding to the upstream tool.
# Use this for upstream tools that require URI-style inputs instead of
# raw absolute paths.
# When false or null, the adapter forwards plain absolute paths.
# Optional. Default: null. Allowed: true, false, or null.
uri_prefix: null
# Per-adapter tool-call behaviour overrides.
# null values inherit the next level up (server then core).
overrides:
# Optional. Default: null (inherit). Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Optional. Default: null (inherit).
allow_raw_output: null
# -----------------------------------------------------------------------
# artifact_producer adapter
# -----------------------------------------------------------------------
# Intercepts tool calls that produce output files (screenshots, PDFs,
# exports ...) and ensures those files are:
# 1. Written into the adapter's managed artifact store.
# 2. Registered with the session under a stable artifact_id.
# 3. Exposed as a session-scoped MCP resource (if expose_as_resource=true).
# 4. Referenced in the tool result metadata via artifact_uri.
#
# Two strategies for capturing the file are available and can be combined:
#
# output_path_argument (preferred when supported by the upstream tool)
# The adapter allocates an artifact path in the store, injects it as
# the value of the specified tool argument, calls the tool, and the
# tool writes its output directly to that path.
#
# output_locator (fallback when the tool cannot accept an output path)
# After the tool returns, the adapter searches the result for the
# file using one of the locator modes below.
# -----------------------------------------------------------------------
- type: "artifact_producer"
# Tool names on this server that this adapter should intercept.
# At least one name is required.
# Required.
tools: ["browser_take_screenshot", "browser_pdf_save"]
# Name of the tool argument that accepts an output file path.
# When set, the adapter:
# 1. Allocates a path under the artifact store.
# 2. Sets arguments[output_path_argument] = <allocated path>.
# 3. Calls the tool (which writes the file to that path).
# 4. Finalises the artifact record.
# Set to null if the upstream tool cannot accept an explicit output path
# and use output_locator instead.
# Optional. Default: null.
output_path_argument: "filename"
# How to locate the produced file when output_path_argument is null
# OR when the tool ignores the supplied path and writes elsewhere.
#
# mode: "none" -- Do not attempt to persist; pass through raw output.
# Use when you only want the tool result unmodified.
#
# mode: "structured" -- Read a filesystem path from the structured output
# using output_path_key as a dot-path into the
# result's structured_content (JSON) dict.
# Example: output_path_key "result.file.path"
# reads structured_content["result"]["file"]["path"]
# Requires output_path_key to be set (non-empty).
#
# mode: "regex" -- Search all TextContent blocks in the tool result
# for a filesystem path using the first matching
# pattern in output_path_regexes. The first capture
# group (if any) is used; otherwise the full match.
# If output_path_regexes is empty, built-in default
# path regexes are used.
#
# mode: "embedded" -- Extract raw bytes directly from the tool result
# content blocks. Checks ImageContent (base64 PNG)
# and EmbeddedResource (BlobResourceContents or
# TextResourceContents) blocks in that order.
# Use when the upstream tool returns file content
# inline rather than writing to disk.
#
# Mode resolution when output_path_argument is also set:
# The adapter first checks whether the tool actually wrote to the
# injected path. If not (tool ignored it), it falls back to the
# output_locator. mode="none" disables this fallback.
#
output_locator:
# Optional. Default: "none".
# Allowed: "structured" | "regex" | "embedded" | "none"
mode: "structured"
# Dot-path into structured_content to extract a filesystem path from.
# Required when mode="structured" and output_path_argument is null.
# Optional otherwise. Default: null.
output_path_key: null
# output_path_key: "path"
# output_path_key: "result.file.path"
# List of Python regex patterns applied to joined TextContent output.
# Patterns are tried in order; the first match wins.
# If the pattern has a capture group, group(1) is used; else group(0).
# Optional. Default: [].
# If empty in regex mode, built-in default path regexes are used.
output_path_regexes: []
# output_path_regexes:
# - "Saved to: (.+\\.pdf)"
# - "/data/shared/\\S+"
# Whether to persist the located/embedded file into the artifact store.
# When false the tool result is returned as-is with no artifact stored.
# Useful when you want the adapter for its timeout/override behaviour
# only, without artifact side-effects.
# Optional. Default: true.
persist: true
# Whether to register this artifact as a session-scoped MCP resource,
# allowing MCP clients to read file bytes via resources/read.
# Overrides artifacts.expose_as_resources on a per-adapter basis.
# Has no effect when artifacts.enabled is false.
# Optional. Default: true.
expose_as_resource: true
# Whether to embed raw file bytes (base64) directly in the tool result
# alongside the artifact_uri metadata.
# Overrides the allow_raw_output chain specifically for this adapter.
# Also accepted as "include_raw_output" (legacy alias).
# null falls through to overrides.allow_raw_output -> server -> core.
# Warning: large files produce very large responses and high memory
# pressure; prefer MCP resource access or HTTP download.
# Optional. Default: null.
allow_raw_output: null
# Per-adapter tool-call behaviour overrides.
# null values inherit the next level up (server then core).
overrides:
# Optional. Default: null (inherit). Allowed: > 0 or null.
tool_call_timeout_seconds: null
# Optional. Default: null (inherit).
allow_raw_output: null
Next steps¶
- Previous topic: Configuration - practical guide to the main config sections.
- Next: Local Dev Scenario - start with the easiest opinionated profile.