Configuration
mcpr.toml declares how the proxy behaves: where to route traffic, CSP settings, resource limits, tunnel, and cloud sync. It does not manage process lifecycle — that’s owned by your supervisor (terminal, systemd, Docker, k8s) and invoked via mcpr proxy run.
mcpr searches the current directory, then parent directories, for mcpr.toml.
Field reference
Section titled “Field reference”Top-level
Section titled “Top-level”| Field | Type | Default | Description |
|---|---|---|---|
mcp | string | required | Upstream MCP server URL |
port | number | 3004 | Local proxy port (override per environment) |
name | string | filename stem | Proxy name used in logs and the cloud dashboard |
drain_timeout | number | 30 | Seconds to wait for in-flight requests on SIGTERM |
Resource limits & timeouts
Section titled “Resource limits & timeouts”All sizes are bytes; all timeouts are seconds.
| Field | Type | Default | Description |
|---|---|---|---|
max_request_body_size | number | 5242880 (5 MB) | Reject inbound requests larger than this (413) |
max_response_body_size | number | 10485760 (10 MB) | Reject upstream responses larger than this (502) |
max_concurrent_upstream | number | 100 | Max in-flight upstream requests (semaphore) |
connect_timeout | number | 5 | TCP connect timeout to upstream |
request_timeout | number | 30 | Total request timeout including response |
CSP rewriting for MCP Apps. Three independent directives, each with its own domains list and mode. See Routing for the full CSP story.
| Directive | Controls | Default mode |
|---|---|---|
[csp.connectDomains] | fetch, WebSocket, EventSource targets | extend |
[csp.resourceDomains] | Script / style / image / font / media sources | extend |
[csp.frameDomains] | Nested <iframe> sources | replace |
extend merges declared domains with whatever upstream returned. replace discards upstream for that directive and uses only declared domains.
[csp].domain (string) sets the bare public host injected into widget metadata (openai/widgetDomain). When unset, mcpr falls back to the tunnel URL.
[[csp.widget]]
Section titled “[[csp.widget]]”Glob-matched overrides layered on top of the global policy.
| Field | Type | Default | Description |
|---|---|---|---|
match | string | required | Glob pattern matched against resource URI (e.g. ui://widget/payment*) |
connectDomains | string[] | — | Override connect domains for matching widgets |
connectDomainsMode | string | extend | extend or replace |
resourceDomains | string[] | — | Override resource domains |
resourceDomainsMode | string | extend | extend or replace |
frameDomains | string[] | — | Override frame domains |
frameDomainsMode | string | extend | extend or replace |
[tunnel]
Section titled “[tunnel]”| Field | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable tunnel for a public URL (proxy-only mode otherwise) |
relay_url | string | https://tunnel.mcpr.app | Relay server URL |
token | string | — | Tunnel authentication token (register at mcpr.app) |
subdomain | string | derived from token | Fixed subdomain (claim one in mcpr Cloud) |
[cloud]
Section titled “[cloud]”| Field | Type | Default | Description |
|---|---|---|---|
token | string | — | Cloud authentication token from cloud.mcpr.app |
server | string | — | Server slug to identify this proxy |
endpoint | string | https://api.mcpr.app/api/ingest-events | Custom ingest endpoint |
batch_size | number | 100 | Events per batch before flushing |
flush_interval_ms | number | 5000 | Flush interval in milliseconds |
Examples
Section titled “Examples”Minimal
Section titled “Minimal”mcp = "http://localhost:9000"MCP server + CSP
Section titled “MCP server + CSP”mcp = "http://localhost:9000"port = 3000
[csp]domain = "widgets.example.com"
[csp.connectDomains]domains = ["api.example.com"]mode = "extend"
[csp.resourceDomains]domains = ["cdn.example.com"]mode = "extend"
[csp.frameDomains]domains = []mode = "replace"
# Optional: override CSP for specific widgets by URI glob[[csp.widget]]match = "ui://widget/payment*"connectDomains = ["api.stripe.com"]connectDomainsMode = "extend"Cloud sync
Section titled “Cloud sync”mcp = "http://localhost:9000"
[cloud]token = "mcpr_xxxxxxxx"server = "my-proxy"Public tunnel
Section titled “Public tunnel”mcp = "http://localhost:9000"
[tunnel]enabled = truetoken = "your-tunnel-token" # register at https://mcpr.appsubdomain = "myapp" # optional, claim in mcpr CloudResource limits
Section titled “Resource limits”max_request_body_size = 10485760 # 10 MBmax_response_body_size = 52428800 # 50 MBmax_concurrent_upstream = 100connect_timeout = 5request_timeout = 30Production (Docker / Kubernetes)
Section titled “Production (Docker / Kubernetes)”mcp = "http://mcp-server:9000"port = 8080drain_timeout = 25
[cloud]token = "mcpr_xxxxxxxx"server = "prod-1"Validating config
Section titled “Validating config”mcpr validate # checks ./mcpr.tomlmcpr validate -c /etc/mcpr/mcpr.toml # checks a specific fileExit code 0 means valid. Exit code 1 means errors.
For tunnel deployment details, see Tunnels.
