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 git@github.com:BWB03/mcp-gateway.git
cd mcp-gateway
npm install
cp gateway.config.example.yaml gateway.config.yaml
npm start
That'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/manifest
Then 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
$ 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 more
Use it from anywhere — any language, any framework, any agent:
$ 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"
$ curl -X POST http://localhost:3033/get_organization \
-H "Content-Type: application/json" \
-d '{}'
{
"organizations": [
{ "organization_id": 42280, "name": "Voartex" }
]
}
$ curl http://localhost:3045/health
{"status":"ok","server":"filesystem","connected":true,"tool_count":14}
$ 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:
/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
mcp-gateway start <server>
mcp-gateway tools <server>
mcp-gateway status
mcp-gateway --version
mcp-gateway --help
OAuth setup (one-time per HTTP server with auth.type: oauth):
npm run authorize <server_name>
Configuration Reference
Common fields
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
url | ✅ | Remote MCP server URL |
auth | ✅ | Auth config (oauth / api_key / none) |
transport: stdio fields
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)
auth:
type: oauth
client_id: "..."
redirect_uri: "https://..."
scope: "..."
token_file: "..."
auth:
type: api_key
header: X-API-Key
env: MY_API_KEY
auth:
type: none
How It Compares
| 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 response
The gateway is a thin proxy. It doesn't transform, cache, or rate-limit by default — those are planned as optional middleware.
Roadmap
See the project plan for details.
Development
npm install
npm run dev
npm run build
npm test
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.