Skip to content

Latest commit

 

History

History
292 lines (223 loc) · 10.9 KB

File metadata and controls

292 lines (223 loc) · 10.9 KB

Proxy Tool

Connect to upstream MCP servers and expose their tools via mcp-devtools, enabling access to external MCP ecosystems with OAuth support, dynamic tool registration, and transparent request proxying.

Example use cases:

  • You have an upstream HTTP MCP server (e.g., Atlassian's MCP server) - but your MCP client only speaks stdio.
  • You have an upstream HTTP MCP server with OAuth, but your client fails to handle OAuth flows.
  • You have an upstream MCP server where you want to filter or restrict which tools are available to your clients.

By using the proxy tool, you can connect to the upstream server, authenticate via OAuth, and expose its tools (all or filtered) as native mcp-devtools tools.

Features

  • Dynamic Tool Registration: Automatically fetches and registers tools from upstream MCP servers before the main server starts
  • OAuth 2.0/2.1 Support: Full OAuth flow with PKCE, automatic browser opening, and secure token management
  • Streamable HTTP: Connects to upstream servers over streamable HTTP
  • Tool Filtering: Configure which upstream tools to expose or ignore using patterns
  • Transparent Proxying: Tools appear as native mcp-devtools tools to clients
  • Token Persistence: Securely stores OAuth tokens and client registration info for seamless reconnection
  • Aggregation: Combine tools from multiple upstream servers into a single unified interface

Note: The proxy tool does not utilise the security middleware, it provides tools proxied as-is from the configured upstream MCP server(s).

Configuration

IMPORTANT: The proxy tool must be explicitly enabled via ENABLE_ADDITIONAL_TOOLS to function. Upstream tools will not be registered if proxy is not enabled.

The proxy tool is configured via the PROXY_UPSTREAMS environment variable, which accepts a JSON array of upstream server configurations.

Basic Configuration

{
  "ENABLE_ADDITIONAL_TOOLS": "proxy",
  "PROXY_UPSTREAMS": "[{\"name\": \"atlassian\", \"url\": \"https://mcp.atlassian.com/v1/mcp\"}]"
}

In this example when the MCP Server is started, it will connect to the Atlassian MCP server, open your browser to authenticate via OAuth, fetch the available tools, and register them as tools.

Configuration Parameters

Each upstream server configuration supports these parameters:

  • name (required): Unique identifier for the upstream server (e.g., "atlassian", "github-mcp")
  • url (required): Server URL endpoint
  • transport (optional): Kept for backwards compatibility. Streamable HTTP is the only supported transport; an sse value logs a warning and connects over HTTP anyway.
  • ignore_tools (optional): Array of glob patterns for tools to exclude
  • include_tools (optional): Array of glob patterns for tools to include (when specified, only matching tools are exposed)
  • headers (optional): Custom HTTP headers as key-value pairs

Multiple Upstreams

{
  "ENABLE_ADDITIONAL_TOOLS": "proxy",
  "PROXY_UPSTREAMS": "[
    {
      \"name\": \"example-atlassian\",
      \"url\": \"https://mcp.atlassian.com/v1/mcp\",
      \"ignore_tools\": [\"*update*\", \"*create*\", \"*add*\", \"*edit*\", \"*delete*\", \"*jira*\"]
    },
    {
      \"name\": \"example-http-mcp\",
      \"url\": \"https://mcp.example.com/mcp\"
    }
  ]"
}

OAuth Authentication

When connecting to OAuth-enabled MCP servers:

  1. The proxy automatically detects OAuth requirements by fetching server metadata
  2. Opens your default browser to the authorisation URL
  3. Starts a local callback server to receive the authorisation code
  4. Exchanges the code for access and refresh tokens
  5. Stores tokens securely in ~/.mcp-devtools/oauth/<upstream-name>/
  6. Automatically refreshes tokens when they expire

OAuth Configuration

For servers that require client credentials, configure them via environment variables:

# Server-specific client ID (optional, falls back to dynamic registration)
PROXY_<UPSTREAM_NAME>_CLIENT_ID="your-client-id"
PROXY_<UPSTREAM_NAME>_CLIENT_SECRET="your-client-secret"

# Example for Atlassian
PROXY_ATLASSIAN_CLIENT_ID="ari:cloud:mcp::app/abc123"

Token Storage

OAuth tokens and client registration info are stored securely:

  • Location: ~/.mcp-devtools/oauth/<upstream-name>/
  • Files:
    • tokens.json: Access token, refresh token, and expiry
    • client-info.json: Dynamic client registration details
  • Permissions: 0600 (read/write for owner only)

Transport

The proxy speaks streamable HTTP only. SSE was removed in MCP spec revision 2026-07-28 and dropped here with it.

Each call is a single POST carrying the _meta fields the stateless spec requires (protocol version, client capabilities, client info) plus the Mcp-Method and Mcp-Name routing headers. There is no initialize handshake and no session ID.

Existing configs with "transport": "sse" or "http-first" still load; the value is ignored, and an sse value logs a warning.

An upstream that predates 2026-07-28 rejects the new framing with a 400. When that happens the request is retried once without the version header, routing headers and _meta, and the connection stays in that older mode for its lifetime. A warning is logged the first time it happens.

Tool Filtering

Control which upstream tools are exposed using include/ignore patterns:

