npm package: @michlyn/mcpgateway
Description: Enhanced version of supercorp-ai/supergateway, adding streamable http support and the ability to run MCP services based on both OpenAPI protocol interface documentation and higress MCP template files.
Latest version: 4.0.4

### Enhanced version of https://github.com/supercorp-ai/supergateway, adding streamablehttp support and the ability to run MCP services based on both OpenAPI protocol interface documentation and [higress MCP template files](https://github.com/higress-group/openapi-to-mcpserver).

# McpGateway

**McpGateway** is a versatile protocol conversion tool for Model Context Protocol (MCP) servers, enabling:

1. Running **MCP stdio-based servers** over **SSE (Server-Sent Events)**, **WebSockets (WS)**, or **Streamable HTTP**
2. Converting **OpenAPI 3.0.1** interface definitions to **MCP tools**
3. Providing seamless interoperability between different MCP transport protocols

## Key Features

### Protocol Conversion

- Convert between stdio, SSE, WS, and Streamable HTTP (bidirectionally)
- Support multiple concurrent sessions with proper session management
- Provide comprehensive MCP protocol compatibility

### API Integration

- Convert OpenAPI 3 specifications to MCP tools automatically
- Generate tool names, descriptions, and parameter definitions from API specs
- Support complex parameter types with validation rules
- Automatically detect OpenAPI specs or MCP templates

### Session Management

- Robust session tracking with unique session IDs
- Automatic session timeout cleanup
- Detailed session status logging
- Fallback mechanisms for session ID mismatches

## Installation & Usage

Run McpGateway via the unified `npx` command. The system automatically detects whether to run in single-server or multi-server mode based on your parameters:

```bash
# Single server mode (auto-detected from parameters)
npx -y @michlyn/mcpgateway --stdio "uvx mcp-server-git"
npx -y @michlyn/mcpgateway --stdio "uvx mcp-server-git" --outputTransport streamable-http

# Multi-server mode (auto-detected from parameters)
npx -y @michlyn/mcpgateway --config mcp-servers.json
npx -y @michlyn/mcpgateway mcp-servers.json
```

### Automatic Mode Detection

The unified `mcpgateway` command intelligently determines the appropriate mode:

**Single Server Mode** - Detected when using:

- `--stdio "command"` - Run MCP stdio server
- `--sse "url"` - Connect to SSE server
- `--api "spec.json" --apiHost "url"` - Convert OpenAPI to MCP
- Other single-server specific parameters

**Multi Server Mode** - Detected when using:

- `--config config.json` - Multi-server configuration
- `config.json` - Direct config file path
- `--routerPort` - Router port specification

### Multi-Server Mode

Support running multiple MCP servers with **dynamic routing** through a single unified port. Features hot configuration reload and automatic server discovery.

#### Dynamic Routing Features

- ✅ **Single External Port**: Docker exposes only port 80
- ✅ **Hot Configuration Reload**: Modify `mcp-servers.json` without restart
- ✅ **Automatic Server Discovery**: Routes based on server names
- ✅ **Health Monitoring**: Built-in health checks for all servers
- ✅ **Simplified Architecture**: Direct routing without proxy layer

#### Configuration File Format

Create a `mcp-servers.json` configuration file:

```json
{
  "mcpServers": {
    "mcp-server-feedback": {
      "api": "https://example.com/api/feedback.json",
      "apiHost": "https://example.com/api",
      "outputTransport": "streamable-http",
      "port": 8000,
      "httpPath": "/mcp",
      "ignoreHeader": true
    },
    "server-filesystem": {
      "stdio": "npx -y @modelcontextprotocol/server-filesystem /data",
      "outputTransport": "sse",
      "port": 8001,
      "ssePath": "/sse",
      "messagePath": "/message"
    },
    "comp-info-server": {
      "api": "/data/openapi.json",
      "apiHost": "https://example.com/api",
      "outputTransport": "sse",
      "port": 8002,
      "ssePath": "/sse",
      "messagePath": "/message"
    }
  }
}
```

