@gongrzhe/mcp-proxy-server
v0.0.2
Published
MCP proxy server with multiple downstream server support and stateless architecture
Maintainers
Readme
MCP Proxy Server
A stateless HTTP proxy server for aggregating multiple Model Context Protocol (MCP) servers into a single endpoint. This allows AI clients to access tools and resources from multiple MCP servers through one unified interface.
Features
- Stateless Architecture: Each request is handled independently without session management
- Multiple MCP Server Support: Connect to and aggregate multiple downstream MCP servers
- Tool Aggregation: All tools, prompts, and resources from downstream servers are exposed with prefixed names
- Authorization Pass-through: Forwards Bearer tokens to downstream servers
- Advanced Configuration: JSON configuration files with template variables and environment substitution
- Tool Management: Enable/disable specific tools via configuration or runtime API
- Health Monitoring: Real-time server health tracking with 30-second intervals
- Auto-Reconnection: Automatic reconnection to failed servers every 60 seconds
- MongoDB Logging: Comprehensive logging of tool calls with HTTP metadata analytics
- Admin API: REST endpoints for runtime tool management and health monitoring
- Header Template System: Dynamic header processing with variable substitution
- Error Handling: Graceful error handling with detailed error responses
Quick Start
Installation
npm installBuild
npm run buildConfiguration
Simple Configuration (URLs only)
Set the DOWNSTREAM_MCP_SERVERS environment variable with a comma-separated list of MCP server URLs:
export DOWNSTREAM_MCP_SERVERS="https://mcp.context7.com/mcp,https://mcp.deepwiki.com/mcp"Advanced Configuration (JSON)
For advanced features like authentication, tool filtering, and header templates, use a JSON configuration file:
export DOWNSTREAM_MCP_SERVERS="./config/servers.json"Example configuration file:
{
"slack": {
"url": "http://localhost:30003/mcp",
"variables": {
"slack_token": "xoxp-your-token-here",
"workspace_id": "T1234567"
},
"headers": {
"Authorization": "Bearer {{slack_token}}",
"X-Workspace": "{{workspace_id}}",
"X-Custom-Header": "proxy-${USER}"
},
"tools": {
"enabled": ["channels_*", "users_list"],
"disabled": ["admin_*", "files_delete"],
"defaultEnabled": false
}
},
"context7": {
"url": "https://mcp.context7.com/mcp",
"tools": {
"disabled": ["dangerous_*"],
"defaultEnabled": true
}
}
}Template Variables
The proxy supports three types of variable substitution:
- Environment Variables:
${VAR_NAME}- Replaced withprocess.env.VAR_NAME - Custom Variables:
{{variable_name}}- Defined in thevariablessection - Direct Replacements: String replacements using the
replacementssection
Tool Filtering
Control which tools are available from each server:
enabled: Array of tool names or patterns (wildcards supported with*)disabled: Array of tool names or patterns to disabledefaultEnabled: Whether tools are enabled by default (default: true)
Filter Priority: disabled list > enabled list > defaultEnabled
Start Server
# Using compiled JavaScript (recommended)
npm run start:js
# Or using TypeScript directly
npm start
# With MongoDB logging
export MONGODB_URI="mongodb://localhost:27017/mcp_proxy"
npm run start:jsThe server will start on port 30000 by default, or use the PORT environment variable.
Usage
List Available Tools
curl -X POST http://localhost:30000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc": "2.0", "id": "1", "method": "tools/list", "params": {}}'Call a Tool
Tools are prefixed with their source server URL (with special characters replaced by underscores):
curl -X POST http://localhost:30000/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": "2",
"method": "tools/call",
"params": {
"name": "https___mcp_deepwiki_com_mcp_read_wiki_structure",
"arguments": {"repoName": "facebook/react"}
}
}'With Authorization
curl -X POST http://localhost:30000/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "Authorization: Bearer your-token-here" \
-d '{"jsonrpc": "2.0", "id": "3", "method": "tools/call", "params": {...}}'Tool Management
Runtime Tool Control
The proxy provides REST API endpoints for managing tool availability at runtime:
List All Tools and States
curl http://localhost:30000/admin/toolsResponse includes all available tools with their enabled/disabled status and whether they're controlled by configuration or runtime state.
Enable a Tool
curl -X POST http://localhost:30000/admin/tools/http%3A%2F%2Flocalhost%3A30003%2Fmcp/tool_name/enable \
-H "Content-Type: application/json" \
-d '{"updatedBy": "admin"}'Disable a Tool
curl -X POST http://localhost:30000/admin/tools/http%3A%2F%2Flocalhost%3A30003%2Fmcp/tool_name/disable \
-H "Content-Type: application/json" \
-d '{"updatedBy": "admin"}'Remove Runtime State
curl -X DELETE http://localhost:30000/admin/tools/http%3A%2F%2Flocalhost%3A30003%2Fmcp/tool_nameNote: Server URLs in API paths must be URL-encoded.
Priority System
Tool availability is determined by this priority order:
- Runtime State (MongoDB) - Highest priority
- Configuration filtering - Middle priority
- Default enabled - Lowest priority
MongoDB Logging & Analytics
Setup
Set the MONGODB_URI environment variable to enable comprehensive logging:
export MONGODB_URI="mongodb://localhost:27017/mcp_proxy"Features
- Tool Call Logging: Every tool call with timing, parameters, and results
- HTTP Metadata: Request/response headers, status codes, client IPs, User-Agent
- Accept Header Tracking: Content negotiation patterns
- Runtime Tool States: Persistent enable/disable states with audit trail
- Performance Analytics: Duration, error rates, usage patterns
Analytics Scripts
Analyze your MCP proxy usage:
# View comprehensive analytics
MONGODB_URI="mongodb://localhost:27017/mcp_proxy" node scripts/analyze-tool-calls.js
# View detailed sample record
MONGODB_URI="mongodb://localhost:27017/mcp_proxy" node scripts/view-sample-record.jsHealth Monitoring & Auto-Reconnection
Real-time Server Health Tracking
The proxy automatically monitors all downstream MCP servers with:
- 30-second health checks via
client.listTools() - Immediate disconnect detection (within 5 seconds)
- Automatic reconnection every 60 seconds for failed servers
- Persistent health history in MongoDB
- Real-time status tracking with detailed metrics
Health Status API
View Server Health
# Get health status for all servers
curl http://localhost:30000/admin/health
# Get health status for specific server
curl "http://localhost:30000/admin/health?serverUrl=http://localhost:30003/mcp"Response includes:
- Current status (
connected,disconnected,reconnecting,error) - Last connected/disconnected timestamps
- Health check history
- Reconnection attempt counts
- Error messages
Manual Health Operations
# Perform immediate health check
curl -X POST http://localhost:30000/admin/health/http%3A%2F%2Flocalhost%3A30003%2Fmcp/check
# Force reconnection attempt
curl -X POST http://localhost:30000/admin/health/http%3A%2F%2Flocalhost%3A30003%2Fmcp/reconnectHealth Monitoring Demo
Use the included demo script to monitor health status:
# Show current health status
node scripts/health-monitor-demo.js status
# Perform health check on specific server
node scripts/health-monitor-demo.js check "https://mcp.context7.com/mcp"
# Monitor health changes for 60 seconds
node scripts/health-monitor-demo.js monitor 60
# Attempt manual reconnection
node scripts/health-monitor-demo.js reconnect "http://localhost:30003/mcp"Auto-Reconnection Behavior
When a server goes offline:
- Detection: Health check failure detected within 30 seconds
- Status Change: Server marked as
disconnected→error - Auto-Reconnection: Attempts every 60 seconds automatically
- Recovery: When server returns, immediate reconnection
- Logging: All events logged to MongoDB with timestamps
MongoDB Health Data
Health monitoring data is stored in the server_health collection:
{
serverUrl: "http://localhost:30003/mcp",
status: "connected",
lastConnected: "2025-08-16T15:30:00.000Z",
lastDisconnected: "2025-08-16T15:25:00.000Z",
lastHealthCheck: "2025-08-16T15:31:00.000Z",
reconnectAttempts: 0,
errorMessage: null
}Example Use Cases
1. Multi-Service Integration
# Configuration for integrating Slack, GitHub, and documentation services
export DOWNSTREAM_MCP_SERVERS='{
"slack": {
"url": "http://localhost:30003/mcp",
"headers": {"Authorization": "Bearer ${SLACK_TOKEN}"},
"tools": {"enabled": ["channels_*", "users_*"], "defaultEnabled": false}
},
"github": {
"url": "http://localhost:30002/mcp",
"headers": {"Authorization": "token ${GITHUB_TOKEN}"},
"tools": {"disabled": ["delete_*", "admin_*"]}
},
"docs": {
"url": "https://mcp.context7.com/mcp"
}
}'2. Development vs Production Tool Control
# Enable all tools in development
export DOWNSTREAM_MCP_SERVERS='{"dev": {"url": "http://localhost:30001/mcp"}}'
# Restrict tools in production
export DOWNSTREAM_MCP_SERVERS='{
"prod": {
"url": "http://production-server/mcp",
"tools": {"enabled": ["read_*", "list_*"], "defaultEnabled": false}
}
}'3. Runtime Tool Management Workflow
# 1. Check current tool states
curl http://localhost:30000/admin/tools
# 2. Temporarily disable a problematic tool
curl -X POST http://localhost:30000/admin/tools/server/problematic_tool/disable \
-H "Content-Type: application/json" -d '{"updatedBy": "ops-team"}'
# 3. Re-enable after fix
curl -X POST http://localhost:30000/admin/tools/server/problematic_tool/enable \
-H "Content-Type: application/json" -d '{"updatedBy": "ops-team"}'
# 4. Remove runtime override (revert to config)
curl -X DELETE http://localhost:30000/admin/tools/server/problematic_tool4. Production Health Monitoring Workflow
# Monitor all servers continuously
node scripts/health-monitor-demo.js monitor 300 # 5 minutes
# Set up alerts for server failures
while true; do
offline_servers=$(curl -s http://localhost:30000/admin/health | \
jq -r '.data.currentStatuses[] | select(.status != "connected") | .serverUrl')
if [ ! -z "$offline_servers" ]; then
echo "ALERT: Servers offline: $offline_servers"
# Send notification (email, Slack, etc.)
fi
sleep 60
done
# Manual recovery of failed server
curl -X POST http://localhost:30000/admin/health/http%3A%2F%2Ffailed-server%2Fmcp/reconnect
# Check historical health data
MONGODB_URI="mongodb://localhost:27017/mcp_proxy" node -e "
const { MongoClient } = require('mongodb');
(async () => {
const client = new MongoClient('mongodb://localhost:27017/mcp_proxy');
await client.connect();
const collection = client.db('mcp_proxy').collection('server_health');
// Get servers with high failure rates
const healthStats = await collection.aggregate([
{ \$group: {
_id: '\$serverUrl',
totalReconnects: { \$sum: '\$reconnectAttempts' },
avgReconnects: { \$avg: '\$reconnectAttempts' }
}
},
{ \$sort: { totalReconnects: -1 } }
]).toArray();
console.log('Server Health Statistics:', healthStats);
await client.close();
})();
"How It Works
Tool Name Mapping
The proxy server transforms tool names from downstream servers by prefixing them with the server URL:
- Original tool:
read_wiki_structure - From server:
https://mcp.deepwiki.com/mcp - Proxied name:
https___mcp_deepwiki_com_mcp_read_wiki_structure
Request Flow
- Client sends MCP request to proxy server
- Proxy server creates a fresh MCP server instance (stateless)
- For tool calls, proxy parses the prefixed tool name to identify the target server
- Health check: Proxy verifies server status before forwarding request
- Request is forwarded to the appropriate downstream MCP server
- Response is returned to the client
- Background: Health monitoring continues every 30 seconds
Architecture
┌─────────────┐ HTTP POST ┌─────────────────┐ MCP Client ┌────────────────┐
│ AI Client │ ──────────────► │ MCP Proxy │ ──────────────► │ MCP Server 1 │
│ │ │ Server │ │ (Context7) │
└─────────────┘ │ │ ──────────────► ┌────────────────┐
│ (Stateless) │ │ MCP Server 2 │
└─────────────────┘ │ (DeepWiki) │
└────────────────┘Environment Variables
DOWNSTREAM_MCP_SERVERS: Comma-separated list of downstream MCP server URLs or path to JSON config filePORT: Server port (default: 30000)MONGODB_URI: MongoDB connection string for logging and tool state management (optional)USER: User identifier for template substitution (optional)
API Endpoints
MCP Protocol Endpoints
POST /mcp: Main MCP endpoint for all requestsGET /mcp: Returns 405 Method Not Allowed (stateless mode)DELETE /mcp: Returns 405 Method Not Allowed (stateless mode)
Admin API Endpoints
Tool Management
GET /admin/tools: List all tools and their enabled/disabled statesPOST /admin/tools/:serverUrl/:toolName/enable: Enable a specific tool at runtimePOST /admin/tools/:serverUrl/:toolName/disable: Disable a specific tool at runtimeDELETE /admin/tools/:serverUrl/:toolName: Remove runtime state for a tool (reverts to config)
Health Monitoring
GET /admin/health: View health status of all serversGET /admin/health?serverUrl=<url>: View health status of specific serverPOST /admin/health/:serverUrl/check: Perform immediate health check on serverPOST /admin/health/:serverUrl/reconnect: Force reconnection attempt to server
Development
Scripts
npm start: Start with TypeScript (ts-node)npm run build: Compile TypeScript to JavaScriptnpm run start:js: Start compiled JavaScript versionnpm test: Run tests (not implemented)
Project Structure
mcp-proxy-server/
├── src/
│ └── index.ts # Main server implementation
├── config/ # Configuration examples
│ ├── servers-template-examples.json
│ ├── servers-with-tool-filtering.json
│ └── servers-local-only.json
├── scripts/ # Analytics and utilities
│ ├── analyze-tool-calls.js
│ ├── view-sample-record.js
│ └── health-monitor-demo.js
├── dist/ # Compiled JavaScript (after build)
├── package.json
├── tsconfig.json
└── README.mdExample Downstream Servers
- Context7:
https://mcp.context7.com/mcp- Library documentation and code examples - DeepWiki:
https://mcp.deepwiki.com/mcp- GitHub repository documentation
Error Handling
The server provides detailed error responses:
{
"jsonrpc": "2.0",
"error": {
"code": -32603,
"message": "Internal server error"
},
"id": null
}Common errors:
No client found for tool: <tool_name>- Tool name doesn't match any connected serverTool '<tool_name>' is disabled on server '<server_url>'- Tool is disabled via configuration or runtime stateArguments are required- Missing arguments in tool call- Connection errors to downstream servers
Client must accept both application/json and text/event-stream- Missing Accept header
Limitations
- Stateless Only: No session management or persistent connections
- HTTP Transport: Only supports HTTP-based MCP servers
- URL Encoding: Server URLs in admin API paths must be URL-encoded
- MongoDB Dependency: Tool management and logging features require MongoDB
License
ISC
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
