README.md•9.33 kB
# 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](https://github.com/sparfenyuk/mcp-proxy) and enhanced with additional security features.
- [secure-mcp-proxy](#secure-mcp-proxy)
- [About](#about)
- [Features](#features)
- [Quick Start](#quick-start)
- [Installation](#installation)
- [Running the Proxy](#running-the-proxy)
- [Configuration](#configuration)
- [Authentication](#authentication)
- [Docker Support](#docker-support)
- [Command Line Reference](#command-line-reference)
## About
The `mcp-proxy` is a tool that lets you switch between server transports. There are two supported modes:
1. stdio to SSE/StreamableHTTP
2. 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 supported
natively.
```mermaid
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.
```mermaid
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
```bash
# 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
```bash
# 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
```bash
# 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
```bash
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)
```bash
# 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:
```json
{
"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 execute
- `args`: Command arguments as array
- `auth`: 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
1. **No authentication**: When `MCP_PROXY_API_TOKEN` is not set, all endpoints are public
2. **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
```bash
# 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:
```json
{
"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
```bash
# 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
```bash
# 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
```yaml
# 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
1. **ENOENT error**: Use full path to binary in Claude Desktop config
2. **Port already in use**: Change port with `--port` option
3. **401/403 errors**: Check your `MCP_PROXY_API_TOKEN` environment variable
4. **Module not found**: Ensure you're in the correct directory and dependencies are installed
### Debug Mode
```bash
# Enable detailed logging
uv run python -m secure_mcp_proxy --debug --port 3000 uvx mcp-server-fetch
```