mcp-proxy

module
v0.0.0-...-7d1323b Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 29, 2026 License: MIT

README

mcp-proxy

A single-binary MCP proxy that connects AI clients (Claude, Copilot, Cursor, etc.) to one or more upstream MCP servers, with built-in authentication support for Google Cloud and static bearer tokens.

Instead of flooding the LLM context with dozens of tools from multiple servers, mcp-proxy exposes a single mcp meta-tool so the model can discover and invoke upstream tools on demand. A direct mode is also available when full tool visibility is preferred.

Installation

go install github.com/Mrflatt/mcp-proxy/cmd/mcp-proxy@latest

Requires Go 1.21+.

Quick start

  1. Create ~/.config/mcp-proxy/config.json:
{
  "servers": {
    "my-api": {
      "url": "https://my-api.example.com/mcp",
      "auth": {
        "type": "google-idtoken",
        "audience": "https://my-api.example.com"
      }
    }
  }
}
  1. Add mcp-proxy to your client config:

Claude Desktop (~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "proxy": {
      "command": "mcp-proxy"
    }
  }
}

VS Code Copilot (.vscode/mcp.json or run MCP: Open User Configuration):

{
  "servers": {
    "proxy": {
      "command": "mcp-proxy"
    }
  }
}

Claude Code — run once to register:

claude mcp add --transport stdio proxy -- mcp-proxy

Or edit ~/.claude.json directly:

{
  "mcpServers": {
    "proxy": {
      "type": "stdio",
      "command": "mcp-proxy",
      "args": []
    }
  }
}

GitHub Copilot CLI (~/.copilot/mcp-config.json):

{
  "mcpServers": {
    "proxy": {
      "type": "stdio",
      "command": "mcp-proxy",
      "args": []
    }
  }
}

How it works

Proxy mode (default)

mcp-proxy exposes a single mcp tool to the AI client:

Call Description
mcp({}) List all servers with tool counts
mcp({ server: "name" }) List tools for a specific server
mcp({ search: "query" }) Search tools by server or tool name
mcp({ tool: "server-toolname", arguments: {} }) Call a tool

Tool names use the server-toolname convention, so my-api-list_users identifies the list_users tool on the my-api server.

Direct mode

When you want the LLM to see all upstream tools natively, use --direct:

mcp-proxy --direct

Each upstream tool is registered directly as servername-toolname. You can also enable this per server in config with "directTools": true, or for specific tools with "directTools": ["tool1", "tool2"].

Configuration

Default config location: ~/.config/mcp-proxy/config.json
Override with: mcp-proxy --config /path/to/config.json

Full config reference
{
  "servers": {
    "http-server": {
      "url": "https://api.example.com/mcp",
      "headers": {
        "X-Custom-Header": "value"
      },
      "auth": {
        "type": "bearer",
        "tokenEnv": "MY_API_TOKEN"
      },
      "eager": true,
      "keepalive": "30s",
      "excludeTools": ["internal_tool", "debug_tool"],
      "directTools": false
    },

    "stdio-server": {
      "command": "my-mcp-server",
      "args": ["--flag"],
      "env": {
        "SERVER_USERNAME": "${SERVER_USERNAME}",
        "SERVER_PASSWORD": "${SERVER_PASSWORD}"
      }
    }
  }
}
Server options
Field Type Description
url string HTTP upstream endpoint (streamable MCP)
headers object Extra HTTP headers added to every request. Values support ${VAR} interpolation
command string Command to run as a stdio MCP server
args array Arguments for the stdio command
env object Extra environment variables for the subprocess. Values support ${VAR} interpolation
auth object Authentication config (see below)
eager bool Connect at startup instead of on first use
keepalive string Ping interval to keep the connection alive (e.g. "30s")
directTools true or ["tool1","tool2"] Expose all or specific tools directly, bypassing the meta-tool layer
noPrefix true or ["tool1","tool2"] Omit the server name prefix from tool names (toolname instead of server-toolname). true = all tools, array = only those tools. Only safe when unprefixed names are unique across all servers
excludeTools array Upstream tool names to hide from the LLM
Authentication
No auth (default)

Omit the auth field entirely.

Static bearer token
{
  "type": "bearer",
  "tokenEnv": "MY_API_TOKEN"
}

Use token for a literal value or tokenEnv to read from an environment variable.

Google ID token (OIDC)
{
  "type": "google-idtoken",
  "audience": "https://api.example.com"
}

Uses Application Default Credentials. Run gcloud auth application-default login to set up ADC locally.

Add "includeEmail": true to include the service account email in the token claim (required by some IAP-protected endpoints).

Google access token (OAuth2)
{
  "type": "google-access-token",
  "scopes": ["https://www.googleapis.com/auth/cloud-platform"]
}
Service account impersonation

Add serviceAccount to either Google type to impersonate a service account before fetching the token:

{
  "type": "google-idtoken",
  "audience": "https://api.example.com",
  "serviceAccount": "proxy-sa@my-project.iam.gserviceaccount.com",
  "includeEmail": true
}
{
  "type": "google-access-token",
  "scopes": ["https://www.googleapis.com/auth/cloud-platform"],
  "serviceAccount": "proxy-sa@my-project.iam.gserviceaccount.com"
}

Your ADC principal needs the roles/iam.serviceAccountTokenCreator role on the target service account.

Mixing proxy and direct mode

You can expose some servers directly while keeping others behind the meta-tool layer. directTools accepts true for all tools or a list of specific tool names:

{
  "servers": {
    "always-needed": {
      "url": "https://core.example.com/mcp",
      "directTools": true
    },
    "partially-direct": {
      "url": "https://other.example.com/mcp",
      "directTools": ["ping", "list_interfaces"]
    },
    "large-api": {
      "url": "https://large.example.com/mcp"
    }
  }
}

always-needed tools appear directly in the client's tool list as always-needed-toolname. partially-direct exposes only ping and list_interfaces directly — its other tools are still discoverable via mcp({ server: "partially-direct" }). large-api tools are only visible after calling mcp({}) or mcp({ search: "..." }).

[!NOTE] mcp({}) and mcp({ search }) only list tools not exposed via directTools.

[!NOTE] noPrefix: true is safe only when tool names are unique across all servers. If two servers expose a tool with the same name, the last one wins.

CLI flags

Flag Default Description
--config ~/.config/mcp-proxy/config.json Path to config file
--direct false Expose all upstream tools directly (overrides per-server config)

Directories

Path Synopsis
cmd
mcp-proxy command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL