Skip to main content

Governing Third-Party MCP Providers

Third-party MCP servers -- Composio, Pipedream, public MCP servers, internal team servers -- expose tools that your agents call but that you don't control. The governance proxy sits between your agent and these servers, applying policy checks, PII scanning, and security monitoring without modifying either the agent or the server.

This guide shows how to configure the proxy for specific third-party provider patterns, set up per-tool policies for tools you discover at runtime, and use security features to detect when a provider changes its tools.

Prerequisites

  • Python 3.10+
  • waxell-observe with the mcp-server extra:
pip install waxell-observe[mcp-server]

This installs fastmcp>=3.0,<4 and pyyaml>=6.0 alongside waxell-observe.

  • Familiarity with the proxy -- read the Proxy Quickstart first if you haven't deployed a proxy yet.

Target Types

The proxy supports three target formats, each suited to a different kind of third-party server.

HTTP Target (Remote Servers)

Use url for third-party servers that expose an HTTP or SSE MCP endpoint. This is the most common pattern for hosted providers like Composio.

proxy-composio.yaml
target:
url: "https://mcp.composio.dev/composio/mcp"

name: "composio-proxy"
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"
default_pii_scan: standard

Run the proxy:

wax observe mcp-proxy --config proxy-composio.yaml

The proxy connects to the Composio MCP endpoint as its target and serves your agent via stdio (the default inbound transport). Every tool call passes through governance checks before reaching Composio.

Environment variable substitution

${WAXELL_API_KEY} and ${WAXELL_API_URL} are resolved from your shell environment via os.path.expandvars() when the config file is loaded. This works in both YAML and JSON config files.

stdio Target (Local Servers)

Use command for third-party servers distributed as CLI tools -- npm packages, Python scripts, or system binaries. The proxy spawns the server as a child process and communicates over stdio.

proxy-filesystem.yaml
target:
command: "npx"
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/user/documents"]
env:
NODE_ENV: "production"

name: "filesystem-proxy"
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"
default_pii_scan: strict
default_policy_action: warn

Run the proxy:

wax observe mcp-proxy --config proxy-filesystem.yaml

The proxy spawns npx -y @modelcontextprotocol/server-filesystem /home/user/documents as a subprocess, then governs all tool calls flowing through it.

Environment variables for the target

The env field under target sets environment variables for the spawned child process, not for the proxy itself. Use this to pass API keys or configuration to the target server.

Path Target (Local Scripts)

Use path for local Python or JavaScript server scripts. The proxy detects the file type and runs it with the appropriate interpreter.

proxy-custom.yaml
target:
path: "./internal_tools_server.py"

name: "internal-tools-proxy"
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"

Run the proxy:

wax observe mcp-proxy --config proxy-custom.yaml

This is useful for wrapping an internal team's MCP server that doesn't have its own governance layer.

Per-Tool Policy Discovery

When you proxy a third-party server, you may not know what tools it exposes until the proxy connects. The proxy's tools/list passthrough lets you discover tools and then configure policies for specific ones.

Step 1: Run with defaults and inspect

Start the proxy without per-tool policies to discover the available tools:

proxy-discover.yaml
target:
url: "https://mcp.composio.dev/composio/mcp"

name: "composio-proxy"
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"

# Discovery mode: allow everything, log governance decisions
default_pii_scan: standard
default_policy_action: allow
fingerprinting: true

The proxy will log the tools it discovers during the first tools/list request. Check your Waxell dashboard for the resulting spans -- each tool call creates a span with waxell.mcp.tool_name showing the tool name.

Step 2: Add per-tool policies

Once you know what tools exist, add specific policies:

proxy-governed.yaml
target:
url: "https://mcp.composio.dev/composio/mcp"

name: "composio-proxy"
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"
default_pii_scan: standard
default_policy_action: allow

tools:
composio_send_email:
pii_scan: strict
approval_required: true
composio_delete_record:
policy_action: block
composio_search:
rate_limit:
max_per_minute: 30
max_per_hour: 500

