Getting started
MCP REST Bridge turns your REST APIs and existing MCP servers into a single, governed set of MCP tools — managed from a built-in admin UI. This guide gets you from zero to a running bridge with a registered backend in a few minutes.
Prerequisites
- Bun
1.x(the bridge uses Bun's built-ins —bun:sqlite,Bun.dns,Bun.password— so Node.js is not a substitute), or Docker. - An OpenAPI/Swagger URL for a REST API, or the URL of an existing MCP server.
Option A — Docker (fastest)
docker build -t mcpbridge .
export ADMIN_API_KEY=$(openssl rand -hex 24)
docker run -p 3000:3000 \
-e NODE_ENV=development \
-e SESSION_COOKIE_SECURE=false \
-e BOOTSTRAP_ADMIN_USERNAME=admin \
-e BOOTSTRAP_ADMIN_PASSWORD=change-me-min-12-chars \
-e ADMIN_API_KEYS=$ADMIN_API_KEY \
-v "$PWD/data:/app/data" \
mcpbridgeThen open http://localhost:3000/admin and log in with the bootstrap credentials. $ADMIN_API_KEY is the Bearer token the curl examples below use — keep it exported in the same shell, or re-export it later with the same value.
Local HTTP only
NODE_ENV=development and SESSION_COOKIE_SECURE=false relax the startup guards so the session cookie works over plain http://localhost. In production, serve over HTTPS and drop both — the cookie then becomes __Host-/Secure automatically.
Prefer not to build from source?
Once the first release is tagged, every release will publish a prebuilt, multi-arch, signed image to GHCR — you'll then be able to drop the docker build and use ghcr.io/carlxsmg/mcpbridge:latest as the image in docker run. Until then, build locally with the docker build above. See Deployment →.
Option B — Bun (local dev, hot reload)
bun install
cp .env.example .env # then set BOOTSTRAP_ADMIN_PASSWORD (min 12 chars)
cd admin-ui && bun install && cd ..
bun run dev:all # backend :8790 + admin UI :8791Why different ports than the Docker example above?
Dev mode deliberately uses high, uncommon ports (8790/8791) instead of the Docker/production default of 3000, so a local dev server doesn't clash with 3000 — or with a real gateway instance you might also be running locally. Both are configurable (PORT, UI_PORT in .env) — see Configuration →.
Open http://localhost:8791/admin/ and log in.
The bootstrap admin is created only once, while the users table is empty. After that these env vars are ignored and you manage users from the UI.
Set ADMIN_API_KEYS in .env (e.g. ADMIN_API_KEYS=$(openssl rand -hex 24)), restart bun run dev:all, then export the same value as $ADMIN_API_KEY for the curl examples below.
Every command below assumes Option A's port
The examples use http://localhost:3000 (Docker/Option A). On Option B, the backend is on :8790 instead — set export BASE=http://localhost:8790 and swap $BASE in for http://localhost:3000, or just replace the port by hand.
Register a REST API (auto-discovered from OpenAPI)
The easy path: in the UI, go to Add server → REST, paste an OpenAPI URL, and submit — the bridge fetches the spec, generates one MCP tool per operation, and starts health-checking the backend.
Or via the API (needs the admin API key you set above, sent as a Bearer token):
curl -X POST http://localhost:3000/register \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "petstore",
"health_url": "https://petstore3.swagger.io/",
"openapi_url": "https://petstore3.swagger.io/api/v3/openapi.json"
}'You can also include_tags / exclude_operations to select exactly which operations become tools, or pass a manual tools array instead of openapi_url when there's no spec.
Register an existing MCP server as an upstream
curl -X POST http://localhost:3000/register \
-H "Authorization: Bearer $ADMIN_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "github",
"kind": "mcp",
"mcp_url": "https://your-mcp-server.example.com/mcp",
"mcp_transport": "streamable-http"
}'The bridge connects to the upstream, discovers its tools, and re-exposes them through the same guard stack as everything else. Both streamable-http and sse upstream transports are supported.
Connect an MCP client
Point any MCP client (Claude Desktop, Cursor, your own agent) at a backend shard — one registered backend's tools. For the petstore you just registered, that's /mcp/petstore. The bridge negotiates the MCP protocol version via the official TypeScript SDK, which supports 2024-10-07 through 2025-11-25 and defaults to 2025-03-26 when a client sends none — see Connecting MCP clients → for details on version negotiation.
{
"mcpServers": {
"petstore": { "url": "http://localhost:3000/mcp/petstore" }
}
}(:8790 instead of :3000 if you're on Option B.)
Three endpoints, two planes:
| Endpoint | Plane | Gives the client |
|---|---|---|
/mcp/:clientName | data | One backend's tools (e.g. /mcp/petstore) |
/mcp-custom/:bundleName | data | A curated cross-backend subset — several behind one endpoint |
POST /mcp | control | sys_* tools to operate the gateway itself, not backend tools |
Transport is Streamable HTTP on every endpoint (the legacy SSE transport was removed).
Want one endpoint that exposes petstore and an upstream together?
That's a bundle — see Aggregating backends into one endpoint →.
Next steps
- Features → — the full capability list (guardrails, RBAC, canary, tracing, audit, and more).
- Why MCP REST Bridge → — how it compares and where it fits.
- Copy-and-run samples — the repo's
examples/directory has a ready-to-sendPOST /registerbody per registration mode, a config-as-codegateway.yaml, and drop-in MCP client configs (Claude Desktop, Cursor). - Lock things down for production: set
MCP_API_KEYS, configure per-tool guardrails, and serve behind HTTPS.