Ignore Patterns

Exclude specific tools from registration:

{
  "name": "example",
  "url": "https://mcp.example.com",
  "ignore_tools": ["debug_*", "internal_*", "admin_*"]
}

Include Patterns

Only expose specific tools (whitelist mode):

{
  "name": "example",
  "url": "https://mcp.example.com",
  "include_tools": ["search*", "get*"]
}

Pattern Matching Rules:

  • Patterns use glob syntax where * matches any characters
  • Matching is case-insensitive (e.g., *jira* matches both getJiraIssue and getJIRATicket)
  • If both include_tools and ignore_tools are specified, tools must match an include pattern AND not match any ignore pattern

How It Works

1. Registration Phase (Before Server Starts)

  1. Proxy reads PROXY_UPSTREAMS configuration
  2. For each upstream:
    • Connects over streamable HTTP
    • Performs OAuth flow if required (with browser popup)
    • Fetches available tools via tools/list
    • Applies filtering rules
    • Registers each tool as a proxied tool in the registry
  3. Main MCP server starts with all tools available

2. Execution Phase (When Tools Are Called)

  1. Client calls a proxied tool (e.g., search)
  2. Proxy identifies the upstream server for that tool
  3. Proxy forwards the request to the upstream server
  4. Proxy receives the response from the POST body
  5. Proxy returns the response to the client

Architecture

┌─────────────────┐
│   MCP Client    │
│  (Claude Code)  │
└────────┬────────┘
         │ tools/call: search
         ▼
┌─────────────────────────────────┐
│     mcp-devtools Server         │
│  ┌───────────────────────────┐  │
│  │  Proxied Tool: search     │  │
│  │  (upstream: atlassian)    │  │
│  └───────────┬───────────────┘  │
└──────────────┼──────────────────┘
               │
               ▼
┌──────────────────────────────────┐
│   Upstream MCP Server            │
│   (Atlassian)                    │
│  ┌────────────────────────────┐  │
│  │  Streamable HTTP           │  │
│  │  OAuth Authentication      │  │
│  │  Native Tool: search       │  │
│  └────────────────────────────┘  │
└──────────────────────────────────┘

Examples

Example 1: Atlassian MCP Server

Connect to Atlassian's MCP server to access Confluence and Jira tools:

{
  "ENABLE_ADDITIONAL_TOOLS": "proxy",
  "PROXY_UPSTREAMS": "[{
    \"name\": \"atlassian\",
    \"url\": \"https://mcp.atlassian.com/v1/mcp\"
  }]"
}

This exposes 27 Atlassian tools including:

  • search - Search Confluence and Jira using Rovo Search
  • getConfluenceSpaces - List Confluence spaces
  • searchConfluenceUsingCql - Search Confluence with CQL
  • getJiraIssue - Retrieve Jira issue details
  • createJiraIssue - Create new Jira issues
  • And 22 more Confluence/Jira operations

Example 2: Multiple Upstreams with Filtering

{
  "ENABLE_ADDITIONAL_TOOLS": "proxy",
  "PROXY_UPSTREAMS": "[
    {
      \"name\": \"atlassian\",
      \"url\": \"https://mcp.atlassian.com/v1/mcp\",
      \"include_tools\": [\"search*\", \"get*\"]
    },
    {
      \"name\": \"internal\",
      \"url\": \"https://internal-mcp.corp/api\",
      \"ignore_tools\": [\"debug_*\", \"test_*\"],
      \"headers\": {
        \"X-Environment\": \"production\"
      }
    }
  ]"
}

Example 3: Custom OAuth Client

For servers requiring static client credentials:

export PROXY_EXAMPLE_CLIENT_ID="client-abc123"
export PROXY_EXAMPLE_CLIENT_SECRET="secret-xyz789"
export PROXY_UPSTREAMS='[{"name": "example", "url": "https://mcp.example.com"}]'

Security Considerations

  • OAuth Token Storage: Tokens stored with 0600 permissions in user home directory
  • PKCE Flow: Uses Proof Key for Code Exchange for enhanced security
  • Token Refresh: Automatically refreshes tokens before expiry
  • Transport Security: All connections use HTTPS
  • Rate Limiting: Respects upstream server rate limits
  • Error Handling: Doesn't expose sensitive auth details in errors

Environment Variables

Core Configuration

  • ENABLE_ADDITIONAL_TOOLS: Must include proxy to enable the proxy tool
  • PROXY_UPSTREAMS: JSON array of upstream server configurations

Per-Upstream OAuth (Optional)

  • PROXY_<UPSTREAM_NAME>_CLIENT_ID: Static OAuth client ID
  • PROXY_<UPSTREAM_NAME>_CLIENT_SECRET: Static OAuth client secret

Debugging

  • DEBUG: Set to 1 to enable verbose logging

Limitations

  • OAuth callback server uses a random port (3000-4000 range) if default unavailable
  • Browser must be available for OAuth flows (no headless support)
  • Tool names must be unique across all upstreams
  • Some MCP servers may have additional authentication requirements

Implementation Details

Tool Registration

Tools are registered using RegisterProxiedTool() which:

  • Bypasses normal ENABLE_ADDITIONAL_TOOLS checks
  • Stores tools in a separate proxied tools list
  • Makes tools available before the MCP server starts
  • Ensures tools appear as native first-class tools to clients