#### Start Multi-Server

```bash
# Dynamic multi-server with unified routing (Recommended)
npx -y @michlyn/mcpgateway --config mcp-servers.json

# 🆕 Remote configuration support
npx -y @michlyn/mcpgateway --config https://api.example.com/mcp-servers.json
```

#### 🆕 Remote Configuration Support

The configuration file now supports **remote URLs** with automatic monitoring for changes:

**Features:**

- 🌐 **HTTP/HTTPS URLs**: Load configuration from remote servers
- 🔄 **Auto-monitoring**: Check for updates every 30 seconds
- ⚡ **Cache Validation**: Support Last-Modified and ETag headers
- 🚀 **Hot Reload**: Automatically reload routes when config changes
- ⏱️ **Fast Response**: 1-second response time for configuration updates

**Examples:**

```bash
# Use remote configuration
npx -y @michlyn/mcpgateway --config https://api.example.com/mcp-servers.json --routerPort 80

# Use local configuration
npx -y @michlyn/mcpgateway --config ./mcp-servers.json --routerPort 80
```

#### Access Patterns

**Dynamic Routing (Recommended):**

- **Unified Entry**: `http://localhost:80/{server-name}/{path}`
- **Server Status**: `http://localhost:80/servers`
- **Health Check**: `http://localhost:80/health`

**Examples:**

- Feedback Server: `http://localhost:80/mcp-server-feedback/mcp`
- Filesystem Server: `http://localhost:80/server-filesystem/sse`
- Info Server: `http://localhost:80/comp-info-server/sse`

#### Docker Deployment

Deploy using the unified Docker configuration that supports both single and multi-server modes:

```bash
# Multi-server mode (auto-detected)
docker run -it --rm -p 80:80 -v $(pwd)/mcp-servers.json:/app/mcp-servers.json \
    michlyn/mcpgateway --config mcp-servers.json

# Single server mode (auto-detected)
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /" --port 8000
```

**Unified Docker Features:**

- **Intelligent Startup**: Automatically detects single vs multi-server mode
- **Single Port**: External port 80 with internal dynamic routing
- **Smart Health Checks**: Multi-port health monitoring
- **Seamless Operation**: No mode keywords needed, just provide your parameters

For detailed Docker usage instructions, see: [Docker Usage Guide](docs/DOCKER_USAGE.md)

### Common Options

- **`--stdio "command"`**: Command that runs an MCP server over stdio
- **`--sse "https://mcp-server-url.example.com"`**: SSE URL to connect to (SSE→stdio mode)
- **`--outputTransport stdio | sse | ws | streamable-http`**: Output MCP transport (default: `sse` with `--stdio`, `stdio` with `--sse`)
- **`--port 8000`**: Port to listen on (default: `8000`)
- **`--baseUrl "http://localhost:8000"`**: Base URL for SSE, WS, or Streamable HTTP clients (optional)
- **`--header "x-user-id: 123"`**: Add custom headers (can be used multiple times)
- **`--oauth2Bearer "some-access-token"`**: Add an `Authorization` header with the provided Bearer token
- **`--logLevel info | none`**: Control logging level (default: `info`)
- **`--cors`**: Enable CORS (use with no values to allow all origins, or specify allowed origins)
- **`--healthEndpoint /healthz`**: Register endpoints that respond with `"ok"`

### Path Options

- **`--ssePath "/sse"`**: Path for SSE subscriptions (default: `/sse`)
- **`--messagePath "/message"`**: Path for messages (default: `/message`)
- **`--httpPath "/mcp"`**: Path for Streamable HTTP (default: `/mcp`)

### API Integration Options

