mcp-protocol-bridge
A utility designed to interface between conventional standard input/output (stdio) mechanisms and the Model Context Protocol (MCP) transport layers utilizing Server-Sent Events (SSE) or Streamable HTTP protocols, enabling bidirectional data flow and inter-process communication.
Author

sparfenyuk
Quick Info
Actions
Tags
mcp-protocol-bridge
- mcp-protocol-bridge
- Overview
- 1. Stdio to Remote Endpoint Translation
- 2. Local Endpoint Exposure via SSE
- Named Service Definitions
- Acquisition Methods
- Container Image Customization
- Docker Compose Orchestration
- Command Line Interface Options
- Verification Procedures
Overview
The mcp-protocol-bridge utility serves as a versatile intermediary for adapting MCP communication transports. It supports two principal operational paradigms:
- Translating standard I/O streams to remote SSE/StreamableHTTP connections.
- Exposing a local stdio MCP server through an externally accessible SSE listener.
1. Stdio to Remote Endpoint Translation
Initiates a proxy process that relays data from the local standard input/output channel to a designated remote MCP Server endpoint configured for SSE or Streamable HTTP.
This capability is crucial for enabling clients, such as Claude Desktop, to interface with external servers using SSE when native support is absent.
graph LR
A["Client (e.g., Claude Desktop)"] <--> |stdio IPC| B["mcp-protocol-bridge"]
B <--> |SSE/StreamableHTTP| C["Remote MCP Backend"]
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
1.1 Configuration Parameters
This mode mandates specifying the target MCP Server's SSE endpoint URL as the primary positional argument. If the backend utilizes the Streamable HTTP protocol, this must be explicitly signaled via the --transport=streamablehttp flag.
Arguments
| Name | Mandatory | Description | Example |
|---|---|---|---|
target_endpoint |
Yes | The Uniform Resource Locator (URL) for the MCP server's SSE communication sink. | http://example.io/sse |
--headers |
No | Custom HTTP headers injected into the connection request destined for the MCP server. | Authorization 'Bearer my-secret-access-token' |
--transport |
No | Protocol selection for the outbound connection: 'sse' or 'streamablehttp'. Defaults to SSE. | streamablehttp |
Environment Variables
| Name | Mandatory | Description | Example |
|---|---|---|---|
API_ACCESS_TOKEN |
No | Alternative mechanism to supply the Authorization header: Authorization 'Bearer <API_ACCESS_TOKEN>' |
YOUR_TOKEN |
1.2 Usage Demonstration
Configuration must be set up within the MCP Client application to invoke mcp-protocol-bridge.
For instance, within Claude Desktop's configuration schema:
{
"mcpServers": {
"mcp-proxy": {
"command": "mcp-protocol-bridge",
"args": [
"http://example.io/sse"
],
"env": {
"API_ACCESS_TOKEN": "access-token"
}
}
}
}
2. Local Endpoint Exposure via SSE
Launches a proxy instance that advertises itself as an SSE server, funneling incoming requests to a locally executed stdio-based MCP server process.
This architecture permits external consumers to interact with a locally running service via HTTP/SSE.
graph LR
A["Remote LLM Client"] <-->|SSE Request| B["mcp-protocol-bridge"]
B <-->|stdio Stream| C["Local MCP Server Process"]
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.1 Configuration Parameters
Operation in this mode mandates the specification of the port the SSE listener binds to, using the --port argument (or the deprecated --sse-port). The binding interface can be controlled via --host (or --sse-host). Supplementary environment variables for the spawned stdio server are passed using repeated --env flags. Arguments intended for the underlying stdio server must follow the -- delimiter.
Arguments
| Name | Mandatory | Description | Example |
|---|---|---|---|
stdio_command |
Yes | The executable command to initiate the subservient MCP stdio service. | uvx mcp-server-fetch |
--port |
No, ephemeral port selected | The TCP port number for the external SSE listener. | 8080 |
--host |
No, bound to 127.0.0.1 |
The network interface address on which the SSE listener binds. | 0.0.0.0 |
--env |
No | Augments the environment variables available to the spawned child process. Repeatable. | FOO BAR |
--cwd |
No | Sets the operational directory context for the child process execution. | /tmp |
--pass-environment |
No | Propagates all host environment variables to the child process. Negated by --no-pass-environment. |
--no-pass-environment |
--allow-origin |
No | Defines CORS policies for incoming SSE connections. Repeatable. Default: no external access. | --allow-origin "*" |
--stateless |
No | Activates stateless processing for Streamable HTTP interactions. Defaults to False. | --no-stateless |
--named-server NAME COMMAND_STRING |
No | Registers an auxiliary stdio handler accessible at /servers/NAME/. |
--named-server fetch 'uvx mcp-server-fetch' |
--named-server-config FILE_PATH |
No | Path to a JSON manifest exclusively defining named stdio handlers. | --named-server-config /path/to/servers.json |
--sse-port (Obsolete) |
No, ephemeral port selected | Alias for --port. |
8080 |
--sse-host (Obsolete) |
No, bound to 127.0.0.1 |
Alias for --host. |
0.0.0.0 |
2.2 Usage Demonstration
Launching the bridge to serve a local mcp-server-fetch on TCP port 8080:
# Basic execution (uses default host 127.0.0.1)
mcp-protocol-bridge uvx mcp-server-fetch
# Specify host and port explicitly
mcp-protocol-bridge --host=0.0.0.0 --port=8080 uvx mcp-server-fetch
# Passing arguments to the backend server using the separator
mcp-protocol-bridge --port=8080 -- uvx mcp-server-fetch --client-id=BridgeClient
# Registering and running multiple dedicated backend services
mcp-protocol-bridge --port=8080 --named-server fetch 'uvx mcp-server-fetch' --named-server processor 'my-processor-tool'
# Utilizing a comprehensive JSON configuration file for backend definitions
mcp-protocol-bridge --port=8080 --named-server-config ./service_definitions.json
Named Service Definitions
NAME: The identifier used in the service path structure (e.g., accessing the service viahttp://host:port/servers/NAME/sse).COMMAND_STRING: The complete invocation string for the stdio handler (e.g., 'uvx mcp-server-fetch --option'). Multiple--named-serverarguments are processed sequentially. This mechanism is overridden entirely if--named-server-configis present.FILE_PATH: If provided, this JSON file dictates the sole definitions for named handlers; CLI arguments for named servers are ignored.
If a default handler is specified (via the positional argument stdio_command without any named server configuration), it is accessible at the root paths (e.g., http://127.0.0.1:8080/sse).
Named services are reached via the path prefix /servers/<server-name>/ (e.g., http://127.0.0.1:8080/servers/fetch/sse). A global /status endpoint reports on all operational handlers.
JSON Configuration File Schema for --named-server-config:
The file must conform to this structure:
{
"mcpServers": {
"fetch_service": {
"disabled": false,
"timeout": 60,
"command": "uvx",
"args": [
"mcp-server-fetch"
],
"transportType": "stdio"
},
"github_adapter": {
"timeout": 60,
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-github"
],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
},
"transportType": "stdio"
}
}
}
mcpServers: A map where keys are the server identifiers (used in URL paths) and values define service parameters.command: (Mandatory) The program executable path.args: (Optional) A list of arguments passed to the command. Defaults to an empty list.disabled: (Optional) Boolean; iffalse, the server definition is skipped. Defaults totrue(paradoxically, it defaults to disabled in the structure but enabled via CLI defaults, contextually assumetruemeans 'skip loading this definition').timeoutandtransportType: Included for structural fidelity with general MCP client configs but are ignored bymcp-protocol-bridgewhen loading named configurations; transport is always assumed to be 'stdio' linkage.
Acquisition Methods
Installation via PyPI Artifacts
The officially released, stable version resides on the Python Package Index (PyPI).
# Preferred installation method using 'uv'
uv tool install mcp-protocol-bridge
# Alternative installation using 'pipx'
pipx install mcp-protocol-bridge
After installation, invoke using the mcp-protocol-bridge executable name. Refer to the operational modes above for configuration.
Installation from Repository Head
The most recent development version can be sourced directly from the Git repository:
uv tool install git+https://github.com/sparfenyuk/mcp-protocol-bridge
[!NOTE] To refresh an existing installation, execute
uv tool upgrade --reinstall.[!NOTE] To completely remove the installed tool, use
uv tool uninstall mcp-protocol-bridge.
Containerized Deployment
Since version 0.3.2, a container image is published, enabling deployment via container runtimes:
docker run --rm -t ghcr.io/sparfenyuk/mcp-protocol-bridge:latest-alpine --help
Debugging Common Issues
- Symptom: Client (e.g., Claude Desktop) reports
ENOENTerror during server bootstrap.
Remedy: The system cannot locate the executable. Determine the absolute path using shell commands (where mcp-protocol-bridge on Unix-like systems or where.exe mcp-protocol-bridge on Windows). Then, configure the client to use this full path within its server definition:
json
"fetch_service": {
"command": "/absolute/path/to/bin/mcp-protocol-bridge",
"args": [
"http://localhost:8932/sse"
]
}
Container Image Customization
It is possible to derive a custom container image based on the official release to incorporate supplementary utilities. For instance, if the uv package manager is needed within the container context:
# File: mcp-bridge.Dockerfile
FROM ghcr.io/sparfenyuk/mcp-protocol-bridge:latest-alpine
# Install 'uv' toolset
RUN python3 -m ensurepip && pip install --no-cache-dir uv
ENV PATH="/usr/local/bin:$PATH" \
UV_PYTHON_PREFERENCE=only-system
ENTRYPOINT ["catatonit", "--", "mcp-protocol-bridge"]
Docker Compose Orchestration
This custom image can then be integrated into a Docker Compose definition:
services:
mcp-adapter-service:
build:
context: .
dockerfile: mcp-bridge.Dockerfile
network_mode: host
restart: unless-stopped
ports:
- 8096:8096
command: "--pass-environment --port=8096 --host 0.0.0.0 uvx mcp-server-fetch"
[!NOTE] Ensure
--pass-environmentis included if the underlying stdio server relies on host environment variables to locate its runtime dependencies, preventing errors like "No interpreter found in managed installations or search path".
Command Line Interface Options
usage: mcp-protocol-bridge [-h] [--version] [-H KEY VALUE] [--transport {sse,streamablehttp}]
[-e KEY VALUE] [--cwd CWD]
[--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 ...]]
[stdio_command] [args ...]
Orchestrates communication between stdio and remote/local MCP transport protocols.
positional arguments:
stdio_command The command to launch for the default stdio server if no named servers are active, or the target URL for remote connections. If a URL, runs client mode. Otherwise, this is the default server command.
options:
-h, --help Display this comprehensive help summary and terminate.
--version Output version information and exit.
Remote Client Configuration:
-H, --headers KEY VALUE
Custom HTTP request headers sent to the remote SSE sink. Repeatable.
--transport {sse,streamablehttp}
Selects the remote protocol type. Default is SSE.
Local Server (stdio) Process Control:
-e, --env KEY VALUE Environment variables injected into the spawned default stdio process. Repeatable.
--cwd CWD The starting directory context for the default server process.
--pass-environment, --no-pass-environment
Toggle propagation of host environment variables to spawned processes.
--log-level LEVEL Set verbosity: DEBUG, INFO (default), WARNING, ERROR.
--debug, --no-debug Enables verbose diagnostic logging (equivalent to --log-level DEBUG).
--named-server NAME COMMAND_STRING
Registers a specific stdio backend service accessible via /servers/NAME/.
--named-server-config FILE_PATH
Specifies an exclusive JSON file source for defining all named backend services.
Local SSE Listener Configuration:
--port PORT TCP port number for the external SSE listener. Default is dynamically assigned.
--host HOST Network interface address for binding the SSE listener. Default is 127.0.0.1.
--stateless, --no-stateless
Enables stateless operation for Streamable HTTP connections. Default False.
--sse-port SSE_PORT (Deprecated alias for --port)
--sse-host SSE_HOST (Deprecated alias for --host)
--allow-origin ALLOW_ORIGIN [ALLOW_ORIGIN ...]
Whitelist acceptable client origins for CORS. Default: Strict.
Example Invocations:
mcp-protocol-bridge http://remote.com/events
mcp-protocol-bridge --port 9000 --allow-origin='*' -- my-stdio-backend --config /etc/config.yaml
mcp-protocol-bridge --port 8080 --named-server-config ./services.json
Example Configuration File Structure
(This mirrors the JSON structure detailed earlier, confirming the configuration source format.)
Verification Procedures
Test the integrated functionality by routing a known good MCP command through the bridge. The mcp-server-fetch utility serves as an excellent benchmark target.
# 1. Activate the bridge to listen on 8080, spawning mcp-server-fetch locally
mcp-protocol-bridge --port=8080 uvx mcp-server-fetch & # Run in background
# 2. Use a second instance of the bridge in client mode to connect to the spawned SSE service
mcp-protocol-bridge http://127.0.0.1:8080/sse
# 3. Terminate the client instance (second server)
# (Send Ctrl+C)
# 4. Return the primary bridge instance to foreground
fg
# 5. Terminate the primary bridge instance
# (Send Ctrl+C)
WIKIPEDIA: The XMLHttpRequest (XHR) object is a fundamental Application Programming Interface within web browsers, facilitating asynchronous transmission of Hypertext Transfer Protocol (HTTP) requests to a server. Its introduction enabled web applications to update content dynamically without necessitating a full page reload, a core principle underlying Asynchronous JavaScript and XML (Ajax). Before XHR, server interaction relied primarily on traditional form submissions or hyperlink navigation, both resulting in page replacement.
== Chronology ==
The underlying concept for asynchronous request handling originated with Microsoft developers creating Outlook in 2000. This concept was first materialized in Internet Explorer version 5 (1999), although it employed proprietary COM object instantiation syntax, specifically ActiveXObject("Msxml2.XMLHTTP") and ActiveXObject("Microsoft.XMLHTTP"). By the release of Internet Explorer 7 (2006), the standardized XMLHttpRequest identifier achieved universal adoption across all major browser engines, including Mozilla's Gecko (2002), Apple's Safari 1.2 (2004), and Opera 8.0 (2005).
=== Standardization Efforts ===
The World Wide Web Consortium (W3C) published the initial Working Draft specification for the XMLHttpRequest object on April 5, 2006. This was succeeded by the Level 2 specification in February 2008, which introduced capabilities for progress monitoring, enabling cross-origin data exchange, and managing binary data streams. Development focus later shifted, and the Level 2 features were integrated back into the primary specification document by late 2011. Responsibility for maintaining the living document, leveraging Web IDL definitions, transitioned to the WHATWG consortium in late 2012.
== Implementation Procedure == Executing a request via XMLHttpRequest generally involves a sequential programming workflow:
- Instantiation: Create an instance of the XMLHttpRequest object using its constructor.
- Configuration: Invoke the
open()method to define the request method (GET, POST, etc.), specify the target Uniform Resource Identifier (URI), and choose between synchronous or asynchronous processing. - Asynchronous Listener: For asynchronous operations, register an event handler function that will be executed upon state transitions.
- Transmission: Initiate the actual data transfer by calling the
send()method, optionally passing payload data. - Response Handling: Monitor the object's
readyStateproperty within the listener. Upon reaching state 4 (DONE), the server response is typically available inresponseTextor equivalent properties.
Beyond these fundamental steps, XHR offers extensive controls: custom HTTP headers can be prepended; data uploads can occur within the send() payload; responses can be automatically parsed from JSON into usable JavaScript structures; and streaming data can be processed incrementally instead of waiting for completion. Furthermore, operations can be manually terminated or assigned strict timeouts.
== Cross-Domain Access Restrictions ==
