Skip to main content
Glama
README.md11.2 kB
# MCP Proxy A TypeScript streamable HTTP and SSE proxy for [MCP](https://modelcontextprotocol.io/) servers that use `stdio` transport. > [!NOTE] > CORS is enabled by default with configurable options. See [CORS Configuration](#cors-configuration) for details. > [!NOTE] > For a Python implementation, see [mcp-proxy](https://github.com/sparfenyuk/mcp-proxy). > [!NOTE] > MCP Proxy is what [FastMCP](https://github.com/punkpeye/fastmcp) uses to enable streamable HTTP and SSE. ## Installation ```bash npm install mcp-proxy ``` ## Quickstart ### Command-line ```bash npx mcp-proxy --port 8080 --shell tsx server.js ``` This starts a server and `stdio` server (`tsx server.js`). The server listens on port 8080 and `/mcp` (streamable HTTP) and `/sse` (SSE) endpoints, and forwards messages to the `stdio` server. options: - `--server`: Set to `sse` or `stream` to only enable the respective transport (default: both) - `--endpoint`: If `server` is set to `sse` or `stream`, this option sets the endpoint path (default: `/sse` or `/mcp`) - `--sseEndpoint`: Set the SSE endpoint path (default: `/sse`). Overrides `--endpoint` if `server` is set to `sse`. - `--streamEndpoint`: Set the streamable HTTP endpoint path (default: `/mcp`). Overrides `--endpoint` if `server` is set to `stream`. - `--stateless`: Enable stateless mode for HTTP streamable transport (no session management). In this mode, each request creates a new server instance instead of maintaining persistent sessions. - `--port`: Specify the port to listen on (default: 8080) - `--requestTimeout`: Timeout in milliseconds for requests to the MCP server (default: 300000, which is 5 minutes) - `--debug`: Enable debug logging - `--shell`: Spawn the server via the user's shell - `--apiKey`: API key for authenticating requests (uses X-API-Key header) ### Passing arguments to the wrapped command When wrapping a command that takes arguments starting with `-`, you must use `--` to prevent `mcp-proxy` from interpreting them as its own options. Everything after `--` is passed directly to the wrapped command. For example, to wrap a command that uses the `-v` flag: ```bash # Wrong: mcp-proxy will try to parse -v as its own option npx mcp-proxy --port 8080 my-command -v # Correct: use -- to pass -v to my-command npx mcp-proxy --port 8080 -- my-command -v ``` ### Stateless Mode By default, MCP Proxy maintains persistent sessions for HTTP streamable transport, where each client connection is associated with a server instance that stays alive for the duration of the session. Stateless mode (`--stateless`) changes this behavior: - **No session management**: Each request creates a new server instance instead of maintaining persistent sessions - **Simplified deployment**: Useful for serverless environments or when you want to minimize memory usage - **Request isolation**: Each request is completely independent, which can be beneficial for certain use cases Example usage: ```bash # Enable stateless mode npx mcp-proxy --port 8080 --stateless tsx server.js # Stateless mode with stream-only transport npx mcp-proxy --port 8080 --stateless --server stream tsx server.js ``` > [!NOTE] > Stateless mode only affects HTTP streamable transport (`/mcp` endpoint). SSE transport behavior remains unchanged. **When to use stateless mode:** - **Serverless environments**: When deploying to platforms like AWS Lambda, Vercel, or similar - **Load balancing**: When requests need to be distributed across multiple instances - **Memory optimization**: When you want to minimize server memory usage - **Request isolation**: When you need complete independence between requests - **Simple deployments**: When you don't need to maintain connection state ### API Key Authentication MCP Proxy supports optional API key authentication to secure your endpoints. When enabled, clients must provide a valid API key in the `X-API-Key` header to access the proxy. #### Enabling Authentication Authentication is disabled by default for backward compatibility. To enable it, provide an API key via: **Command-line:** ```bash npx mcp-proxy --port 8080 --apiKey "your-secret-key" tsx server.js ``` **Environment variable:** ```bash export MCP_PROXY_API_KEY="your-secret-key" npx mcp-proxy --port 8080 tsx server.js ``` #### Client Configuration Clients must include the API key in the `X-API-Key` header: ```typescript // For streamable HTTP transport const transport = new StreamableHTTPClientTransport( new URL("http://localhost:8080/mcp"), { headers: { "X-API-Key": "your-secret-key", }, }, ); // For SSE transport const transport = new SSEClientTransport(new URL("http://localhost:8080/sse"), { headers: { "X-API-Key": "your-secret-key", }, }); ``` #### Exempt Endpoints The following endpoints do not require authentication: - `/ping` - Health check endpoint - `OPTIONS` requests - CORS preflight requests #### Security Notes - **Use HTTPS in production**: API keys should only be transmitted over secure connections - **Keep keys secure**: Never commit API keys to version control - **Generate strong keys**: Use cryptographically secure random strings for API keys - **Rotate keys regularly**: Change API keys periodically for better security ### CORS Configuration MCP Proxy provides flexible CORS (Cross-Origin Resource Sharing) configuration to control how browsers can access your MCP server from different origins. #### Default Behavior By default, CORS is enabled with the following settings: - **Origin**: `*` (allow all origins) - **Methods**: `GET, POST, OPTIONS` - **Headers**: `Content-Type, Authorization, Accept, Mcp-Session-Id, Last-Event-Id` - **Credentials**: `true` - **Exposed Headers**: `Mcp-Session-Id` #### Basic Configuration ```typescript import { startHTTPServer } from "mcp-proxy"; // Use default CORS settings (backward compatible) await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, }); // Explicitly enable default CORS await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: true, }); // Disable CORS completely await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: false, }); ``` #### Advanced CORS Configuration For more control over CORS behavior, you can provide a detailed configuration: ```typescript import { startHTTPServer, CorsOptions } from "mcp-proxy"; const corsOptions: CorsOptions = { // Allow specific origins origin: ["https://app.example.com", "https://admin.example.com"], // Or use a function for dynamic origin validation origin: (origin: string) => origin.endsWith(".example.com"), // Specify allowed methods methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"], // Allow any headers (useful for browser clients with custom headers) allowedHeaders: "*", // Or specify exact headers allowedHeaders: [ "Content-Type", "Authorization", "Accept", "Mcp-Session-Id", "Last-Event-Id", "X-Custom-Header", "X-API-Key", ], // Headers to expose to the client exposedHeaders: ["Mcp-Session-Id", "X-Total-Count"], // Allow credentials credentials: true, // Cache preflight requests for 24 hours maxAge: 86400, }; await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: corsOptions, }); ``` #### Common Use Cases **Allow any custom headers (solves browser CORS issues):** ```typescript await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: { allowedHeaders: "*", // Allows X-Custom-Header, X-API-Key, etc. }, }); ``` **Restrict to specific domains:** ```typescript await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: { origin: ["https://myapp.com", "https://admin.myapp.com"], allowedHeaders: "*", }, }); ``` **Development-friendly settings:** ```typescript await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: { origin: ["http://localhost:3000", "http://localhost:5173"], // Common dev ports allowedHeaders: "*", credentials: true, }, }); ``` #### Migration from Older Versions If you were using mcp-proxy 5.5.6 and want the same permissive behavior in 5.9.0+: ```typescript // Old behavior (5.5.6) - automatic wildcard headers await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, }); // New equivalent (5.9.0+) - explicit wildcard headers await startHTTPServer({ createServer: async () => { /* ... */ }, port: 3000, cors: { allowedHeaders: "*", }, }); ``` ### Node.js SDK The Node.js SDK provides several utilities that are used to create a proxy. #### `proxyServer` Sets up a proxy between a server and a client. ```ts const transport = new StdioClientTransport(); const client = new Client(); const server = new Server(serverVersion, { capabilities: {}, }); proxyServer({ server, client, capabilities: {}, }); ``` In this example, the server will proxy all requests to the client and vice versa. #### `startHTTPServer` Starts a proxy that listens on a `port`, and sends messages to the attached server via `StreamableHTTPServerTransport` and `SSEServerTransport`. ```ts import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { startHTTPServer } from "mcp-proxy"; const { close } = await startHTTPServer({ createServer: async () => { return new Server(); }, eventStore: new InMemoryEventStore(), port: 8080, stateless: false, // Optional: enable stateless mode for streamable HTTP transport }); close(); ``` Options: - `createServer`: Function that creates a new server instance for each connection - `eventStore`: Event store for streamable HTTP transport (optional) - `port`: Port number to listen on - `host`: Host to bind to (default: "::") - `sseEndpoint`: SSE endpoint path (default: "/sse", set to null to disable) - `streamEndpoint`: Streamable HTTP endpoint path (default: "/mcp", set to null to disable) - `stateless`: Enable stateless mode for HTTP streamable transport (default: false) - `apiKey`: API key for authenticating requests (optional) - `cors`: CORS configuration (default: enabled with permissive settings, see CORS Configuration section) - `onConnect`: Callback when a server connects (optional) - `onClose`: Callback when a server disconnects (optional) - `onUnhandledRequest`: Callback for unhandled HTTP requests (optional) #### `startStdioServer` Starts a proxy that listens on a `stdio`, and sends messages to the attached `sse` or `streamable` server. ```ts import { ServerType, startStdioServer } from "./startStdioServer.js"; await startStdioServer({ serverType: ServerType.SSE, url: "http://127.0.0.1:8080/sse", }); ``` #### `tapTransport` Taps into a transport and logs events. ```ts import { tapTransport } from "mcp-proxy"; const transport = tapTransport(new StdioClientTransport(), (event) => { console.log(event); }); ``` ## Development ### Running MCP Proxy with a local server ```bash tsx src/bin/mcp-proxy.ts --debug tsx src/fixtures/simple-stdio-server.ts ```

Latest Blog Posts

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/Valerio357/bet-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server