- **`--api "./openapi.json"`**: OpenAPI document or MCP template file (JSON or YAML), supports both local file paths and remote URLs (http:// or https://)
- **`--apiHost "https://api.example.com"`**: Base URL for the API server
- **`--ignoreHeader`**: Ignore header parameters defined in OpenAPI specification during conversion (default: false)

#### Remote URL Support

The `--api` parameter now supports downloading files from remote URLs. This is useful for:

- Loading OpenAPI specifications from API documentation servers
- Using centralized configuration files stored on web servers
- Fetching MCP templates from content delivery networks

**Examples:**

```bash
# Using a remote OpenAPI specification
npx -y @michlyn/mcpgateway \
    --api https://api.example.com/openapi.json \
    --apiHost https://api.example.com \
    --outputTransport streamable-http

# Using a remote MCP template file
npx -y @michlyn/mcpgateway \
    --api https://cdn.example.com/mcp-templates/my-service.yaml \
    --apiHost https://api.example.com \
    --outputTransport sse

# With URL encoding (Chinese characters in path)
npx -y @michlyn/mcpgateway \
    --api "http://localhost:8081/bsp-admin/files/mcp/%E6%84%8F%E8%A7%81%E5%8F%8D%E9%A6%88.json" \
    --apiHost https://api.example.com \
    --outputTransport streamable-http
```

**Features:**

- Automatic file type detection from URL extension (.json, .yaml, .yml)
- Supports standard HTTP/HTTPS protocols
- Automatic cleanup of temporary files used during conversion
- Detailed logging of download process
- Error handling for network failures and invalid URLs

## Usage Scenarios

### stdio → SSE

Expose an MCP stdio server as an SSE server:

```bash
npx -y @michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem ./my-folder" \
    --port 8000 --baseUrl http://localhost:8000 \
    --ssePath /sse --messagePath /message
```

- **Subscribe to events**: `GET http://localhost:8000/sse`
- **Send messages**: `POST http://localhost:8000/message`

### stdio → Streamable HTTP

Expose an MCP stdio server as a Streamable HTTP server:

```bash
npx -y @michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem ./my-folder" \
    --port 8000 --baseUrl http://localhost:8000 \
    --outputTransport streamable-http --httpPath /mcp
```

- **Streamable HTTP endpoint**: `http://localhost:8000/mcp`

### SSE → stdio

Connect to a remote SSE server and expose locally via stdio:

```bash
npx -y @michlyn/mcpgateway --sse "https://mcp-server-ab71a6b2-cd55-49d0-adba-562bc85956e3.supermachine.app"
```

You can add authentication headers:

```bash
npx -y @michlyn/mcpgateway \
    --sse "https://mcp-server-ab71a6b2-cd55-49d0-adba-562bc85956e3.supermachine.app" \
    --oauth2Bearer "some-access-token" \
    --header "X-My-Header: another-header-value"
```

### SSE → Streamable HTTP

Convert a remote SSE MCP server to Streamable HTTP:

```bash
npx -y @michlyn/mcpgateway \
    --sse "https://mcp-server-ab71a6b2-cd55-49d0-adba-562bc85956e3.supermachine.app" \
    --outputTransport streamable-http --port 8000 --httpPath /mcp
```

- **Streamable HTTP endpoint**: `http://localhost:8000/mcp`

### stdio → WS

Expose an MCP stdio server as a WebSocket server:

```bash
npx -y @michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem ./my-folder" \
    --port 8000 --outputTransport ws --messagePath /message
```

- **WebSocket endpoint**: `ws://localhost:8000/message`

### API → SSE or Streamable HTTP

Convert an OpenAPI specification to an MCP server:

```bash
# Using Streamable HTTP
npx -y @michlyn/mcpgateway \
    --api ./openapi.json --apiHost https://api.example.com \
    --outputTransport streamable-http --port 8000 --httpPath /mcp

# Using SSE
npx -y @michlyn/mcpgateway \
    --api ./openapi.json --apiHost https://api.example.com \
    --outputTransport sse --port 8000 --ssePath /sse --messagePath /message

# Ignore header parameters in OpenAPI spec (useful when headers are handled elsewhere)
npx -y @michlyn/mcpgateway \
    --api ./openapi.json --apiHost https://api.example.com \
    --outputTransport streamable-http --port 8000 --httpPath /mcp \
    --ignoreHeader
```

McpGateway automatically detects whether the input file is an OpenAPI specification or an MCP template:

- If it's an OpenAPI spec, it converts it to an MCP template and provides the service
- If it's already an MCP template, it uses it directly

## OpenAPI to MCP Conversion Tool

McpGateway includes a standalone tool to convert OpenAPI documents to MCP templates:

```bash
# Using npx
npx -y @michlyn/mcpgateway openapi-to-mcp --input openapi.json --output mcp-template.json

# Or use the direct command
openapi-to-mcp --input openapi.json --output mcp-template.json

# Ignore header parameters during conversion
openapi-to-mcp --input openapi.json --output mcp-template.json --ignore-header
```

### Parameters

- `--input, -i`: Path to OpenAPI spec file (JSON or YAML)
- `--output, -o`: Path for output MCP config file
- `--server-name, -n`: MCP server name (default: "openapi-server")
- `--tool-prefix, -p`: Tool name prefix (default: "")
- `--format, -f`: Output format (yaml or json) (default: "yaml")
- `--validate, -v`: Validate OpenAPI spec (default: false)
- `--template, -t`: Template file path for patching output (default: "")
- `--ignore-header`: Ignore header parameters in OpenAPI specification (default: false)

## Client Integrations

### Example with MCP Inspector (stdio → SSE mode)

1. Run McpGateway:

```bash
npx -y @michlyn/mcpgateway --port 8000 \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /Users/MyName/Desktop"
```

2. Use MCP Inspector:

```bash
npx @modelcontextprotocol/inspector
```

### Using with Cursor (SSE → stdio mode)

Cursor can integrate with McpGateway in SSE→stdio mode:

```json
{
  "mcpServers": {
    "cursorExampleNpx": {
      "command": "npx",
      "args": [
        "-y",
        "@michlyn/mcpgateway",
        "--sse",
        "https://mcp-server-ab71a6b2-cd55-49d0-adba-562bc85956e3.supermachine.app"
      ]
    }
  }
}
```

### Using with Modern Cursor (Streamable HTTP mode)

Cursor can use McpGateway's stdio→Streamable HTTP mode:

```json
{
  "mcpServers": {
    "modernCursorExample": {
      "type": "streamableHttp",
      "url": "http://localhost:8000/mcp"
    }
  }
}
```

Run McpGateway on your local machine:

```bash
npx -y @michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem ./my-folder" \
    --outputTransport streamable-http --port 8000 --httpPath /mcp
```

## Docker Support

McpGateway is available as a Docker image, making it easy to run without installing Node.js locally.

### Docker Image

Available on Docker Hub: [michlyn/mcpgateway](https://hub.docker.com/r/michlyn/mcpgateway)

### Docker Examples for All Gateway Types

#### stdio → SSE

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /" \
    --port 8000 --ssePath /sse --messagePath /message
```

#### stdio → Streamable HTTP

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /" \
    --outputTransport streamable-http --port 8000 --httpPath /mcp
```

#### stdio → WS

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /" \
    --outputTransport ws --port 8000 --messagePath /message
```

#### SSE → stdio

```bash
docker run -it --rm michlyn/mcpgateway \
    --sse "https://mcp-server-example.supermachine.app" \
    --outputTransport stdio
```

#### SSE → Streamable HTTP

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --sse "https://mcp-server-example.supermachine.app" \
    --outputTransport streamable-http --port 8000 --httpPath /mcp
```

#### API → SSE

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --api /path/to/openapi.json --apiHost https://api.example.com \
    --outputTransport sse --port 8000 --ssePath /sse --messagePath /message
```

#### API → Streamable HTTP

```bash
docker run -it --rm -p 8000:8000 michlyn/mcpgateway \
    --api /path/to/openapi.json --apiHost https://api.example.com \
    --outputTransport streamable-http --port 8000 --httpPath /mcp
```

#### Multi-Server Mode

```bash
# Multi-server with config file
docker run -it --rm -p 80:80 -v $(pwd)/mcp-servers.json:/app/mcp-servers.json \
    michlyn/mcpgateway --config mcp-servers.json

# Multi-server with remote config
docker run -it --rm -p 80:80 michlyn/mcpgateway \
    --config https://api.example.com/mcp-servers.json
```

### Volume Mounting

To provide files from your host system:

```bash
docker run -it --rm -p 8000:8000 -v $(pwd):/workspace michlyn/mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /workspace" \
    --port 8000
```

### Building the Image Yourself

```bash
# 1. Compile TypeScript
npm run build

# 2. Build Docker image
docker build -t mcpgateway .

# 3. Run the container (single server)
docker run -it --rm -p 8000:8000 mcpgateway \
    --stdio "npx -y @modelcontextprotocol/server-filesystem /" \
    --port 8000

# 4. Run the container (multi-server)
docker run -it --rm -p 80:80 -v $(pwd)/mcp-servers.json:/app/mcp-servers.json \
    mcpgateway --config mcp-servers.json
```

## Public Access with ngrok

Share your local MCP server publicly:

```bash
# Single server mode
npx -y @michlyn/mcpgateway --port 8000 --stdio "npx -y @modelcontextprotocol/server-filesystem ."

# In another terminal:
ngrok http 8000
```

The MCP server will be available at a URL similar to: https://1234-567-890-12-456.ngrok-free.app/sse

## Troubleshooting SSE Connections

If you encounter issues with SSE connections or tool calls not being processed:

1. **Check Session IDs**: Ensure the client is using the session ID returned by the server in the SSE response headers:

   ```javascript
   // Example JavaScript client code
   const sseConnection = new EventSource('/sse')
   let sessionId

   sseConnection.onopen = (event) => {
     // Get session ID from response headers
     sessionId = event.target.getResponseHeader('mcp-session-id')
     console.log('Connected with session ID:', sessionId)
   }

   // Use that session ID for message requests
   async function callTool(toolName, parameters) {
     const response = await fetch('/message', {
       method: 'POST',
       headers: {
         'Content-Type': 'application/json',
         'mcp-session-id': sessionId,
       },
       body: JSON.stringify({
         jsonrpc: '2.0',
         method: 'tools/call',
         params: { name: toolName, arguments: parameters },
         id: Date.now(),
       }),
     })
     return await response.json()
   }
   ```

````

2. **Standard MCP tools/call Format**: Use the standard MCP tools/call message format:

   ```json
   {
     "jsonrpc": "2.0",
     "method": "tools/call",
     "params": {
       "name": "toolName",
       "arguments": {
         "param1": "value1",
         "param2": "value2"
       }
     },
     "id": 1
   }
````

Note: The `arguments` field is used instead of `parameters`. This is required for compatibility with the standard MCP tools/call format and direct-intercept mode.

3. **Use the Debug Tool**: The server includes a built-in debug tool to test tool invocation:

   ```bash
   curl -X POST \
     -H "Content-Type: application/json" \
     -H "mcp-session-id: YOUR_SESSION_ID" \
     http://localhost:8080/message \
     -d '{
       "jsonrpc": "2.0",
       "method": "tools/call",
       "params": {
         "name": "debug",
         "arguments": {
           "message": "Testing connection",
           "testMode": true
         }
       },
       "id": 1
     }'
   ```

4. **Check Server Logs**: Look for detailed logs showing:

   - SSE connection establishment
   - Session ID creation and tracking
   - JSON parsing of message bodies
   - Tool call processing
   - Direct interception of tools/call requests

5. **Common Issues**:

   - "Headers already sent" errors can occur if trying to modify response headers after sending data
   - Missing session ID in message requests
   - Incorrect JSON formatting in tool call requests
   - CORS issues when connecting from a different origin
   - "stream is not readable" errors when the request body is consumed before the SSE transport can process it
   - Tool calls not being executed (looking for "EXECUTING TOOL" in logs)

6. **Authentication Headers Handling**:

   - The gateway seamlessly passes authentication headers (Authorization, tokens, etc.) through the entire request chain
   - Authentication headers are automatically detected and preserved across all transport layers
   - Handles various authentication header formats: Authorization, bspa_access_token, api-key, etc.
   - When experiencing "登录信息超时" (login timeout) errors, check that:
     - Your client is sending proper authentication headers
     - The headers are being correctly passed through (see server logs)
     - The format of authentication headers matches what the API expects
   - You can test authentication header passing with a simple curl command:
     ```bash
     curl -X POST \
       -H "Content-Type: application/json" \
       -H "Authorization: Bearer YOUR_TOKEN" \
       -H "mcp-session-id: YOUR_SESSION_ID" \
       http://localhost:8000/message \
       -d '{
         "jsonrpc": "2.0",
         "method": "tools/call",
         "params": {
           "name": "debug",
           "arguments": {
             "message": "Testing auth headers",
             "testMode": true
           }
         },
         "id": 1
       }'
     ```
   - The authentication header will be passed to the SSE server and then to the API call

7. **tools/call Direct Interception**:

   - The apiToSse module uses direct interception for tools/call requests
   - These requests are intercepted before passing to the SSE transport
   - Direct interception logs will show: "===== 直接拦截并处理tools/call请求 ====="
   - If you don't see this log, check that your request format follows the standard MCP tools/call format
   - This approach bypasses any potential issues with the SSE transport's handling of tools/call requests

8. **Request Body Handling**:

   - The apiToSse module includes special handling for message path request bodies
   - For message endpoint requests, the raw request body is preserved for processing
   - Ensure that Content-Type header is set to "application/json" for message requests
   - When testing with curl, verify the full request body syntax matches JSON-RPC format
   - Use --logLevel debug flag when starting the server to see detailed request processing logs

9. **Request Headers Pass-through**:
   - Authentication headers (Authorization, bspa_access_token) from SSE connection are passed to API calls
   - Session headers are preserved and tracked throughout the connection lifecycle
   - To verify headers are passed correctly, check the RequestHeaders log entries

## Why MCP?

[Model Context Protocol](https://spec.modelcontextprotocol.io/) standardizes AI tool interactions. McpGateway converts between different MCP transport types (stdio, SSE, WS, and Streamable HTTP), simplifying integration and debugging with various clients.

The Streamable HTTP transport is the latest MCP standard, offering improved performance and better compatibility with modern web infrastructure. McpGateway makes it easy to use this transport with any MCP server, regardless of the transport it natively supports.

## Advanced Features

- **Automatic File Type Detection**: McpGateway intelligently detects whether input files are OpenAPI specs or MCP templates
- **Parameter Type Validation**: Robust validation and conversion for different parameter types
- **Comprehensive CORS Support**: Configurable cross-origin resource sharing
- **Enhanced Session Management**: Robust handling of session IDs with fallback mechanisms
- **Detailed Logging**: Comprehensive logging for debugging and monitoring
- **Robust Error Handling**: Prevents common issues like "Headers already sent" errors in SSE connections
- **Tool Call Debugging**: Built-in debug tools to test and validate tool invocation chains
- **Auto-Session Detection**: Automatically selects the correct session when only one is active

## Contributors

- [@StefanBurscher](https://github.com/StefanBurscher)
- [@tarasyarema](https://github.com/tarasyarema)
- [@pcnfernando](https://github.com/pcnfernando)
- [@Areo-Joe](https://github.com/Areo-Joe)
- [@Joffref](https://github.com/Joffref)
- [@michaeljguarino](https://github.com/michaeljguarino)
- [@michaelyn](https://github.com/wizizm)

## Contributing

Issues and PRs welcome. Please open one if you encounter problems or have feature suggestions.

## License

[MIT License](./LICENSE)

## Contact

欢迎有兴趣的伙伴+v入群技术沟通：

<img src="https://raw.githubusercontent.com/michlyn/mcpgateway/main/mywxqrcode.jpg" alt="微信二维码" width="200"/>

```

```