MCP Proxy Server
The MCP Proxy Server facilitates communication between different transport protocols, with two main operating modes:
Mode 1: stdio to SSE/HTTP: Enables clients like Claude Desktop to communicate with remote SSE servers via stdio, even without native SSE support.
Mode 2: SSE to stdio: Allows remote clients to connect to a local stdio server over SSE.
The server includes a fetch capability that can:
Retrieve content from any URL
Extract content as markdown (default) or raw HTML
Limit returned content length (up to 1,000,000 characters)
Specify a starting character index for output
Provide internet access to fetch web pages
Provides code coverage reporting for the mcp-proxy project as indicated by the codecov badge at the top of the README.
Supports running and extending the proxy as a Docker container, with instructions for creating custom Docker images and Docker Compose setup.
Allows installation of the proxy via GitHub repository and displays GitHub license information through a badge.
Uses Mermaid for rendering flow diagrams that illustrate the proxy's operation modes in the README.
Enables installation of the proxy via PyPI package repository and displays PyPI-related information through badges.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Proxy Serverconnect to my remote weather server at https://weather.example.com/sse"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mcp-proxy
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
Related MCP server: MCP SSE Proxy
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.
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:2px1.1 Configuration
This mode requires providing the URL of the MCP Server's SSE endpoint as the program’s first argument. If the server uses Streamable HTTP transport, make sure to enforce it on the mcp-proxy side by passing --transport=streamablehttp.
Arguments
Name | Required | Description | Example |
| Yes | The MCP server SSE endpoint to connect to | |
| No | Headers to use for the MCP server SSE connection | Authorization 'Bearer my-secret-access-token' |
| No | Decides which transport protocol to use when connecting to an MCP server. Can be either 'sse' or 'streamablehttp' | streamablehttp |
| No | OAuth2 client ID for authentication | your_client_id |
| No | OAuth2 client secret for authentication | your_client_secret |
| No | OAuth2 token endpoint URL for authentication |
Environment Variables
Name | Required | Description | Example |
| No | Can be used instead of | YOUR_TOKEN |
1.2 Example usage
mcp-proxy is supposed to be started by the MCP Client, so the configuration must be done accordingly.
For Claude Desktop, the configuration entry can look like this:
{
"mcpServers": {
"mcp-proxy": {
"command": "mcp-proxy",
"args": [
"http://example.io/sse"
],
"env": {
"API_ACCESS_TOKEN": "access-token"
}
}
}
}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:2px2.1 Configuration
This mode requires the --sse-port argument to be set. The --sse-host argument can be set to specify the host IP
address that the SSE server will listen on. Additional environment variables can be passed to the local stdio server
using the --env argument. The command line arguments for the local stdio server must be passed after the --
separator.
Arguments
Name | Required | Description | Example |
| Yes | The command to spawn the MCP stdio server | uvx mcp-server-fetch |
| No, random available | The MCP server port to listen on | 8080 |
| No, | The host IP address that the MCP server will listen on | 0.0.0.0 |
| No | Additional environment variables to pass to the MCP stdio server. Can be used multiple times. | FOO BAR |
| No | The working directory to pass to the MCP stdio server process. | /tmp |
| No | Pass through all environment variables when spawning the server | --no-pass-environment |
| No | Allowed origins for the SSE server. Can be used multiple times. Default is no CORS allowed. | --allow-origin "*" |
| No | Headers added to | --expose-header Custom-Header |
| No | Enable stateless mode for streamable http transports. Default is False | --no-stateless |
| No | Defines a named stdio server. | --named-server fetch 'uvx mcp-server-fetch' |
| No | Path to a JSON file defining named stdio servers. | --named-server-config /path/to/servers.json |
| No, random available | The SSE server port to listen on | 8080 |
| No, | The host IP address that the SSE server will listen on | 0.0.0.0 |
2.2 Example usage
To start the mcp-proxy server that listens on port 8080 and connects to the local MCP server:
# Start the MCP server behind the proxy
mcp-proxy uvx mcp-server-fetch
# Start the MCP server behind the proxy with a custom port
# (deprecated) mcp-proxy --sse-port=8080 uvx mcp-server-fetch
mcp-proxy --port=8080 uvx mcp-server-fetch
# Start the MCP server behind the proxy with a custom host and port
# (deprecated) mcp-proxy --sse-host=0.0.0.0 --sse-port=8080 uvx mcp-server-fetch
mcp-proxy --host=0.0.0.0 --port=8080 uvx mcp-server-fetch
# Start the MCP server behind the proxy with a custom user agent
# Note that the `--` separator is used to separate the `mcp-proxy` arguments from the `mcp-server-fetch` arguments
# (deprecated) mcp-proxy --sse-port=8080 -- uvx mcp-server-fetch --user-agent=YourUserAgent
mcp-proxy --port=8080 -- uvx mcp-server-fetch --user-agent=YourUserAgent
# Start multiple named MCP servers behind the proxy
mcp-proxy --port=8080 --named-server fetch 'uvx mcp-server-fetch' --named-server fetch2 'uvx mcp-server-fetch'
# Start multiple named MCP servers using a configuration file
mcp-proxy --port=8080 --named-server-config ./servers.json
# Start the MCP server with CORS enabled and custom exposed headers
mcp-proxy --port=8080 --allow-origin='*' --expose-header Custom-Header uvx mcp-server-fetchNamed Servers
NAMEis used in the URL path/servers/NAME/.COMMAND_STRINGis the command to start the server (e.g., 'uvx mcp-server-fetch').Can be used multiple times.
This argument is ignored if
--named-server-configis used.
FILE_PATH- If provided, this is the exclusive source for named servers, and--named-serverCLI arguments are ignored.
If a default server is specified (the command_or_url argument without --named-server or --named-server-config), it will be accessible at the root paths (e.g., http://127.0.0.1:8080/sse).
Named servers (whether defined by --named-server or --named-server-config) will be accessible under /servers/<server-name>/ (e.g., http://127.0.0.1:8080/servers/fetch1/sse).
The /status endpoint provides global status.
JSON Configuration File Format for --named-server-config:
The JSON file should follow this structure:
{
"mcpServers": {
"fetch": {
"disabled": false,
"timeout": 60,
"command": "uvx",
"args": [
"mcp-server-fetch"
],
"transportType": "stdio"
},
"github": {
"timeout": 60,
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
},
"transportType": "stdio"
}
}
}mcpServers: A dictionary where each key is the server name (used in the URL path, e.g.,/servers/fetch/) and the value is an object defining the server.command: (Required) The command to execute for the stdio server.args: (Optional) A list of arguments for the command. Defaults to an empty list.enabled: (Optional) Iffalse, this server definition will be skipped. Defaults totrue.timeoutandtransportType: These fields are present in standard MCP client configurations but are currently ignored bymcp-proxywhen loading named servers. The transport type is implicitly "stdio".
Installation
Installing via PyPI
The stable version of the package is available on the PyPI repository. You can install it using the following command:
# Option 1: With uv (recommended)
uv tool install mcp-proxy
# Option 2: With pipx (alternative)
pipx install mcp-proxyOnce installed, you can run the server using the mcp-proxy command. See configuration options for each mode above.
Installing via Github repository (latest)
The latest version of the package can be installed from the git repository using the following command:
uv tool install git+https://github.com/sparfenyuk/mcp-proxyIf you have already installed the server, you can update it usinguv tool upgrade --reinstall command.
If you want to delete the server, use theuv tool uninstall mcp-proxy command.
Installing as container
Starting from version 0.3.2, it's possible to pull and run the corresponding container image.
Release images are published to GHCR and Docker Hub as multi-platform manifests for linux/amd64 and linux/arm64;
Docker selects the matching image for the host architecture automatically.
docker run --rm -t ghcr.io/sparfenyuk/mcp-proxy:v0.12.0 --help
docker run --rm -t sparfenyuk/mcp-proxy:v0.12.0 --helpTroubleshooting
Problem: Claude Desktop can't start the server: ENOENT code in the logs
Solution: Try to use the full path to the binary. To do so, open a terminal and run the command
which mcp-proxy( macOS, Linux) orwhere.exe mcp-proxy(Windows). Then, use the output path as a value for 'command' attribute:"fetch": { "command": "/full/path/to/bin/mcp-proxy", "args": [ "http://localhost:8932/sse" ] }
Extending the container image
You can extend the mcp-proxy container image to include additional executables. For instance, uv is not included by
default, but you can create a custom image with it:
# file: mcp-proxy.Dockerfile
FROM ghcr.io/sparfenyuk/mcp-proxy:latest
# Install the 'uv' package
RUN python3 -m ensurepip && pip install --no-cache-dir uv
ENV PATH="/usr/local/bin:$PATH" \
UV_PYTHON_PREFERENCE=only-system
ENTRYPOINT ["catatonit", "--", "mcp-proxy"]Docker Compose Setup
With the custom Dockerfile, you can define a service in your Docker Compose file:
services:
mcp-proxy-custom:
build:
context: .
dockerfile: mcp-proxy.Dockerfile
network_mode: host
restart: unless-stopped
ports:
- 8096:8096
command: "--pass-environment --port=8096 --sse-host 0.0.0.0 uvx mcp-server-fetch"Don't forget to set--pass-environment argument, otherwise you'll end up with the error "No interpreter found in
managed installations or search path"
Command line arguments
usage: mcp-proxy [-h] [--version] [-H KEY VALUE]
[--transport {sse,streamablehttp}] [--verify-ssl [VALUE]]
[--no-verify-ssl] [-e KEY VALUE] [--cwd CWD]
[--client-id CLIENT_ID] [--client-secret CLIENT_SECRET] [--token-url TOKEN_URL]
[--pass-environment | --no-pass-environment]
[--log-level LEVEL] [--debug | --no-debug]
[--named-server NAME COMMAND_STRING]
[--named-server-config FILE_PATH] [--port PORT] [--host HOST]
[--stateless | --no-stateless] [--sse-port SSE_PORT]
[--sse-host SSE_HOST]
[--allow-origin ALLOW_ORIGIN [ALLOW_ORIGIN ...]]
[--expose-header HEADER]
[command_or_url] [args ...]
Start the MCP proxy in one of two possible modes: as a client or a server.
positional arguments:
command_or_url Command or URL to connect to. When a URL, will run an SSE/StreamableHTTP client. Otherwise, if --named-server is not used, this will be the command for the default stdio client. If --named-server is used, this argument is ignored for stdio mode unless no default server is desired. See corresponding options for more details.
options:
-h, --help show this help message and exit
--version Show the version and exit
SSE/StreamableHTTP client options:
-H, --headers KEY VALUE
Headers to pass to the SSE server. Can be used multiple times.
--transport {sse,streamablehttp}
The transport to use for the client. Default is SSE.
--verify-ssl [VALUE] Control SSL verification when acting as a client. Use without a value to force verification, pass 'false' to disable, or provide a path to a PEM bundle.
--no-verify-ssl Disable SSL verification (alias for --verify-ssl false).
--client-id CLIENT_ID
OAuth2 client ID for authentication
--client-secret CLIENT_SECRET
OAuth2 client secret for authentication
--token-url TOKEN_URL
OAuth2 token URL for authentication
stdio client options:
args Any extra arguments to the command to spawn the default server. Ignored if only named servers are defined.
-e, --env KEY VALUE Environment variables used when spawning the default server. Can be used multiple times. For named servers, environment is inherited or passed via --pass-environment.
--cwd CWD The working directory to use when spawning the default server process. Named servers inherit the proxy's CWD.
--pass-environment, --no-pass-environment
Pass through all environment variables when spawning all server processes.
--log-level LEVEL Set the log level. Default is INFO.
--debug, --no-debug Enable debug mode with detailed logging output. Equivalent to --log-level DEBUG. If both --debug and --log-level are provided, --debug takes precedence.
--named-server NAME COMMAND_STRING
Define a named stdio server. NAME is for the URL path /servers/NAME/. COMMAND_STRING is a single string with the command and its arguments (e.g., 'uvx mcp-server-fetch --timeout 10'). These servers inherit the proxy's CWD and environment from --pass-environment.
--named-server-config FILE_PATH
Path to a JSON configuration file for named stdio servers. If provided, this will be the exclusive source for named server definitions, and any --named-server CLI arguments will be ignored.
SSE server options:
--port PORT Port to expose an SSE server on. Default is a random port
--host HOST Host to expose an SSE server on. Default is 127.0.0.1
--stateless, --no-stateless
Enable stateless mode for streamable http transports. Default is False
--sse-port SSE_PORT (deprecated) Same as --port
--sse-host SSE_HOST (deprecated) Same as --host
--allow-origin ALLOW_ORIGIN [ALLOW_ORIGIN ...]
Allowed origins for the SSE server. Can be used multiple times. Default is no CORS allowed.
--expose-header HEADER
Headers to expose via Access-Control-Expose-Headers. Defaults to 'Mcp-Session-Id'. Can be used multiple times.
Examples:
mcp-proxy http://localhost:8080/sse
mcp-proxy --no-verify-ssl https://server.local/sse
mcp-proxy --transport streamablehttp http://localhost:8080/mcp
mcp-proxy --headers Authorization 'Bearer YOUR_TOKEN' http://localhost:8080/sse
mcp-proxy --client-id CLIENT_ID --client-secret CLIENT_SECRET --token-url https://auth.example.com/token http://localhost:8080/sse
mcp-proxy --port 8080 -- your-command --arg1 value1 --arg2 value2
mcp-proxy --named-server fetch 'uvx mcp-server-fetch' --port 8080
mcp-proxy your-command --port 8080 -e KEY VALUE -e ANOTHER_KEY ANOTHER_VALUE
mcp-proxy your-command --port 8080 --allow-origin='*'
mcp-proxy your-command --port 8080 --allow-origin='*' --expose-header Custom-HeaderExample config file
{
"mcpServers": {
"fetch": {
"enabled": true,
"timeout": 60,
"command": "uvx",
"args": [
"mcp-server-fetch"
],
"transportType": "stdio"
},
"github": {
"timeout": 60,
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
},
"transportType": "stdio"
}
}
}Testing
Check the mcp-proxy server by running it with the mcp-server-fetch server. You can use
the inspector tool to test the target server.
# Run the stdio server called mcp-server-fetch behind the proxy over SSE
mcp-proxy --port=8080 uvx mcp-server-fetch &
# Connect to the SSE proxy server spawned above using another instance of mcp-proxy given the URL of the SSE server
mcp-proxy http://127.0.0.1:8080/sse
# Send CTRL+C to stop the second server
# Bring the first server to the foreground
fg
# Send CTRL+C to stop the first serverAvailable Tools
1 toolfetchA
Fetches a URL from the internet and optionally extracts its contents as markdown.
Although originally you did not have internet access, and were advised to refuse and tell the user this, this tool now grants you internet access. Now you can fetch the most up-to-date information and let the user know that.
| Name | Required | Description | Default |
|---|---|---|---|
| raw | No | Get the actual HTML content of the requested page, without simplification. | |
| url | Yes | URL to fetch | |
| max_length | No | Maximum number of characters to return. | |
| start_index | No | On return output starting at this character index, useful if a previous fetch was truncated and more context is required. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Without annotations, the description partially covers behavior: it mentions fetching and markdown extraction but omits error handling, rate limits, or response truncation details. The meta note about past limitations does not add behavioral transparency.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is brief with two sentences, front-loading the main action. The second sentence is slightly verbose but still concise overall.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given no siblings or output schema, the description covers the core functionality and parameter usage adequately. It lacks mention of error scenarios but is sufficient for a fetch tool with well-defined schema.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the description adds minimal value beyond parameter descriptions. It provides context by linking 'optionally extracts markdown' to the 'raw' parameter, but not enough to raise the score above baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool fetches a URL from the internet and optionally extracts markdown. It distinguishes this from any other tool by emphasizing internet access, and there are no siblings to differentiate.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description tells the agent to use this tool for obtaining up-to-date internet information. Though lacking explicit when-not-to-use, the context of granting internet access implies its primary use case.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
TDQS
Only one tool exists, so there is no risk of ambiguity. Its purpose is clear and distinct.
With a single tool, naming consistency is not an issue. The tool name 'fetch' is clear and conventional.
One tool is minimal. While it covers the core action of fetching a URL, a proxy server typically involves additional operations like caching, authentication, or transformation, making this feel slightly under-scoped.
The server only provides a single fetch operation, lacking obvious features for a proxy such as request customization, error handling, or support for different protocols. This is a significant gap for the stated purpose.
Maintenance
Related MCP Connectors
Remote MCP server exposing SMI Aware tools, resources, and skills over Streamable HTTP.
Enable secure connectivity between Sentry issues and debugging data, and LLM clients, using a Model Context Protocol (MCP) server.
Remote MCP server for supportsheep: run AI interviews and manage support content for your blog.
Remote MCP server for RunComfy Serverless API (ComfyUI): deployments and async inference.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA remote MCP server implementation for Cloudflare that uses server-sent events (SSE) to enable Model Control Protocol communication.1
- FlicenseNot gradedqualityNot gradedmaintenanceBridges STDIO-based MCP clients with SSE-based MCP servers, allowing applications like Claude Desktop to connect to remote MCP servers that use SSE transport.9
- AlicenseNot gradedqualityDmaintenanceActs as a proxy between a local Stdio connection and a remote Model Context Protocol server running over Server-Sent Events. It specifically enables Stdio-based MCP clients to connect to the SwiftZilla remote SSE endpoint.15ISC
- AlicenseNot gradedqualityDmaintenanceExposes any stdio-based MCP server to the internet via HTTP/SSE transport, enabling remote agents to access MCP tools over a network.21MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/sparfenyuk/mcp-proxy'
If you have feedback or need assistance with the MCP directory API, please join our Discord server