Configuration
MCP Compose is configured using a TOML file, typically named mcp_compose.toml. This page provides a comprehensive reference for all configuration options.
Configuration File Location
MCP Compose searches for configuration in the following order:
- Path specified via
--configCLI argument mcp_compose.tomlin the current directorymcp_compose.tomlin parent directories (walking up to root)
Variable Substitution
Keep sensitive data like API keys out of your configuration files by referencing environment variables instead. MCP Compose automatically replaces variable placeholders with their actual values when the configuration is loaded.
Environment Variables
Use ${VAR_NAME} or $VAR_NAME syntax to reference environment variables:
[[servers.proxied.stdio]]
name = "my-server"
command = ["python", "server.py"]
env = { API_KEY = "${MY_API_KEY}" }
Special Variables
| Variable | Description |
|---|---|
${MCP_COMPOSE_CONFIG_DIR} | Absolute path to the directory containing the config file |
The MCP_COMPOSE_CONFIG_DIR variable is particularly useful for portable configurations with relative paths:
[[servers.proxied.stdio]]
name = "calculator"
command = ["python", "server.py"]
working_dir = "${MCP_COMPOSE_CONFIG_DIR}"
Composer Section
This is the main section where you give your unified MCP server a name and configure how it behaves when multiple downstream servers expose tools with the same name. Think of it as the identity and personality of your composed server.
[composer]
name = "my-unified-server" # Server name (required)
conflict_resolution = "prefix" # Tool name conflict strategy
log_level = "INFO" # Logging level
port = 8080 # Default port for HTTP transports
Conflict Resolution Strategies
| Strategy | Description | Example Result |
|---|---|---|
prefix | Prefix tool name with server name | calculator_add |
suffix | Suffix tool name with server name | add_calculator |
error | Fail on conflict | Error raised |
override | Last server wins | add |
ignore | Skip conflicting tools | Tool skipped |
custom | Use custom template | See tool_manager section |
Log Levels
| Level | Description |
|---|---|
DEBUG | Verbose debugging information |
INFO | General operational messages |
WARNING | Warning messages |
ERROR | Error messages only |
Transport Section
Choose how MCP clients (like Claude Desktop or VS Code) connect to your composed server. STDIO is the simplest option where the client launches MCP Compose as a subprocess, while Streamable HTTP runs as a standalone server that multiple clients can connect to over the network.
[transport]
# STDIO transport - for subprocess communication
stdio_enabled = true
# Streamable HTTP transport (recommended)
streamable_http_enabled = true
streamable_http_path = "/mcp"
streamable_http_cors_enabled = true
# SSE transport (deprecated - use streamable_http instead)
sse_enabled = false
sse_path = "/sse"
sse_cors_enabled = true
| Option | Type | Default | Description |
|---|---|---|---|
stdio_enabled | bool | true | Enable STDIO transport |
streamable_http_enabled | bool | false | Enable Streamable HTTP transport |
streamable_http_path | string | "/mcp" | HTTP endpoint path |
streamable_http_cors_enabled | bool | true | Enable CORS for HTTP |
sse_enabled | bool | false | Enable SSE transport (deprecated) |
sse_path | string | "/sse" | SSE endpoint path |
sse_cors_enabled | bool | true | Enable CORS for SSE |
Authentication Section
Protect your MCP server from unauthorized access by requiring clients to prove their identity. Choose from simple API keys for internal use, JWT tokens for stateless authentication, or OAuth2 for integration with existing identity providers like GitHub or Auth0.
[authentication]
enabled = false
providers = ["api_key"]
default_provider = "api_key"
API Key Authentication
[authentication.api_key]
header_name = "X-API-Key"
keys = ["${MCP_API_KEY_1}", "${MCP_API_KEY_2}"]
Basic Authentication
[authentication.basic]
username = "${MCP_USERNAME}"
password = "${MCP_PASSWORD}"
JWT Authentication
[authentication.jwt]
secret = "${JWT_SECRET}"
algorithm = "HS256"
issuer = "mcp-compose"
audience = "mcp-clients"
OAuth2 Authentication
[authentication.oauth2]
provider = "generic" # github, auth0, okta, or generic
authorization_endpoint = "https://id.example.com/oauth2/authorize"
token_endpoint = "https://id.example.com/oauth2/token"
userinfo_endpoint = "https://id.example.com/oauth2/userinfo"
scopes = ["openid", "profile"]
client_id = "${OAUTH_CLIENT_ID}"
client_secret = "${OAUTH_CLIENT_SECRET}"
discovery_url = "${OAUTH_DISCOVERY_URL}" # Optional OIDC discovery
mTLS Authentication
[authentication.mtls]
ca_cert = "/path/to/ca.crt"
client_cert = "/path/to/client.crt"
client_key = "/path/to/client.key"
Authorization Section
Control what authenticated users are allowed to do. Define roles with specific permissions so that administrators can manage servers while regular users can only execute tools. Rate limiting prevents any single user from overwhelming the system.
[authorization]
enabled = false
model = "rbac"
Role-Based Access Control (RBAC)
[[authorization.roles]]
name = "admin"
permissions = ["*"]
[[authorization.roles]]
name = "developer"
permissions = ["tools:*", "servers:read", "logs:read"]
[[authorization.roles]]
name = "user"
permissions = ["tools:execute", "tools:list"]
Rate Limiting
[authorization.rate_limiting]
enabled = false
default_limit = 100
per_role_limits = { admin = 1000, developer = 500, user = 100 }
Servers Section
This is where you define the MCP servers that MCP Compose will unify. You can embed Python-based servers directly, launch local servers as subprocesses (STDIO), or connect to remote servers over HTTP. Each downstream server's tools become available through the single composed endpoint.
Embedded Servers
Embedded servers are Python packages that implement MCP servers, loaded directly into the MCP Compose process.
[servers.embedded]
[[servers.embedded.servers]]
name = "jupyter-mcp-server"
package = "jupyter_mcp_server"
enabled = true
tool_mappings = { "create" = "jupyter_create", "run" = "jupyter_run" }
| Option | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Server identifier |
package | string | Yes | Python package name |
enabled | bool | No | Enable/disable server (default: true) |
tool_mappings | table | No | Custom tool name mappings |
STDIO Proxied Servers
STDIO servers run as subprocesses, communicating via stdin/stdout.
[[servers.proxied.stdio]]
name = "weather-server"
command = ["uvx", "mcp-server-weather"]
working_dir = "${MCP_COMPOSE_CONFIG_DIR}"
env = { WEATHER_API_KEY = "${WEATHER_API_KEY}" }
# Lifecycle management
restart_policy = "on-failure" # never, on-failure, always
max_restarts = 3
restart_delay = 5
# Health checks
health_check_enabled = true
health_check_interval = 30
health_check_timeout = 5
health_check_method = "tool"
health_check_tool = "health"
# Logging
log_stdout = true
log_stderr = true
log_file = "/var/log/mcp-compose/weather-server.log"
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Server identifier |
command | array | Yes | - | Command and arguments |
working_dir | string | No | - | Working directory for subprocess |
env | table | No | {} | Environment variables |
restart_policy | string | No | "never" | Restart behavior |
max_restarts | int | No | 3 | Maximum restart attempts |
restart_delay | int | No | 5 | Seconds between restarts |
health_check_enabled | bool | No | false | Enable health checking |
health_check_interval | int | No | 30 | Seconds between checks |
health_check_timeout | int | No | 5 | Health check timeout |
health_check_method | string | No | "tool" | Check method |
health_check_tool | string | No | "health" | Tool to call for health |
log_stdout | bool | No | true | Log server stdout |
log_stderr | bool | No | true | Log server stderr |
log_file | string | No | - | File path for logs |
Resource Limits
[[servers.proxied.stdio]]
name = "resource-limited-server"
command = ["python", "server.py"]
[servers.proxied.stdio.resource_limits]
max_memory_mb = 512
max_cpu_percent = 50
Streamable HTTP Proxied Servers
Connect to remote MCP servers over HTTP with streaming support.
[[servers.proxied.http]]
name = "remote-api-server"
url = "https://api.example.com/mcp"
protocol = "lines" # chunked, lines, poll
auth_token = "${REMOTE_SERVER_TOKEN}"
auth_type = "bearer" # bearer, basic
timeout = 30
retry_interval = 5
keep_alive = true
reconnect_on_failure = true
max_reconnect_attempts = 10
poll_interval = 2 # Only for poll protocol
mode = "proxy" # proxy or translator
# Health checks
health_check_enabled = true
health_check_interval = 60
health_check_endpoint = "/health"
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | - | Server identifier |
url | string | Yes | - | Server URL |
protocol | string | No | "lines" | HTTP streaming protocol |
auth_token | string | No | - | Authentication token |
auth_type | string | No | "bearer" | Token type |
timeout | int | No | 30 | Request timeout in seconds |
retry_interval | int | No | 5 | Retry interval in seconds |
keep_alive | bool | No | true | Maintain persistent connection |
reconnect_on_failure | bool | No | true | Auto-reconnect on failure |
max_reconnect_attempts | int | No | 10 | Maximum reconnection attempts |
poll_interval | int | No | 2 | Polling interval (poll protocol only) |
mode | string | No | "proxy" | Operating mode |
SSE Proxied Servers (Deprecated)
SSE transport is deprecated. Use Streamable HTTP ([[servers.proxied.http]]) instead.
[[servers.proxied.sse]]
name = "legacy-server"
url = "http://localhost:8080/sse"
auth_token = "${AUTH_TOKEN}"
timeout = 30
retry_interval = 5
reconnect_on_failure = true
max_reconnect_attempts = 10
Tool Manager Section
Fine-tune how tools from different servers are named and organized. Create user-friendly aliases, apply different naming strategies to specific tools, or enable versioning when you need to support multiple versions of the same tool simultaneously.
[tool_manager]
conflict_resolution = "prefix"
Tool-Specific Overrides
Apply different conflict resolution strategies to specific tools:
[[tool_manager.tool_overrides]]
tool_pattern = "notebook_*"
resolution = "prefix"
[[tool_manager.tool_overrides]]
tool_pattern = "search_*"
resolution = "suffix"
Custom Naming Template
Define a custom template for tool naming:
[tool_manager.custom_template]
template = "{server_name}_{tool_name}"
Available template variables:
{server_name}- The server's name{tool_name}- The original tool name
Tool Aliases
Create aliases for tools:
[tool_manager.aliases]
jupyter_create = "create_notebook"
fs_read = "read_file"
Tool Versioning
Enable multiple versions of the same tool:
[tool_manager.versioning]
enabled = false
allow_multiple_versions = false
version_suffix_format = "_v{version}"
REST API Section
Expose a REST API for programmatic management of your MCP Compose instance. Use it to start/stop servers, invoke tools, or integrate with external systems. The built-in OpenAPI documentation makes it easy to explore available endpoints.
[api]
enabled = true
path_prefix = "/api/v1"
host = "0.0.0.0"
port = 8080
cors_enabled = true
cors_origins = ["http://localhost:3000"]
cors_methods = ["GET", "POST", "PUT", "DELETE"]
docs_enabled = true
docs_path = "/docs"
openapi_path = "/openapi.json"
| Option | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable REST API |
path_prefix | string | "/api/v1" | API path prefix |
host | string | "0.0.0.0" | Bind address |
port | int | 8080 | Listen port |
cors_enabled | bool | true | Enable CORS |
cors_origins | array | ["*"] | Allowed origins |
cors_methods | array | ["GET", "POST", ...] | Allowed HTTP methods |
docs_enabled | bool | true | Enable API documentation |
docs_path | string | "/docs" | Documentation path |
openapi_path | string | "/openapi.json" | OpenAPI spec path |
Web UI Section
Enable a browser-based dashboard for managing your MCP Compose instance without command-line tools. Test tools interactively, view logs in real-time, monitor metrics, and even edit configuration—all from a visual interface.
[ui]
enabled = true
framework = "react"
mode = "embedded" # embedded or separate
path = "/ui"
port = 9456 # Used when mode is 'separate'
static_dir = "/var/www/mcp-compose/ui"
features = [
"server_management",
"tool_testing",
"logs_viewing",
"metrics_dashboard",
"configuration_editor"
]
| Option | Type | Default | Description |
|---|---|---|---|
enabled | bool | true | Enable web UI |
framework | string | "react" | UI framework |
mode | string | "embedded" | Deployment mode |
path | string | "/ui" | UI path |
port | int | 9456 | Separate mode port |
static_dir | string | - | Static files directory |
features | array | all | Enabled UI features |
Available Features
| Feature | Description |
|---|---|
server_management | Start, stop, restart servers |
tool_testing | Interactive tool testing |
logs_viewing | View server logs |
metrics_dashboard | Metrics and monitoring |
configuration_editor | Edit configuration |
Monitoring Section
Gain visibility into how your MCP servers are performing. Collect metrics for dashboards and alerts, configure structured logging for troubleshooting, and enable distributed tracing to follow requests across multiple servers.
[monitoring]
enabled = true
Metrics
[monitoring.metrics]
enabled = true
provider = "prometheus"
endpoint = "/metrics"
collection_interval = 15
collect = [
"tool_invocation_count",
"tool_invocation_duration",
"tool_error_rate",
"server_health_status",
"process_cpu_usage",
"process_memory_usage",
"request_rate",
"response_time"
]
Logging
[monitoring.logging]
level = "INFO"
format = "json" # json or text
output = "stdout" # stdout or file
log_file = "/var/log/mcp-compose/composer.log"
rotation = "daily" # daily, size, or none
max_size_mb = 100
max_files = 7
aggregate_managed_logs = true
Distributed Tracing
[monitoring.tracing]
enabled = false
provider = "opentelemetry"
endpoint = "http://localhost:4317"
sample_rate = 1.0
Health Endpoints
[monitoring.health]
endpoint = "/health"
detailed_endpoint = "/health/detailed"
Complete Example
Here's a complete configuration example combining multiple features:
# ============================================================================
# Composer Settings
# ============================================================================
[composer]
name = "production-composer"
conflict_resolution = "prefix"
log_level = "INFO"
port = 8080
# ============================================================================
# Transport Configuration
# ============================================================================
[transport]
stdio_enabled = false
streamable_http_enabled = true
streamable_http_path = "/mcp"
streamable_http_cors_enabled = true
# ============================================================================
# Authentication
# ============================================================================
[authentication]
enabled = true
providers = ["jwt"]
default_provider = "jwt"
[authentication.jwt]
secret = "${JWT_SECRET}"
algorithm = "HS256"
issuer = "mcp-compose"
# ============================================================================
# Servers
# ============================================================================
[[servers.proxied.stdio]]
name = "filesystem"
command = ["python", "-m", "mcp_server_filesystem", "./data"]
working_dir = "${MCP_COMPOSE_CONFIG_DIR}"
restart_policy = "on-failure"
max_restarts = 3
[[servers.proxied.stdio]]
name = "database"
command = ["python", "db_server.py"]
working_dir = "${MCP_COMPOSE_CONFIG_DIR}"
env = { DATABASE_URL = "${DATABASE_URL}" }
health_check_enabled = true
health_check_interval = 30
[[servers.proxied.http]]
name = "remote-api"
url = "https://api.example.com/mcp"
auth_token = "${API_TOKEN}"
timeout = 60
reconnect_on_failure = true
# ============================================================================
# Monitoring
# ============================================================================
[monitoring]
enabled = true
[monitoring.metrics]
enabled = true
provider = "prometheus"
endpoint = "/metrics"
[monitoring.logging]
level = "INFO"
format = "json"
output = "stdout"
[monitoring.health]
endpoint = "/health"
Validating Configuration
Validate your configuration file without starting the server:
mcp-compose validate --config mcp_compose.toml
Best Practices
- Use environment variables for sensitive data like API keys, tokens, and passwords
- Use
${MCP_COMPOSE_CONFIG_DIR}for portable relative paths inworking_dir - Set appropriate restart policies for production deployments (
on-failurerecommended) - Enable health checks for critical servers to detect failures early
- Use
prefixconflict resolution to avoid tool name collisions - Enable monitoring in production for observability
- Use Streamable HTTP instead of SSE for new deployments
- Validate configuration before deploying changes