Skip to content

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.

FieldTypeDefaultDescription
mcpstringrequiredUpstream MCP server URL
portnumber3004Local proxy port (override per environment)
namestringfilename stemProxy name used in logs and the cloud dashboard
drain_timeoutnumber30Seconds to wait for in-flight requests on SIGTERM

All sizes are bytes; all timeouts are seconds.

FieldTypeDefaultDescription
max_request_body_sizenumber5242880 (5 MB)Reject inbound requests larger than this (413)
max_response_body_sizenumber10485760 (10 MB)Reject upstream responses larger than this (502)
max_concurrent_upstreamnumber100Max in-flight upstream requests (semaphore)
connect_timeoutnumber5TCP connect timeout to upstream
request_timeoutnumber30Total 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.

DirectiveControlsDefault mode
[csp.connectDomains]fetch, WebSocket, EventSource targetsextend
[csp.resourceDomains]Script / style / image / font / media sourcesextend
[csp.frameDomains]Nested <iframe> sourcesreplace

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.

Glob-matched overrides layered on top of the global policy.

FieldTypeDefaultDescription
matchstringrequiredGlob pattern matched against resource URI (e.g. ui://widget/payment*)
connectDomainsstring[]Override connect domains for matching widgets
connectDomainsModestringextendextend or replace
resourceDomainsstring[]Override resource domains
resourceDomainsModestringextendextend or replace
frameDomainsstring[]Override frame domains
frameDomainsModestringextendextend or replace
FieldTypeDefaultDescription
enabledbooleanfalseEnable tunnel for a public URL (proxy-only mode otherwise)
relay_urlstringhttps://tunnel.mcpr.appRelay server URL
tokenstringTunnel authentication token (register at mcpr.app)
subdomainstringderived from tokenFixed subdomain (claim one in mcpr Cloud)
FieldTypeDefaultDescription
tokenstringCloud authentication token from cloud.mcpr.app
serverstringServer slug to identify this proxy
endpointstringhttps://api.mcpr.app/api/ingest-eventsCustom ingest endpoint
batch_sizenumber100Events per batch before flushing
flush_interval_msnumber5000Flush interval in milliseconds
mcp = "http://localhost:9000"
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"
mcp = "http://localhost:9000"
[cloud]
token = "mcpr_xxxxxxxx"
server = "my-proxy"
mcp = "http://localhost:9000"
[tunnel]
enabled = true
token = "your-tunnel-token" # register at https://mcpr.app
subdomain = "myapp" # optional, claim in mcpr Cloud
max_request_body_size = 10485760 # 10 MB
max_response_body_size = 52428800 # 50 MB
max_concurrent_upstream = 100
connect_timeout = 5
request_timeout = 30
mcp = "http://mcp-server:9000"
port = 8080
drain_timeout = 25
[cloud]
token = "mcpr_xxxxxxxx"
server = "prod-1"
Terminal window
mcpr validate # checks ./mcpr.toml
mcpr validate -c /etc/mcpr/mcpr.toml # checks a specific file

Exit code 0 means valid. Exit code 1 means errors.

For tunnel deployment details, see Tunnels.