@bwb03/mcp-gateway
v0.1.0
Published
Generic MCP-to-HTTP gateway — auto-discovers any MCP server's tools and exposes them as REST endpoints. Wraps stdio or remote HTTP MCP servers so any agent framework can use them.
Maintainers
Readme
mcp-gateway
Use any MCP server from any agent framework — over plain HTTP.
mcp-gateway is a generic bridge that connects to any MCP server (stdio subprocess or remote HTTP) and exposes its tools as REST endpoints. Configure once with YAML, and any agent — OpenAI Assistants, custom code, OpenClaw, your own Python script — can use MCP servers without speaking the MCP protocol.

┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Any Agent │ HTTP │ mcp-gateway │ MCP │ MCP Server │
│ Framework │ ──────► │ │ ──────► │ (stdio or HTTP) │
└─────────────┘ REST └──────────────┘ proto └──────────────────┘Why?
The Model Context Protocol is a great way to expose tools to AI agents — but right now it's mostly used inside Claude apps (Desktop, Code, Managed Agents). If you're building with anything else (OpenAI, LangChain, custom frameworks, your own bot), you have to either:
- Hand-code an HTTP wrapper for every MCP server you want to use, or
- Implement the MCP protocol yourself in your agent framework
This gateway does #1 generically. Add a server to a YAML file → its tools become HTTP endpoints. No custom code per provider.
What It Does
- Wraps any MCP server — stdio (subprocess) or HTTP (remote) transport
- Auto-discovers tools — calls
listTools()and dynamically generates REST endpoints - Auto-generates
/manifest— agents can introspect available tools and their input schemas - Handles auth — OAuth 2.1 + PKCE with token persistence, API keys, or no-auth
- Multi-server — run many MCP servers behind one gateway, each on its own port
- Zero hand-coding — same gateway binary works with Filesystem, GitHub, Intentwise, Pacvue, anything
Quick Start
git clone [email protected]:BWB03/mcp-gateway.git
cd mcp-gateway
npm install
cp gateway.config.example.yaml gateway.config.yaml
npm startThat's it. Out of the box this wraps the Filesystem MCP server (pointed at $HOME) and exposes its 14 tools at http://localhost:3045. Try it:
curl http://localhost:3045/health
curl http://localhost:3045/manifestThen edit gateway.config.yaml to add more servers — see the example file for templates covering stdio, OAuth, API key, and no-auth servers.
Demo: Two Servers, Side By Side
A single config file wraps a stdio MCP server (Filesystem) and a remote HTTP MCP server (Intentwise) at the same time. Each gets its own port. Each becomes pure HTTP.
gateway.config.yaml:
servers:
filesystem:
transport: stdio
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "/Users/me/projects"
port: 3045
intentwise:
transport: http
url: https://mcp.intentwise.com/mcp
port: 3033
auth:
type: oauth
client_id: "your-client-id"
redirect_uri: "https://your-callback.example.com/callback"Start the gateway:
$ npm run authorize intentwise # one-time OAuth
$ npm start
[intentwise] listening on http://localhost:3033
[intentwise] discovered 5 tool(s):
POST /get_organization — Returns the list of Intentwise organizations...
POST /get_intentwise_accounts — Returns the list of AMS accounts for a given organization...
POST /search_schema — Search Intentwise schema for relevant tables...
POST /get_insights — Generate and execute a BigQuery SQL query from natural language...
POST /query — Generate and execute a BigQuery SQL query (deprecated alias)...
[filesystem] listening on http://localhost:3045
[filesystem] discovered 14 tool(s):
POST /read_file — Read the complete contents of a file as text...
POST /write_file — Create a new file or completely overwrite an existing file...
POST /edit_file — Make line-based edits to a text file...
POST /list_directory — Get a detailed listing of all files and directories...
POST /search_files — Recursively search for files and directories matching a pattern...
POST /get_file_info — Retrieve detailed metadata about a file or directory...
... and 8 moreUse it from anywhere — any language, any framework, any agent:
# stdio MCP server (Filesystem)
$ curl -X POST http://localhost:3045/list_directory \
-H "Content-Type: application/json" \
-d '{"path":"/Users/me/projects/mcp-gateway/src"}'
"[DIR] auth\n[FILE] config.ts\n[FILE] constants.ts\n[FILE] gateway.ts\n[FILE] index.ts\n[FILE] server.ts"# Remote HTTP MCP server (Intentwise — OAuth-authenticated)
$ curl -X POST http://localhost:3033/get_organization \
-H "Content-Type: application/json" \
-d '{}'
{
"organizations": [
{ "organization_id": 42280, "name": "Voartex" }
]
}# Health check
$ curl http://localhost:3045/health
{"status":"ok","server":"filesystem","connected":true,"tool_count":14}# Tool discovery — agents can introspect everything
$ curl http://localhost:3033/manifest
{
"name": "mcp-gateway:intentwise",
"version": "0.1.0",
"transport": "http",
"upstream": "https://mcp.intentwise.com/mcp",
"tools": [
{
"name": "get_organization",
"method": "POST",
"path": "/get_organization",
"description": "Returns the list of Intentwise organizations...",
"input_schema": { "type": "object", "properties": { ... } }
},
...
]
}That's the whole story: one YAML, two MCP servers (one local subprocess, one remote OAuth), every tool available as a plain HTTP endpoint. No custom code per provider.
Endpoints (per server)
Each configured server gets its own port and exposes:
| Endpoint | Method | Description |
|---|---|---|
| /manifest | GET | All discovered tools with their input schemas |
| /health | GET | Connection status + tool count |
| /{tool_name} | POST | One endpoint per discovered tool — JSON body matches the tool's input schema |
Example: /manifest response
{
"name": "mcp-gateway:intentwise",
"version": "0.1.0",
"transport": "http",
"upstream": "https://mcp.intentwise.com/mcp",
"base_url": "http://localhost:3033",
"tools": [
{
"name": "get_organization",
"method": "POST",
"path": "/get_organization",
"description": "Returns the list of Intentwise organizations...",
"input_schema": {
"type": "object",
"properties": {
"name_filter": { "type": "string" }
}
}
}
]
}Agents can hit /manifest once to learn everything about what's available.
CLI
mcp-gateway # Start all servers from gateway.config.yaml
mcp-gateway start <server> # Start a specific server
mcp-gateway tools <server> # List discovered tools for a server (no HTTP listener)
mcp-gateway status # Show all configured servers
mcp-gateway --version
mcp-gateway --helpOAuth setup (one-time per HTTP server with auth.type: oauth):
npm run authorize <server_name>Configuration Reference
Common fields
| Field | Required | Description |
|---|---|---|
| transport | ✅ | "http" or "stdio" |
| port | ✅ | Local port the gateway listens on for this server |
| path_prefix | optional | URL prefix for all tool paths (e.g., intentwise → /intentwise/get_organization) |
transport: http fields
| Field | Required | Description |
|---|---|---|
| url | ✅ | Remote MCP server URL |
| auth | ✅ | Auth config (oauth / api_key / none) |
transport: stdio fields
| Field | Required | Description |
|---|---|---|
| command | ✅ | Executable to run (e.g., npx, node, python) |
| args | optional | Command-line arguments |
| env | optional | Environment variables for the subprocess (${VAR} expanded from process.env) |
| cwd | optional | Working directory for the subprocess |
Auth types (for HTTP transport)
# OAuth 2.1 with PKCE
auth:
type: oauth
client_id: "..."
redirect_uri: "https://..."
scope: "..." # optional
token_file: "..." # optional, defaults to ~/.mcp-gateway/tokens/{server}.json
# API key in header
auth:
type: api_key
header: X-API-Key
env: MY_API_KEY # value pulled from process.env at startup
# Public / no auth
auth:
type: noneHow It Compares
| | mcp-gateway | Hand-coded HTTP adapter | Claude Managed Agents | |---|---|---|---| | Works with non-Claude agents | ✅ | ✅ | ❌ | | Self-hosted | ✅ | ✅ | ❌ Anthropic only | | stdio MCP support | ✅ | One-off code | ✅ | | Remote HTTP MCP support | ✅ | One-off code | ✅ | | Multi-server in one process | ✅ | ❌ Build it | ✅ | | Auto-discovers tools | ✅ | ❌ Hand-coded | ✅ | | Auto-generated manifests | ✅ | ❌ Hand-coded | N/A (native tool calls) | | Effort to add a new MCP server | YAML entry | Days of code | Add to agent config | | Cost | Free (your infra) | Free | Per session-hour + tokens |
Use Claude Managed Agents if your agents are Claude-based and you want zero infrastructure. Use mcp-gateway if you're using OpenAI / LangChain / custom frameworks, need self-hosting, or want a drop-in HTTP layer for any MCP server.
Architecture
mcp-gateway/
src/
index.ts # CLI entry — reads config, starts gateways
config.ts # YAML parser + Zod validation + ${ENV} expansion
gateway.ts # Core: MCP client wrapper + transport selection + discovery
server.ts # HTTP server with dynamic routes per discovered tool
auth/
oauth-provider.ts # Generic OAuth 2.1 + PKCE implementation
scripts/
authorize.ts # Browser-based OAuth bootstrap
gateway.config.yaml # Your server definitions (gitignored)How a tool call flows
1. Agent: POST http://localhost:3033/get_organization { }
2. Gateway: routes path to upstream tool name "get_organization"
3. Gateway → MCP Client → Upstream MCP Server: callTool("get_organization", {})
4. Upstream returns MCP CallToolResult with text content
5. Gateway extracts text, parses as JSON
6. Agent receives plain JSON responseThe gateway is a thin proxy. It doesn't transform, cache, or rate-limit by default — those are planned as optional middleware.
Roadmap
- [x] Phase 1: Core gateway — config, discovery, dynamic routes, manifest, OAuth
- [x] Phase 1.5: stdio support — wrap any subprocess MCP server
- [ ] Phase 2: Multi-server validation — battle-test with 5+ different MCP servers
- [ ] Phase 3: Middleware — universal envelope wrapper, response cache, rate limiting, structured logging
- [ ] Phase 4: Hosted mode — Docker + Railway deployment, multi-tenant token storage
See the project plan for details.
Development
npm install
npm run dev # Run via tsx
npm run build # Build with tsup
npm test # Unit tests (vitest)Project uses native node:http (no Express/Fastify), @modelcontextprotocol/sdk for MCP, zod for validation, and yaml for config parsing.
Contributing
Contributions welcome. See CONTRIBUTING.md. For security issues, see SECURITY.md.
License
MIT — see LICENSE.
