|
1 | 1 | # Open MCP Proxy
|
2 | 2 |
|
3 |
| -An open source proxy for MCP servers. |
| 3 | +A simple and lightweight open-source bidirectional proxy for MCP servers. |
4 | 4 |
|
5 |
| -## Usage |
| 5 | +It exposes several callbacks that you can use to implement your own logic and do your own actions during the MCP protocol lifecycle. |
| 6 | + |
| 7 | +It supports both SSE and STDIO protocols so it can be used to enable MCP Client supporting only stdio (like the Claude Desktop App) to also support SSE. |
6 | 8 |
|
7 |
| -Replace the mcp server command with `uvx omproxy@latest` followed by the command. |
| 9 | +It leverages as much as possible the official mcp-python-sdk to remains simple, lightweight and future-proof. |
8 | 10 |
|
9 |
| -For example: |
| 11 | +it declines in 2 versions to support both SSE and STDIO protocols: |
10 | 12 |
|
11 |
| -replace: |
| 13 | +**SSE Proxy** |
12 | 14 |
|
13 |
| -```json |
14 |
| -{ |
15 |
| - "mcpServers":{ |
16 |
| - "server1":{ |
17 |
| - "command":"uv" |
18 |
| - "args": ["run", "src/example_server.py"] |
19 |
| - } |
20 |
| - } |
21 |
| -} |
| 15 | +```mermaid |
| 16 | +graph LR |
| 17 | + STDIN -->|stdio| Proxy[Open MCP Proxy] |
| 18 | + Proxy -->|SSE| Server[Remote MCP Server] |
22 | 19 | ```
|
23 | 20 |
|
24 |
| -with: |
25 |
| - |
26 |
| -```json |
27 |
| -{ |
28 |
| - "mcpServers":{ |
29 |
| - "server1":{ |
30 |
| - "command": "uvx", |
31 |
| - "args": [ |
32 |
| - "--python", |
33 |
| - "3.12", |
34 |
| - "omproxy@latest", |
35 |
| - "--name", |
36 |
| - "example_server", |
37 |
| - "uv", |
38 |
| - "run", |
39 |
| - "src/example_server.py" |
40 |
| - ] |
41 |
| - } |
42 |
| - } |
43 |
| -} |
| 21 | +```mermaid |
| 22 | +graph RL |
| 23 | + Server[Remote MCP Server] -->|SSE| Proxy[Open MCP Proxy] |
| 24 | + Proxy -->|stdio| STDOUT |
| 25 | +``` |
| 26 | + |
| 27 | +**STDIO Proxy** |
| 28 | + |
| 29 | +```mermaid |
| 30 | +graph LR |
| 31 | + STDIN -->|stdio| Proxy[Open MCP Proxy] |
| 32 | + Proxy -->|stdio| Server[Local MCP Server] |
44 | 33 | ```
|
45 | 34 |
|
46 |
| -## Telemetry Data Collection and Handling |
| 35 | +```mermaid |
| 36 | +graph RL |
| 37 | + Server[Local MCP Server] -->|stdio| Proxy[Open MCP Proxy] |
| 38 | + Proxy -->|stdio| STDOUT |
| 39 | +``` |
| 40 | + |
| 41 | +Note that in both cases the proxy listen to STDIN and write to STDOUT to work seemlessly with stdio MCP Clients. |
| 42 | + |
| 43 | +## Usage |
47 | 44 |
|
48 |
| -We collect anonymous telemetry data of MCP server running through the proxy. |
| 45 | +### Hook into the MCP protocol lifecycle |
49 | 46 |
|
50 |
| -The information collected help us: |
| 47 | +The recommended approach to hook into the MCP protocol lifecycle is to subclass one of the Proxy class that we expose and override the callback methods you need. |
51 | 48 |
|
52 |
| -* display lively health status of MCP servers on our website: https://iod.ai |
53 |
| -* troubleshoot MCP servers, take them out and report issues to corresponding MCP server owner repository. |
54 |
| -* aggregate usage metric to display information such as the most used MCP servers, or the most used tool for a given MCP server. |
| 49 | +At the moment, we expose 4 callback methods: |
55 | 50 |
|
56 |
| -We collect the minimal amount of data to support the use cases above. In practice it means that we collect: |
57 |
| -* 1 anonymous event everytime the proxy is started |
58 |
| -* 1 anonymous event everytime a 'call_tool' is made containing the name of the tool and the arguments passed to the tool. |
59 |
| -* 1 anonymous event everytime a 'resource' is accessed containing the uri accessed but not the content of the resource. |
| 51 | +| Method | Description | Parameters | |
| 52 | +|--------|-------------|------------| |
| 53 | +| `_on_mcp_client_message` | Can be used to handle messages from the MCP client | `message: JSONRPCMessage` | |
| 54 | +| `_on_mcp_server_message` | Can be used to handle messages from the MCP server | `message: JSONRPCMessage \| Exception` | |
| 55 | +| `_on_start` | Can be used to handle the start of the proxy | None | |
| 56 | +| `_on_close` | Can be used to handle the close of the proxy | None | |
60 | 57 |
|
61 |
| -Note: for tool use and resource we do store access or log the response in any way. |
| 58 | +For example if you need a proxy over the stdio protocol: |
62 | 59 |
|
63 |
| -All the data collected is anonymous we use OpenTelemetry the open source standard for collecting telemetry data through logfire (the observability framework by the pydantic team). |
| 60 | +```python |
| 61 | +from omproxy.proxy import StdioProxy |
64 | 62 |
|
65 |
| -Your anonymous data is stored by logfire for a period of 30 days as per logfire retention policy. |
| 63 | +class MyStdioProxy(StdioProxy): |
| 64 | + def _on_start(self): |
| 65 | + print("Starting proxy", file=sys.stderr) |
66 | 66 |
|
| 67 | + def _on_mcp_client_message(self, message: JSONRPCMessage): |
| 68 | + print(message, file=sys.stderr) |
67 | 69 |
|
| 70 | + def _on_mcp_server_message(self, message: JSONRPCMessage | Exception): |
| 71 | + print(message, file=sys.stderr) |
| 72 | + |
| 73 | + def _on_close(self): |
| 74 | + print("Closing proxy", file=sys.stderr) |
| 75 | + |
| 76 | +if __name__ == "__main__": |
| 77 | + proxy = MyStdioProxy() |
| 78 | + proxy.run(StdioServerParameters(command="uv", args=["run", "src/example_server.py"])) |
| 79 | +``` |
| 80 | + |
| 81 | +**tip**: dont write to stdout in your callbacks or anywhere really as it will mess with the stdio MCP communication. |
| 82 | + |
| 83 | +### MCP Client supporting only STDIO to your SSE MCP Server |
| 84 | + |
| 85 | +We provide a simple CLI to start the proxy if you have an SSE MCP server running and you want to make it available to an MCP Client supporting only stdio you can simply do: |
| 86 | + |
| 87 | +```bash |
| 88 | +uvx omproxy@latest sse --url https://yourssemcpserver.io |
| 89 | +``` |
68 | 90 |
|
| 91 | +see `uvx omproxy@latest sse --help` for more information including setting headers for authorization for example. |
0 commit comments