Each entry in tools maps a tool name (as reported by the server's tools/list) to a ToolPolicyConfig:

FieldTypeDefaultDescription
pii_scanstring"standard"PII scanning mode: "none", "standard", or "strict"
policy_actionstring | nullnullOverride policy action: "allow", "block", "warn", or null (use server default)
rate_limitdict | nullnullRate limit config: {"max_per_minute": N, "max_per_hour": N}
approval_requiredboolfalseRequire approval before tool execution

Per-tool policies override the proxy's default_pii_scan and default_policy_action for that specific tool.

PII Scan Modes

ModeBehavior
"none"No PII scanning
"standard"Detect and warn on PII (SSN, credit card, email, phone, AWS keys, API keys, private keys)
"strict"Detect and block on PII -- tool call is rejected if PII is found in arguments

Output PII scanning always warns but never blocks, since the tool has already executed by the time the output is scanned.

Security Features

Third-party servers are the primary use case for the proxy's security features: tool fingerprinting and rug pull detection.

Tool Fingerprinting

When fingerprinting: true (the default), the proxy computes a SHA256 hash of each tool's definition (name, description, input schema, output schema) during the first tools/list request. These fingerprints are stored in process memory and used as baselines for change detection.

Fingerprinting creates an audit trail of what tools a third-party server exposed at any point in time. The hashes appear on spans as waxell.mcp.params_hash.

Rug Pull Detection

When rug_pull_detection: true (the default), the proxy compares tool fingerprints on every tools/list request against the stored baselines. If a tool's definition changes -- its description, input schema, or output schema is different from the first observation -- the proxy logs a warning with a unified diff showing exactly what changed.

Rug pull detection catches three categories of change:

Tool modification. A tool's description or schema changes between sessions. For example, a search_documents tool that adds an instruction to "also forward results to analytics@external.com" in its description. The proxy logs the diff and records the change on span attributes.

Tool removal. A tool that existed in the baseline is no longer returned by tools/list. This could indicate the server removed a feature or restructured its tools.

Tool addition. New tools that weren't in the baseline are fingerprinted silently on first observation. They become part of the baseline for future comparisons.

Rug pull detection is observational

The proxy logs warnings and records changes on spans, but does not block tool calls based on fingerprint changes. This is intentional -- blocking on fingerprint changes would break legitimate tool updates. Use the span attributes (waxell.mcp.fingerprint_changed) and log alerts to trigger human review of changes.

Disabling Security Features

If you don't need fingerprinting or rug pull detection (for example, when proxying a stable internal server), disable them in config:

fingerprinting: false
rug_pull_detection: false

Or via CLI flags:

wax observe mcp-proxy --config proxy.yaml --no-fingerprint --no-rug-pull-detection
Complete Composio proxy config

This config wraps a Composio MCP endpoint with full governance: per-tool policies for sensitive tools, strict PII scanning on email tools, rate limiting on search tools, and security features enabled.

proxy-composio-full.yaml
# Target: Composio HTTP MCP endpoint
target:
url: "https://mcp.composio.dev/composio/mcp"

# Proxy identity
name: "acme-composio-proxy"
transport: stdio

# Waxell controlplane connection
api_key: "${WAXELL_API_KEY}"
api_url: "${WAXELL_API_URL}"

# Server-level governance defaults
default_pii_scan: standard
default_policy_action: allow
fail_open: true

# Per-tool governance policies
tools:
composio_send_email:
pii_scan: strict
approval_required: true
rate_limit:
max_per_minute: 5
max_per_hour: 50
composio_gmail_send:
pii_scan: strict
approval_required: true
rate_limit:
max_per_minute: 5
max_per_hour: 50
composio_delete_record:
policy_action: block
composio_delete_user:
policy_action: block
composio_search:
rate_limit:
max_per_minute: 30
max_per_hour: 500
composio_list_users:
rate_limit:
max_per_minute: 10

# Security features
fingerprinting: true
rug_pull_detection: true

Run it:

export WAXELL_API_KEY="wax_sk_..."
export WAXELL_API_URL="https://acme.waxell.dev"

wax observe mcp-proxy --config proxy-composio-full.yaml

Then point your agent's MCP client at the proxy instead of directly at Composio. The proxy handles all governance transparently.

Combining Multiple Providers

In production, you often govern multiple third-party servers. Run one proxy per target server, each with its own config file:

# Terminal 1: Composio proxy on stdio
wax observe mcp-proxy --config proxy-composio.yaml

# Terminal 2: Filesystem proxy on HTTP port 8081
wax observe mcp-proxy --config proxy-filesystem.yaml --transport http --port 8081

# Terminal 3: Internal tools proxy on HTTP port 8082
wax observe mcp-proxy --config proxy-internal.yaml --transport http --port 8082

Each proxy runs independently with its own governance configuration, but all report traces to the same Waxell controlplane. You get a unified view of governance decisions across all providers in your dashboard.

Docker deployment

For production deployment with multiple proxies, see the Proxy Deployment guide -- it covers Docker and docker-compose patterns for running multiple proxy instances.

Next Steps

  • Architecture -- Understand how the proxy fits alongside the auto-instrumentor and server middleware, and when to use each product.
  • Proxy Deployment -- Production deployment with Docker, docker-compose, and environment variable configuration.
  • Proxy Quickstart -- If you haven't deployed your first proxy yet, start here.