Mcplex
MCPlex - The MCP Smart Gateway. Semantic tool routing, security guardrails, and real-time observability for AI agents.
Ask AI about Mcplex
Powered by Claude Β· Grounded in docs
I know everything about Mcplex. Ask me about installation, configuration, usage, or troubleshooting.
0/500
Reviews
Documentation
π MCPlex β The MCP Smart Gateway
Semantic tool routing β’ Security guardrails β’ Real-time observability
Stop dumping 50k tokens of tool definitions into your LLM's context window. MCPlex intelligently routes only the tools your agent actually needs.
The Problem
Every developer building multi-agent AI systems with MCP hits the same wall:
| Pain Point | Impact |
|---|---|
| π§ Context Bloat | 20+ MCP servers = 50k+ tokens of tool definitions consuming your context window |
| π No Security | No RBAC, no audit trails, tool poisoning vulnerabilities |
| ποΈ Blind Operations | Can't track costs, latency, or debug wrong tool selection |
| π Restart Required | Config changes require full restart in production |
| πΈοΈ NΓM Complexity | Orchestrating dozens of servers is an integration nightmare |
The Solution
MCPlex is a single-binary Rust gateway that sits between your AI agent and MCP servers:
Your Agent βββ MCPlex Gateway βββ GitHub MCP (stdio β persistent)
β βββ Slack MCP (stdio β persistent)
β βββ Database MCP (HTTP)
β βββ Filesystem MCP (stdio β persistent)
βΌ
π§ Smart Routing (70-90% token savings)
π RBAC + Audit Logs + API Key Auth
π Real-time Dashboard + Prometheus
π¦ Response Caching (auto-detect read-only)
π Multi-Tenant (API key β role mapping)
π₯ Hot-reload Config
Transport Support
MCPlex supports both MCP transport types as a first-class citizen:
| Transport | Discovery | Runtime Calls | Connection Model |
|---|---|---|---|
| Stdio | β Full MCP handshake | β Multiplexed JSON-RPC | Persistent child process (long-lived) |
| Streamable HTTP | β Full MCP handshake | β Standard HTTP POST | Stateless (connection pooling) |
Stdio servers are spawned at startup and kept alive for the gateway's lifetime. The MCP handshake (initialize β notifications/initialized) runs once, then all subsequent tools/call, resources/read, and prompts/get requests are multiplexed over the same stdin/stdout pipe using JSON-RPC ID correlation.
β‘ Quick Start
1. Install (Pre-built Binary)
Download the latest release from GitHub Releases:
# Linux / macOS
curl -LO https://github.com/ModernOps888/mcplex/releases/latest/download/mcplex-linux-x86_64
chmod +x mcplex-linux-x86_64
sudo mv mcplex-linux-x86_64 /usr/local/bin/mcplex
2. Build from Source
git clone https://github.com/modernops888/mcplex.git
cd mcplex
cargo build --release
3. Configure
cp mcplex.toml my-config.toml
# Edit my-config.toml with your MCP servers
Minimal config for stdio servers:
[gateway]
listen = "127.0.0.1:3100"
dashboard = "127.0.0.1:9090"
[router]
strategy = "semantic"
[[servers]]
name = "filesystem"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
[[servers]]
name = "memory"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-memory"]
4. Run
./target/release/mcplex --config my-config.toml
# Expected output:
# π Spawning stdio server 'filesystem': npx ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
# π€ MCP handshake complete for 'filesystem'
# π‘ Server 'filesystem': 11 tools, 0 resources, 0 prompts
# π Spawning stdio server 'memory': npx ["-y", "@modelcontextprotocol/server-memory"]
# π€ MCP handshake complete for 'memory'
# π‘ Server 'memory': 3 tools, 0 resources, 0 prompts
# β‘ MCPlex gateway listening on 127.0.0.1:3100
5. Connect Your Agent
Point your MCP client to http://127.0.0.1:3100/mcp and open the dashboard at http://127.0.0.1:9090.
π Running as a Service (Deployment)
For persistent environments, run MCPlex as a background service to ensure it starts automatically on boot and restarts if it crashes.
Linux (systemd)
Create a systemd unit file at /etc/systemd/system/mcplex.service:
[Unit]
Description=MCPlex Gateway
After=network.target
[Service]
Type=simple
User=your_user
WorkingDirectory=/path/to/mcplex
ExecStart=/usr/local/bin/mcplex --config /path/to/mcplex/mcplex.toml
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.target
Enable and start the service:
sudo systemctl daemon-reload
sudo systemctl enable mcplex
sudo systemctl start mcplex
sudo systemctl status mcplex
macOS (launchd)
Create a launchd plist file at ~/Library/LaunchAgents/com.modernops.mcplex.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.modernops.mcplex</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/mcplex</string>
<string>--config</string>
<string>/path/to/mcplex.toml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/mcplex.log</string>
<key>StandardErrorPath</key>
<string>/tmp/mcplex-error.log</string>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin</string>
</dict>
</dict>
</plist>
Load and start the service:
launchctl load ~/Library/LaunchAgents/com.modernops.mcplex.plist
launchctl start com.modernops.mcplex
Log Rotation
When running as a service, ensure you implement log rotation to prevent infinite log growth. For macOS, add an entry to /etc/newsyslog.conf; for Linux, use logrotate. MCPlex also has built-in audit log rotation configured via max_log_size_mb.
Service Troubleshooting
| Issue | Resolution |
|---|---|
| Service fails to start immediately | Check your configuration file syntax by running mcplex --check --config <path> manually. |
| Port already in use | Verify no other service is bound to the listen port. Change gateway.listen in your config. |
launchd permission errors | Ensure the ProgramArguments path is absolute and executable by the user. |
| Server respawn loop | Check the StandardErrorPath log for fatal bootstrap errors or missing dependencies (e.g., Node.js for npx servers). |
π How to Connect Your Agent
MCPlex is a transparent MCP proxy β any MCP client that supports Streamable HTTP can connect to it. Your agent talks to MCPlex as if it were a single MCP server, and MCPlex handles multiplexing, routing, and security behind the scenes.
Claude Code / Claude Desktop (Recommended β stdio bridge)
Claude Code and Claude Desktop use stdio transport. MCPlex ships a cross-platform bridge (bridge.mjs) that translates stdio β HTTP. Works on macOS, Windows, and Linux.
Add a .mcp.json to your project root (Claude Code auto-discovers it):
{
"mcpServers": {
"mcplex": {
"command": "node",
"args": ["/path/to/mcplex/bridge.mjs"],
"env": {
"MCPLEX_GATEWAY": "http://127.0.0.1:3100/mcp"
}
}
}
}
For Claude Desktop, add the same config to claude_desktop_config.json.
Cursor / Windsurf / HTTP-capable MCP Clients
Clients that support streamable HTTP can connect directly:
{
"mcpServers": {
"mcplex-gateway": {
"url": "http://127.0.0.1:3100/mcp"
}
}
}
Custom Python Agent
import requests
GATEWAY = "http://127.0.0.1:3100/mcp"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"} # Optional
# Initialize
resp = requests.post(GATEWAY, json={
"jsonrpc": "2.0", "id": 1, "method": "initialize",
"params": {"protocolVersion": "2025-03-26", "capabilities": {},
"clientInfo": {"name": "my-agent", "version": "1.0"}}
}, headers=HEADERS)
# List all tools (MCPlex aggregates from all servers)
resp = requests.post(GATEWAY, json={
"jsonrpc": "2.0", "id": 2, "method": "tools/list"
}, headers=HEADERS)
tools = resp.json()["result"]["tools"]
# Call a tool (MCPlex routes to the right server automatically)
resp = requests.post(GATEWAY, json={
"jsonrpc": "2.0", "id": 3, "method": "tools/call",
"params": {"name": "create_issue", "arguments": {"repo": "my-repo", "title": "Bug fix"}}
}, headers=HEADERS)
How It Catches Your Agent's Calls
MCPlex acts as a man-in-the-middle proxy for all MCP traffic:
Your Agent ββPOST /mcpβββ MCPlex Gateway βββ Upstream MCP Server
β (persistent stdio or HTTP)
ββ β
Auth check (API key)
ββ π¦ Rate limit check
ββ π RBAC + allowlist/blocklist
ββ π Audit log (every call)
ββ π Metrics (latency, tokens)
Every tools/call goes through the security engine and is logged. Every tools/list goes through the semantic router. There's no way to bypass it β if your agent uses MCPlex as its MCP endpoint, all calls are intercepted, checked, and logged.
π§ Semantic Tool Routing
The killer feature. Instead of dumping all tool definitions into your LLM's context, MCPlex uses a meta-tool pattern that works with every standard MCP client β no custom extensions needed:
| Scenario | Without MCPlex | With MCPlex | Savings |
|---|---|---|---|
| 5 servers, 50 tools | ~10,000 tokens | ~200 tokens | 98% |
| 10 servers, 100 tools | ~20,000 tokens | ~200 tokens | 99% |
| 20 servers, 200 tools | ~40,000 tokens | ~200 tokens | 99.5% |
How It Works
When your agent calls tools/list, MCPlex returns 3 lightweight meta-tools (~200 tokens) instead of all real tools:
Agent MCPlex Gateway
β β
βββtools/listβββββββββββββββββββΊβ Returns: mcplex_find_tools, mcplex_call_tool,
β β mcplex_list_categories (~200 tokens)
β β
βββmcplex_find_toolsβββββββββββββΊβ "store a memory"
βββββββββββββββββββββββββββββββββ€ β [{name: "create_memory", desc: "...", inputSchema: {...}},
β β {name: "save_note", desc: "...", inputSchema: {...}}]
β β
βββmcplex_call_toolββββββββββββββΊβ {name: "create_memory", arguments: {...}}
βββββββββββββββββββββββββββββββββ€ β tool result (routed through security + cache + audit)
mcplex_find_tools(query)β Search for tools by natural language intent. Returns matching tools with full schemas.mcplex_call_tool(name, arguments)β Execute a discovered tool. Routes through the full security/audit/cache pipeline.mcplex_list_categories()β Browse available tool categories (server groups) with tool counts.
This works with Claude Code, Claude Desktop, Cursor, Windsurf, and any other MCP client β no custom extensions or client-side plugins required.
Routing Mode
MCPlex supports three routing modes via router.mode:
| Mode | Behavior | Client Compatibility |
|---|---|---|
metatool (default) | Returns 3 gateway meta-tools; agent discovers real tools via mcplex_find_tools | β All standard MCP clients |
passthrough | Returns all real tools directly (no routing indirection) | β All standard MCP clients |
legacy | Uses _mcplex_query param extension for filtering | β Custom clients only |
Routing Strategy
Within metatool and legacy modes, MCPlex uses a routing strategy to rank tools:
semanticβ Character n-gram embeddings with cosine similarity (recommended)keywordβ TF-IDF keyword matching (zero ML dependency)passthroughβ No filtering (baseline)
[router]
mode = "metatool" # "metatool", "passthrough", or "legacy"
strategy = "semantic" # "semantic", "keyword", or "passthrough"
top_k = 5 # Return top 5 most relevant tools
similarity_threshold = 0.3 # Minimum relevance score
cache_embeddings = true # Cache for faster repeated queries
π Security Engine
Role-Based Access Control (RBAC)
[security]
enable_rbac = true
[roles.developer]
allowed_tools = ["github/*", "database/query_*"]
[roles.admin]
allowed_tools = ["*"]
[roles.readonly]
allowed_tools = ["*/list_*", "*/get_*"]
blocked_tools = ["*/delete_*", "*/drop_*"]
Per-Server Tool Blocklists
[[servers]]
name = "database"
url = "http://localhost:8080/mcp"
blocked_tools = ["drop_table", "delete_*", "truncate_*"]
Structured Audit Logging
Every tool invocation is logged as JSON Lines:
{"timestamp":"2026-04-10T10:00:00Z","event":"tool_call","tool_name":"github/create_issue","server_name":"github","duration_ms":342,"trace_id":"a1b2c3d4"}
{"timestamp":"2026-04-10T10:00:01Z","event":"tool_blocked","tool_name":"database/drop_table","reason":"security_policy","trace_id":"e5f6g7h8"}
π Real-time Dashboard
Built-in observability dashboard at http://localhost:9090:

