Governance Proxy Quickstart
The governance proxy wraps any MCP server -- including third-party servers you don't control -- with policy checks, PII scanning, rate limiting, and full observability. Your agent connects to the proxy instead of the target server. No code changes to the agent or the server.
In this quickstart, you'll wrap a local MCP filesystem server with the proxy and see governed traces in your dashboard -- in under 5 minutes.
By the end, you'll have:
- A governance proxy running between your agent and an MCP server
- Automatic tracing of every proxied tool call with governance attributes
- A config file for per-tool policies
Prerequisites
- Python 3.10+
- A Waxell API key -- get one from your Waxell dashboard
- Node.js 18+ -- for the MCP filesystem server used in examples
Step 1: Install
Install waxell-observe with the MCP server extra:
pip install waxell-observe[mcp-server]
This installs waxell-observe along with fastmcp>=3.0,<4 (MCP server framework) and pyyaml>=6.0 (config file support). The wax CLI is included automatically.
If you already have waxell-observe installed, add the server extra:
pip install "waxell-observe[mcp-server]"
Step 2: One-Liner Proxy
The fastest way to start is the --target flag. This wraps a target server with governance in a single command:
wax observe mcp-proxy --target "npx -y @modelcontextprotocol/server-filesystem /tmp/mcp-test"
That's it. The proxy:
- Starts the MCP filesystem server as a child process
- Wraps it with governance middleware (PII scanning, policy checks, rate limiting)
- Adds security middleware (tool fingerprinting, rug pull detection)
- Listens on stdio for incoming MCP client connections
Your agent connects to the proxy exactly as it would connect to the target server -- no code changes needed.
The --target flag creates a ProxyConfig with the target as a local path and all defaults enabled: standard PII scanning, fail-open governance, tool fingerprinting, and rug pull detection. The proxy appears as a normal MCP server to your agent.
Connect your Waxell API key
To get governed traces flowing to your dashboard, pass your API key:
export WAXELL_API_KEY="wax_sk_..."
export WAXELL_API_URL="https://acme.waxell.dev"
wax observe mcp-proxy --target "npx -y @modelcontextprotocol/server-filesystem /tmp/mcp-test"
The CLI reads WAXELL_API_KEY and WAXELL_API_URL from environment variables automatically. You can also pass them as flags:
wax observe mcp-proxy \
--target "npx -y @modelcontextprotocol/server-filesystem /tmp/mcp-test" \
--api-key wax_sk_... \
--api-url https://acme.waxell.dev
Step 3: See Your Traces
After running the proxy and making tool calls through it, open your Waxell dashboard and navigate to the Traces view. You'll see server-side spans for each proxied tool call:
| Attribute | Example Value | Description |
|---|---|---|
| Span name | tools/call waxell-proxy:read_file | Format: tools/call {proxy-name}:{tool} |
waxell.mcp.server_side | true | Indicates a server-side span |
waxell.mcp.middleware_active | true | Governance middleware processed this call |
waxell.mcp.governance_checked | true | Governance was active |
waxell.mcp.governance_action | allow | Policy decision |
waxell.mcp.pii_detected | false | Whether PII was found |
waxell.mcp.params_hash | a1b2c3d4e5f67890 | SHA256 fingerprint of the arguments |
The proxy creates its own root traces (server-side, SpanKind.SERVER). These are separate from any client-side traces your agent creates. This means you get two views: the agent's perspective and the proxy's perspective.
Step 4: Add a Config File
The one-liner is great for getting started, but real deployments need per-tool policies. Create a config file to customize governance per tool.
Create proxy.yaml:
# Target: local MCP filesystem server
target:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp/mcp-test"]
# Proxy identity
name: "fs-governance-proxy"
# Governance defaults
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"
default_pii_scan: standard
default_policy_action: allow
fail_open: true
# Per-tool policies
tools:
write_file:
pii_scan: strict
approval_required: true
create_directory:
policy_action: warn
Run the proxy with your config file:
wax observe mcp-proxy --config proxy.yaml
Now write_file calls get strict PII scanning and require approval, while create_directory calls emit warnings. All other tools use the server defaults (standard PII scanning, allow policy).
Config files support ${VAR_NAME} syntax for environment variables. The proxy resolves these before parsing the YAML/JSON. This means you can keep secrets out of your config files.
Three Target Formats
The target field in your config file supports three formats depending on how you connect to the backend server:
| Format | When to Use | Example |
|---|---|---|
| URL | Remote HTTP MCP server | target: { url: "http://remote-server:9000/mcp" } |
| Command | Local process via stdio | target: { command: "npx", args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"] } |
| Path | Local Python/JS script | target: { path: "./my_server.py" } |
The --target CLI flag auto-detects the format: URLs starting with http:// or https:// use the URL format, everything else uses the path format.
What the Proxy Does
When your agent makes a tool call through the proxy, the governance pipeline runs:
The proxy also runs security middleware on tools/list calls to capture tool fingerprints and detect rug pulls (tool definition changes between sessions).
Governance is fail-open
If the Waxell controlplane is unreachable or the PII scanner throws an error, the tool call proceeds normally. Governance errors never break your agent's workflow. This fail-open behavior is logged so you can monitor governance health.
Full proxy.yaml with all options
# Target server (required)
target:
url: "http://remote-server:9000/mcp"
# OR:
# command: "npx"
# args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
# env:
# NODE_ENV: "production"
# OR:
# path: "./my_server.py"
# Proxy server settings
name: "my-governance-proxy"
transport: stdio # "stdio" or "http"
host: "0.0.0.0" # HTTP bind host (only used when transport=http)
port: 8080 # HTTP bind port (only used when transport=http)
# Governance
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"
default_pii_scan: standard # "none", "standard", "strict"
default_policy_action: allow # "allow", "block", "warn"
fail_open: true
# Per-tool policies
tools:
send_email:
pii_scan: strict
approval_required: true
rate_limit:
max_per_minute: 10
max_per_hour: 100
delete_records:
policy_action: block
read_file:
pii_scan: none # skip PII scanning for read-only tools
# Security
fingerprinting: true # capture tool fingerprints on first tools/list
rug_pull_detection: true # alert on tool definition changes
Next Steps
- Proxy Deployment -- CLI reference, Docker, docker-compose, and production configuration
- Governing Third-Party Providers -- Wrap Composio, Pipedream, and other remote MCP servers
- Architecture -- How the proxy fits with the auto-instrumentor and server middleware