secure-mcp-proxy
A secure MCP (Model Context Protocol) proxy that enables switching between server transports with built-in API token authentication.
Note: This project is forked from sparfenyuk/mcp-proxy and enhanced with additional security features.
- secure-mcp-proxy
- About
- Features
- Quick Start
- Installation
- Running the Proxy
- Configuration
- Authentication
- Docker Support
- Command Line Reference
About
The mcp-proxy
is a tool that lets you switch between server transports. There are two supported modes:
- stdio to SSE/StreamableHTTP
- SSE to stdio
1. stdio to SSE/StreamableHTTP
Run a proxy server from stdio that connects to a remote SSE server.
This mode allows clients like Claude Desktop to communicate to a remote server over SSE even though it is not supportednatively.
graph LR
A["Claude Desktop"] <--> |stdio| B["mcp-proxy"]
B <--> |SSE| C["External MCP Server"]
style A fill:#ffe6f9,stroke:#333,color:black,stroke-width:2px
style B fill:#e6e6ff,stroke:#333,color:black,stroke-width:2px
style C fill:#e6ffe6,stroke:#333,color:black,stroke-width:2px
2. SSE to stdio
Run a proxy server exposing a SSE server that connects to a local stdio server.
This allows remote connections to the local stdio server. The mcp-proxy
opens a port to listen for SSE requests,spawns a local stdio server that handles MCP requests.
graph LR
A["LLM Client"] <-->|SSE| B["mcp-proxy"]
B <-->|stdio| C["Local MCP Server"]
style A fill:#ffe6f9,stroke:#333,color:black,stroke-width:2px
style B fill:#e6e6ff,stroke:#333,color:black,stroke-width:2px
style C fill:#e6ffe6,stroke:#333,color:black,stroke-width:2px
Features
- Transport switching: stdio โ SSE/StreamableHTTP
- API token authentication: Secure your MCP servers with Bearer token auth
- CORS support: Configure allowed origins for web clients
- Multiple servers: Host multiple named MCP servers simultaneously
- Docker support: Container-ready with Docker and Docker Compose
- Flexible configuration: CLI arguments, environment variables, and JSON config files
- Developer friendly: Built-in token generator and status endpoint
Quick Start
# CLI Mode (No Auth)
uv run python -m secure_mcp_proxy --port 3000 uvx mcp-server-fetch # example
# Named Server Mode
export MCP_PROXY_API_TOKEN=your-secret-token
uv run python -m secure_mcp_proxy --named-server-config servers.json --port 3000 --host 0.0.0.0
Installation
From Source
# Clone the repository
git clone https://github.com/your-username/secure-mcp-proxy
cd secure-mcp-proxy
# Install dependencies with uv (Python package manager)
uv sync
# Now you can run the proxy using: uv run python -m secure_mcp_proxy
Running the Proxy
CLI Mode
# Single server
uv run python -m secure_mcp_proxy --port 3000 uvx mcp-server-fetch
# Multiple servers
uv run python -m secure_mcp_proxy --port 3000 \
--named-server fetch 'uvx mcp-server-fetch' \
--named-server github 'npx -y @modelcontextprotocol/server-github'
# Custom host and port
uv run python -m secure_mcp_proxy --host 0.0.0.0 --port 8080 uvx mcp-server-fetch
# With environment variables and args
uv run python -m secure_mcp_proxy --port 3000 -e API_KEY value -- uvx mcp-server-fetch --timeout 30
Named Server Mode
export MCP_PROXY_API_TOKEN=token
uv run python -m secure_mcp_proxy --named-server-config servers.json --port 3000 --host 0.0.0.0
Client Mode (Connect to Remote Server)
# Connect to remote SSE server
uv run python -m secure_mcp_proxy http://remote-server.com/sse
# With authentication
uv run python -m secure_mcp_proxy --headers Authorization 'Bearer remote-token' http://remote-server.com/sse
# Using StreamableHTTP transport
uv run python -m secure_mcp_proxy --transport streamablehttp http://remote-server.com/mcp
Configuration
Environment Variables
MCP_PROXY_API_TOKEN
: API token for authentication (optional)API_ACCESS_TOKEN
: Token for connecting to remote servers (client mode)
Named Server Configuration File
Create a servers.json
file:
{
"mcpServers": {
"filesystem": {
"enabled": true,
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/Users/username/Downloads"],
"auth": true,
"env": {
"CUSTOM_VAR": "value"
}
},
"fetch": {
"enabled": true,
"command": "uvx",
"args": ["mcp-server-fetch"],
"auth": false
},
"time": {
"enabled": true,
"command": "uvx",
"args": ["mcp-server-time"]
// No "auth" field defaults to false
},
"github": {
"enabled": false,
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"auth": true,
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "your-github-token"
}
}
}
}
Configuration fields:
enabled
: Whether to start this server (default:true
)command
: Command to executeargs
: Command arguments as arrayauth
: Whether authentication is required (default:false
)env
: Environment variables for this server
Authentication
Authentication is controlled by the MCP_PROXY_API_TOKEN
environment variable. When set, you can configure which servers require authentication on a per-server basis.
Authentication Modes
- No authentication: When
MCP_PROXY_API_TOKEN
is not set, all endpoints are public - Selective authentication: When
MCP_PROXY_API_TOKEN
is set, authentication is controlled per-server:
- CLI Mode: Always public (no authentication required)
- Named Server Mode: Follow the
auth
field setting (true
= auth required,false
or omitted = public)
Setting Up Authentication
# Option 1: Environment variable
export MCP_PROXY_API_TOKEN=your-secret-token
# Option 2: .env file
echo 'MCP_PROXY_API_TOKEN="your-secret-token"' > .env
# Option 3: Inline
export MCP_PROXY_API_TOKEN=your-secret-token
uv run python -m secure_mcp_proxy --named-server-config servers.json --port 3000
Per-Server Authentication
You can configure which servers require authentication using the auth
field in your configuration file:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"],
"auth": true // Requires authentication
},
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"],
"auth": false // No authentication required
},
"time": {
"command": "uvx",
"args": ["mcp-server-time"]
// No "auth" field = defaults to false (no authentication)
}
}
}
Generate Secure Tokens
# Generate a production-ready token
uv run python -m secure_mcp_proxy.token_generator --production
# Generate multiple test tokens
uv run python -m secure_mcp_proxy.token_generator
Docker Support
Basic Docker Usage
# Build custom image with uv
cat > Dockerfile << 'EOF'
FROM ghcr.io/sparfenyuk/mcp-proxy:latest
RUN python3 -m ensurepip && pip install --no-cache-dir uv
ENV PATH="/usr/local/bin:$PATH" UV_PYTHON_PREFERENCE=only-system
ENTRYPOINT ["mcp-proxy"]
EOF
docker build -t secure-mcp-proxy .
export MCP_PROXY_API_TOKEN=token
docker run -e MCP_PROXY_API_TOKEN=$MCP_PROXY_API_TOKEN -p 3000:3000 secure-mcp-proxy \
--pass-environment --port=3000 --host=0.0.0.0 uvx mcp-server-fetch
Docker Compose
# docker-compose.yml
services:
secure-mcp-proxy:
build: .
ports:
- "3000:3000"
environment:
- MCP_PROXY_API_TOKEN=your-secret-token
volumes:
- ./servers.json:/app/servers.json
command: >
--pass-environment
--port=3000
--host=0.0.0.0
--named-server-config=/app/servers.json
restart: unless-stopped
Command Line Reference
Common Options
Option | Description | Example |
---|---|---|
--port |
Server port | --port 3000 |
--host |
Server host | --host 0.0.0.0 |
--named-server-config |
Config file path | --named-server-config servers.json |
--named-server |
Define named server | --named-server fetch 'uvx mcp-server-fetch' |
--allow-origin |
CORS origins | --allow-origin "*" |
--debug |
Enable debug logging | --debug |
Troubleshooting
Common Issues
- ENOENT error: Use full path to binary in Claude Desktop config
- Port already in use: Change port with
--port
option - 401/403 errors: Check your
MCP_PROXY_API_TOKEN
environment variable - Module not found: Ensure you're in the correct directory and dependencies are installed
Debug Mode
# Enable detailed logging
uv run python -m secure_mcp_proxy --debug --port 3000 uvx mcp-server-fetch