- Global Metrics β Total requests, tool calls, errors, tokens saved
- Per-Tool Stats β Invocation count, avg/p50/p95/p99 latency
- Server Fleet β Connected servers, transport type, tool/resource/prompt counts
- Live Event Stream β Real-time feed of all gateway activity with latency tags
Glassmorphism design with animated gradients. Auto-refreshes every 3 seconds. Zero configuration.
π¦ Response Caching
Avoid redundant upstream calls for read-only tools:
[cache]
enabled = true
ttl_seconds = 300 # 5 minute TTL
max_entries = 1000 # Max cached responses
MCPlex auto-detects read-only tools by prefix (list_*, get_*, search_*, query_*, describe_*, show_*). You can override with custom patterns:
[cache]
patterns = ["my_custom_tool", "expensive_*"]
Write operations (create_*, update_*, delete_*) are never cached by default.
π Multi-Tenant API Keys
Map API keys to RBAC roles for team-based access:
[api_keys."sk-dev-team-abc123"]
role = "developer"
description = "Dev team key"
[api_keys."sk-admin-xyz789"]
role = "admin"
description = "Admin key"
When a request comes in with Authorization: Bearer sk-dev-team-abc123, MCPlex automatically applies the developer role's RBAC policies.
π₯ Hot-Reload Configuration
Config changes apply instantly β no restart needed:
# Edit config while MCPlex is running
vim mcplex.toml
# MCPlex automatically detects changes:
# π Config file changed, reloading...
# β
Configuration reloaded successfully
π Full MCP Capability Support
MCPlex aggregates and forwards all three MCP capability types from upstream servers:
| Capability | List | Execute/Read | Routing |
|---|---|---|---|
| Tools | tools/list β aggregated | tools/call β routed to owner | β Semantic / Keyword |
| Resources | resources/list β aggregated | resources/read β routed by URI | Direct routing |
| Prompts | prompts/list β aggregated | prompts/get β routed by name | Direct routing |
Configuration Reference
[gateway]
| Key | Type | Default | Description |
|---|---|---|---|
listen | string | 127.0.0.1:3100 | MCP client connection address |
dashboard | string | β | Dashboard address (disabled if not set) |
hot_reload | bool | true | Auto-reload config on file change |
name | string | mcplex | Gateway instance name |
api_key | string | β | API key for client auth (supports ${ENV}) |
rate_limit_rps | int | 0 | Max requests/sec per client (0 = unlimited) |
[router]
| Key | Type | Default | Description |
|---|---|---|---|
mode | string | metatool | metatool, passthrough, or legacy |
strategy | string | keyword | semantic, keyword, or passthrough |
top_k | int | 5 | Maximum tools returned per query |
similarity_threshold | float | 0.3 | Minimum relevance score (0.0-1.0) |
cache_embeddings | bool | true | Cache tool embeddings |
[security]
| Key | Type | Default | Description |
|---|---|---|---|
enable_rbac | bool | false | Enable role-based access control |
enable_audit_log | bool | false | Enable structured audit logging |
audit_log_path | string | ./logs/audit.jsonl | Audit log file path |
max_log_size_mb | int | 100 | Max log file size before rotation (keeps 5 backups) |
[[servers]]
| Key | Type | Required | Description |
|---|---|---|---|
name | string | β | Unique server name |
command | string | β‘ | Executable path for stdio transport |
args | list | β | Command arguments |
url | string | β‘ | URL for HTTP transport |
env | map | β | Environment variables (supports ${VAR}) |
allowed_roles | list | β | Roles allowed to access this server |
blocked_tools | list | β | Tool blocklist patterns (glob) |
allowed_tools | list | β | Tool allowlist patterns (glob) |
enabled | bool | true | Enable/disable this server |
β‘ = One of command or url is required
Note: For stdio servers,
commandshould be the executable path (e.g.npx,/usr/bin/python3). Additional arguments go in theargsarray.
[roles.<name>]
| Key | Type | Description |
|---|---|---|
allowed_tools | list | Tool patterns this role can access (glob) |
blocked_tools | list | Tool patterns this role cannot access (glob) |
Glob Patterns: * matches any characters, ? matches a single character.
Examples: github/*, */query_*, database/get_?ser
Environment Variables
MCPlex supports ${ENV_VAR} syntax in configuration:
[[servers]]
name = "github"
command = "npx"
args = ["-y", "@modelcontextprotocol/server-github"]
env = { GITHUB_TOKEN = "${GITHUB_TOKEN}" }
Architecture
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MCPlex Gateway β
β β
β βββββββββββββββ ββββββββββββββββ ββββββββββββββββββββ β
β β Semantic β β Security β β Observability β β
β β Router β β Engine β β Collector β β
β β β β β β β β
β β β’ Embeddings β β β’ RBAC β β β’ Token Savings β β
β β β’ TopK Match β β β’ Allowlist β β β’ Latency (p99) β β
β β β’ Caching β β β’ Audit Log β β β’ Dashboard β β
β ββββββββ¬βββββββ ββββββββ¬ββββββββ ββββββββββ¬ββββββββββ β
β ββββββββββββββ¬ββββ β β
β βΌ β β
β βββββββββββββββββββββββββββββββββ β β
β β MCP Protocol Multiplexer ββββββββββ β
β β + Response Cache β β
β ββββββββββββ¬βββββββββββββββββββββ β
βββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββ
β
βββββββββββββββΌββββββββββββββββββββββ
βΌ βΌ βΌ
MCP Server MCP Server MCP Server
(stdio β (stdio β (HTTP β
persistent) persistent) stateless)
CLI Reference
mcplex [OPTIONS]
Options:
-c, --config <FILE> Config file path [default: mcplex.toml]
-v, --verbose Enable verbose logging
--listen <ADDR> Override gateway listen address
--dashboard <ADDR> Override dashboard listen address
--check Validate config and exit
-h, --help Print help
-V, --version Print version
π‘οΈ Production Hardening
API Key Authentication
Secure your gateway so only authorized agents can connect:
[gateway]
api_key = "${MCPLEX_API_KEY}" # Set via environment variable
Clients authenticate via header:
Authorization: Bearer your-secret-key
# or
X-API-Key: your-secret-key
Health checks (/health) are always unauthenticated for load balancer probes.
Rate Limiting
Prevent runaway agents from overwhelming your servers:
[gateway]
rate_limit_rps = 50 # Max 50 requests/sec per client (burst: 100)
Uses a per-client token bucket with 2x burst allowance. Returns 429 Too Many Requests when exceeded.
Log Rotation
Audit logs rotate automatically β they won't fill your disk:
[security]
enable_audit_log = true
audit_log_path = "./logs/audit.jsonl"
max_log_size_mb = 100 # Rotates at 100MB, keeps 5 backups
Files rotate as: audit.jsonl β audit.jsonl.1 β ... β audit.jsonl.5 (oldest deleted).
Network Security
Bind to localhost only (default) for local agents:
[gateway]
listen = "127.0.0.1:3100" # Localhost only
dashboard = "127.0.0.1:9090" # Dashboard also localhost
For network access, use a reverse proxy (nginx/caddy) with TLS.
Prometheus Monitoring
MCPlex exposes a Prometheus-compatible /api/metrics endpoint on the dashboard port for external monitoring:
mcplex_requests_total 1234
mcplex_tool_calls_total 567
mcplex_errors_total 3
mcplex_tokens_saved_total 45000
mcplex_tool_duration_ms{tool="create_issue",quantile="0.95"} 142
π AgentLens Integration
MCPlex pairs with AgentLens for full-stack agent observability. MCPlex handles execution, AgentLens handles visualization β together they cover 100% of the agent lifecycle.
Enable the Bridge (opt-in)
Add to your mcplex.toml:
[agentlens]
enabled = true
url = "http://127.0.0.1:3000/api/ingest"
session_name = "MCPlex Gateway"
Every tool call, security event, and routing decision is forwarded to AgentLens's timeline replay UI. The bridge is non-blocking (fire-and-forget) β it never slows down the gateway, even if AgentLens is offline.
Note: MCPlex works 100% independently without AgentLens. The bridge is entirely opt-in.
Contributing
Contributions are welcome! Please:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Run
cargo fmt && cargo clippy -- -D warnings && cargo test - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
MIT License β see LICENSE for details.
Built with π¦ Rust for the AI agent community
If MCPlex saves your context window, give it a β
