External MCP (SecureMCPProxy)
Inline gateway for 3rd-party MCP servers you don't control. Wrap Snowflake, Databricks, Salesforce, and any external MCP server with MACAW security—no server modifications required.
When to Use
| Use Case | Adapter |
|---|---|
| Building your own MCP server | SecureMCP |
| Connecting to Snowflake MCP | SecureMCPProxy |
| Connecting to Databricks MCP | SecureMCPProxy |
| Connecting to Salesforce MCP | SecureMCPProxy |
| Wrapping any 3rd-party MCP server | SecureMCPProxy |
Quick Start
from macaw_adapters.mcp import SecureMCPProxy
# Connect to Snowflake MCP server (running with HTTP transport)
proxy = SecureMCPProxy(
app_name="snowflake-mcp",
upstream_url="http://localhost:9000/mcp"
)
# List available tools
tools = proxy.list_tools()
for tool in tools:
print(f" {tool['name']}: {tool['description']}")
# Call a tool
result = proxy.call_tool("run_snowflake_query", {
"statement": "SELECT CURRENT_USER(), CURRENT_ROLE()"
})
print(result)import os
from macaw_adapters.mcp import SecureMCPProxy
# Connect to Salesforce MCP server via subprocess
proxy = SecureMCPProxy(
app_name="salesforce-dx",
command=["npx", "@salesforce/mcp", "--orgs", "DEFAULT"],
env={"HOME": os.environ["HOME"]} # Pass required env vars
)
# Use same API as HTTP transport
tools = proxy.list_tools()
result = proxy.call_tool("query", {"soql": "SELECT Id FROM Account"})Constructor
class SecureMCPProxy:
def __init__(
self,
app_name: str, # Application name (required)
# HTTP transport (pick one)
upstream_url: str = None, # URL of upstream MCP server
upstream_auth: dict = None, # Auth config (see below)
# stdio transport (pick one)
command: list[str] = None, # Command to start MCP server
env: dict = None, # Environment variables
# Identity
iam_token: str = None, # IAM token for user identity
user_name: str = None, # User name
intent_policy: dict = None # MAPL intent policy
)Transport Selection
Provide either upstream_url (HTTP transport) or command (stdio transport), not both. HTTP transport is for remote MCP servers; stdio transport spawns a local subprocess.
Authentication Options
# Bearer token authentication
proxy = SecureMCPProxy(
app_name="my-proxy",
upstream_url="https://api.example.com/mcp",
upstream_auth={"type": "bearer", "token": "sk-xxx"}
)
# API key authentication
proxy = SecureMCPProxy(
app_name="my-proxy",
upstream_url="https://api.example.com/mcp",
upstream_auth={
"type": "api_key",
"api_key": "my-api-key",
"header_name": "X-API-Key"
}
)Methods
| Method | Description |
|---|---|
| call_tool(name, params) | Call a tool through MACAW security |
| list_tools() | List available tools from upstream |
| get_tool_schema(name) | Get schema for a specific tool |
| bind_to_user(client) | Bind proxy to user identity for multi-tenant |
| refresh_tools() | Re-discover tools from upstream |
Multi-User Pattern
Use bind_to_user() to create per-user proxies with proper identity propagation:
from macaw_adapters.mcp import SecureMCPProxy
from macaw_client import MACAWClient, RemoteIdentityProvider
# Service creates shared proxy
proxy = SecureMCPProxy(
app_name="data-platform",
upstream_url="http://localhost:9000/mcp"
)
# Authenticate users via your IdP (Keycloak, Okta, etc.)
alice_jwt, _ = RemoteIdentityProvider().login("alice", "Alice123!")
alice = MACAWClient(
user_name="alice",
iam_token=alice_jwt,
app_name="data-platform"
)
alice.register()
bob_jwt, _ = RemoteIdentityProvider().login("bob", "Bob@123!")
bob = MACAWClient(
user_name="bob",
iam_token=bob_jwt,
app_name="data-platform"
)
bob.register()
# Bind proxy to each user's identity
alice_proxy = proxy.bind_to_user(alice)
bob_proxy = proxy.bind_to_user(bob)
# Each user's calls use their identity and policy
alice_result = alice_proxy.call_tool("list_databases", {})
bob_result = bob_proxy.call_tool("run_query", {"sql": "SELECT 1"})Per-Invocation Security
Even with persistent connections (stdio), MACAW creates a fresh AuthenticatedContext for each call. This solves the "shared context" problem in standard MCP—each invocation carries the correct user identity and is cryptographically signed.
Security Model
Identity Propagation
User identity embeds in invocation—not impersonation, cryptographic proof
Cryptographic Signing
Every call signed with user's session key, binding identity to exact parameters
Policy Enforcement
MAPL policies evaluated before forwarding to upstream
Audit Logging
All operations logged with cryptographic proof of authorization
The inline gateway pattern provides the same security guarantees as a centralized gateway—but distributed. See the Inline Gateway Whitepaper for architectural details.
Properties
| Property | Type | Description |
|---|---|---|
| proxy.app_name | str | Application name |
| proxy.upstream_url | str | Upstream URL (HTTP transport) |
| proxy.agent_id | str | MACAW agent ID |
| proxy.server_id | str | Alias for agent_id |
| proxy.tool_schemas | dict | Discovered tool schemas |
| proxy.is_connected | bool | Connection status |