Dev.to AI πŸ€– Ai πŸ‘ 0 πŸ“– 10 min read

What Is an MCP Gateway? When You Need One and How to Set It Up

An MCP gateway is a server that sits between AI clients (Claude Code, Claude Desktop, Cursor, your own agents) and the Model Context Protocol servers they use. It connects to each MCP server once, stores their credential

What Is an MCP Gateway? When You Need One and How to Set It Up

An MCP gateway is a server that sits between AI clients (Claude Code, Claude Desktop, Cursor, your own agents) and the Model Context Protocol servers they use. It connects to each MCP server once, stores their credentials server-side, and exposes the combined tool set at a single endpoint. Each client authenticates with its own key and sees only the tools that key is allowed to use, and every tool call is logged in one place. You need one when two or more of these are true: several people or clients share the same MCP servers, credentials are scattered across laptops, different agents need different tool permissions, or you need a record of which tool calls ran.

This post explains what a gateway does, when it is worth adding, and how to set one up with an open-source gateway, plus the three fixes worth making whether or not you add one.

MCP connections without a gateway versus with an MCP gateway

The problem an MCP gateway solves

MCP makes it easy to give an agent tools. It also makes it easy to end up with:

  • The same GitHub server configured separately in .mcp.json, ~/.cursor/mcp.json, and claude_desktop_config.json, with a copy of the same token in each.
  • 300 tools visible to an agent that needs five, filling the context window and making the model pick the wrong tool.
  • A delete_repository tool that runs without anyone approving it.
  • No way to answer "which tool calls did this agent make yesterday, with what arguments?"

Every client-server pair is a separate configuration to update, a separate credential to rotate, and a separate place nothing is logged. With N clients and M servers you maintain up to N Γ— M connections. A gateway reduces that to N connections to the gateway and M connections from it.

What an MCP gateway does

Function What it means in practice
Aggregation One /mcp endpoint exposes tools from many upstream servers
Credential storage Upstream tokens live on the gateway; people get revocable per-person keys instead
Per-identity tool scoping Each key sees only granted tools; deny by default
Transport bridging Clients speak HTTP to the gateway while the gateway runs stdio servers internally
Approval control Tool calls on the API path come back to your app for approval instead of auto-running
Health checks Periodic tools/list checks, automatic reconnects, per-server state
Logging and metrics Every tool call recorded with caller, tool, arguments, latency, and error
Context reduction On-demand tool discovery instead of sending every definition every turn

When you need an MCP gateway

Pick the topology from your situation:

Situation Recommendation
One developer, one or two local servers (filesystem, a local database) Direct stdio connections are fine. Keep secrets in environment variables, not the JSON.
A team sharing the same servers, or servers configured in two or more clients Put a gateway in front: one /mcp endpoint, credentials stored once, per-person keys.
A production agent in app code A gateway, or a single in-app MCP client layer that owns allow-lists, approvals, timeouts, and logging. Never let each feature open its own MCP connections.
Three or more servers, or 50+ tools A gateway plus aggressive filtering and on-demand tool discovery.
Different trust levels (production and development, support and admin) A gateway with per-key tool allow-lists, separate keys per environment and role.

A gateway is worth it once you need any two of: shared credentials, per-identity tool scoping, a central log of tool calls, or one configuration across several clients.

Three fixes to make first, with or without a gateway

Most of the value comes from these, and they apply to any setup.

1. Enforce a tool budget. Target 5 to 20 tools per agent task. Allow-list tools per agent rather than per server: a code-review agent needs get_pull_request and list_files, not the 40 other GitHub tools. Remove near-duplicates, because the model will alternate between two search tools from two servers. Selection accuracy usually drops once 30 to 40 tools are visible at once.

2. Least privilege for every identity. Give each agent, user, team, and environment its own credential so access can be scoped and revoked individually. Deny by default. Use the narrowest upstream credential: read-only database users, fine-grained tokens limited to specific repos, OAuth scopes like drive.readonly.

3. Human approval for destructive and side-effecting tools. Auto-execute only read-only, idempotent tools. Anything that writes, deletes, sends, pays, or deploys goes through an approval step that shows the exact arguments. Enforce it in code; "never delete anything" in the system prompt is not a control.

To see where you stand, inventory every MCP config on a machine and look for literal credentials:

ls -1 .mcp.json .cursor/mcp.json .vscode/mcp.json .gemini/settings.json 2>/dev/null
ls -1 ~/.claude.json ~/.cursor/mcp.json \
  "$HOME/Library/Application Support/Claude/claude_desktop_config.json" 2>/dev/null
grep -rIinE '(token|secret|api[_-]?key|password|authorization)"?\s*[:=]' \
  .mcp.json .cursor/mcp.json .vscode/mcp.json ~/.claude.json ~/.cursor/mcp.json 2>/dev/null \
  | grep -vE '\$\{|env\.|<' | head -50

A literal token in a committed file is a leak: rotate it first, then move it. A literal token in a home-directory file is a credential you cannot revoke centrally.

Set up an MCP gateway with Bifrost

Bifrost is an open-source (Apache 2.0) AI gateway with a built-in MCP gateway. It connects to stdio, HTTP, SSE, and OpenAPI-generated MCP servers and exposes them at /mcp. The Bifrost MCP docs cover the full API; the steps below get a working setup.

1. Run the gateway

npx -y @maximhq/bifrost                       # or:
docker run -p 8080:8080 -v $(pwd)/data:/app/data maximhq/bifrost
# UI and API on http://localhost:8080

For production, pin a version (maximhq/bifrost:<version>), enable dashboard auth and enforce_auth_on_inference, and serve it over TLS.

2. Register MCP servers once

Servers go under mcp.client_configs in config.json (or the MCP Gateway page in the UI). Secrets are referenced as env.VAR, so they never appear in the file:

{
  "client": { "enforce_auth_on_inference": true },
  "mcp": {
    "client_configs": [
      {
        "name": "crm",
        "connection_type": "http",
        "connection_string": "env.CRM_MCP_URL",
        "auth_type": "headers",
        "headers": { "Authorization": "env.CRM_MCP_AUTH" },
        "tools_to_execute": ["search_contacts", "get_contact", "update_contact"]
      },
      {
        "name": "filesystem",
        "connection_type": "stdio",
        "stdio_config": {
          "command": "npx",
          "args": ["-y", "@modelcontextprotocol/server-filesystem", "/srv/shared-docs"],
          "envs": ["HOME", "PATH"]
        },
        "auth_type": "none",
        "tools_to_execute": ["read_text_file", "list_directory", "search_files"]
      }
    ],
    "tool_manager_config": { "tool_execution_timeout": "60s", "max_agent_depth": 10 }
  }
}

Server names must use letters, digits, and underscores (no hyphens or spaces). In Docker, stdio servers need their runtime (npx, python) inside the image; otherwise run the server separately and connect over HTTP.

3. Give each caller a scoped key

Virtual keys carry the tool grants. A key with no mcp_configs gets no MCP tools:

{
  "governance": {
    "virtual_keys": [
      {
        "id": "vk-support-prod",
        "name": "support-agent-prod",
        "value": "env.SUPPORT_AGENT_VK",
        "is_active": true,
        "mcp_configs": [
          { "mcp_client_name": "crm", "tools_to_execute": ["search_contacts", "get_contact"] }
        ]
      }
    ]
  }
}

Three filter levels for MCP tools: server baseline, virtual key ceiling, request headers

A tool is available only if it passes three filter levels: the server baseline (tools_to_execute on the server), the key's ceiling (mcp_configs on the virtual key), and optional request headers (x-bf-mcp-include-clients, x-bf-mcp-include-tools) that can narrow access for one request but never widen it.

4. Connect your clients

Claude Code needs one entry instead of one per server:

claude mcp add --transport http bifrost http://localhost:8080/mcp \
  --header "Authorization: Bearer sk-bf-your-virtual-key" --scope user

Use --scope user or local scope for anything with a key in it; --scope project writes a checked-in .mcp.json. Run /mcp inside Claude Code to confirm the gateway is connected and shows the expected tool count.

Claude Desktop, Cursor, and other hosts with HTTP and header support use the same shape (exact keys vary by host):

{
  "mcpServers": {
    "bifrost": {
      "url": "http://localhost:8080/mcp",
      "headers": { "Authorization": "Bearer sk-bf-your-virtual-key" }
    }
  }
}

When a host like Claude Code runs the agent loop, approvals happen in the host (permission prompts and allow lists). Keep destructive tools off the key entirely for anything that runs unattended.

5. Verify it

# Servers are connected and healthy, with tool counts
curl -s http://localhost:8080/api/mcp/clients | jq '.[] | {name: .config.name, state, tools: (.tools|length)}'

# A scoped key sees only its granted tools
curl -s -X POST http://localhost:8080/mcp -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer sk-bf-support-key' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '[.result.tools[].name]'

# Tool-call metrics are flowing
curl -s http://localhost:8080/metrics | grep bifrost_mcp_client_operation_duration_seconds_count

Also call a tool outside the key's grant and confirm you get an error, not a result. Turn these checks into CI tests so a config change that widens access fails the build.

Cutting tool-definition tokens with Code Mode

With many servers, sending every tool definition on every turn gets expensive. Bifrost's Code Mode replaces a server's individual tools with four meta-tools: the model lists available tool stubs, reads compact Python signatures for the ones it needs, and runs a short sandboxed script that calls them. Intermediate tool results stay in the sandbox, and the model receives only what the script prints.

Bifrost's published benchmark reports 58.2% fewer input tokens at 96 tools across 6 servers, 84.5% at 251 tools across 11 servers, and 92.8% at 508 tools across 16 servers, with pass rates unchanged or better. Results depend on the workload, so measure your own before and after. Enable it per server with "is_code_mode_client": true, and keep classic tools for one or two small servers the model calls on almost every turn.

Common mistakes

  • Adding every server "in case it is useful." Each tool costs tokens on every request and dilutes selection.
  • Allow-listing a whole server (["*"]) on production keys when two read tools would do.
  • Trusting a third-party server's readOnlyHint annotation as a security control. Annotations are hints from the server author.
  • Unpinned npx -y some-mcp-server. A new release can change tool names or descriptions under you; pin [email protected].
  • Leaving automatic tool injection on while the same client also connects to /mcp, so the model sees every tool twice. Turn on disable_auto_tool_inject in that setup.
  • Running a gateway with auth off on a shared network.

Install the mcp-gateway-best-practices skill

mcp-gateway-best-practices

The audit, fixes, and gateway setup in this post are packaged as an open-source agent skill, so your coding agent can inventory your MCP setup and fix it.

npx skills add build-with-ai-hq/mcp-gateway-best-practices

Then ask your agent "we have too many MCP servers, set up one endpoint for Claude Code and Cursor" or "MCP tools are eating my context." When the skill loads, the agent:

  1. Inventories MCP configs across the repo and home directory, finds hardcoded credentials, measures tool count and token cost per server, and classifies tools as read, write, destructive, or side-effecting.
  2. Applies fixes in order of impact: topology, tool budgets, tool naming and descriptions, least privilege, approval gates in code (Python and TypeScript), defenses against injected tool output, credential handling, transport choice, timeouts, health checks, logging, and tests.
  3. Sets up Bifrost as the MCP gateway where centralizing helps: one /mcp endpoint, per-key tool allow-lists, request-level filtering, Code Mode, health monitoring, and tool-call logs and metrics.
  4. Verifies the result with curl checks, metrics queries, and permission tests.

Related reading

FAQ

What is the difference between an MCP gateway and an API gateway?

An API gateway routes HTTP requests to backend services. An MCP gateway speaks the Model Context Protocol on both sides: it acts as an MCP client to upstream servers and as an MCP server to hosts like Claude Code, so it can merge tool lists, filter tools per caller, and log individual tool calls.

Is an MCP gateway the same as an MCP proxy?

A proxy usually forwards one server's traffic. A gateway aggregates many servers behind one endpoint and adds credential storage, per-identity tool scoping, health checks, and logging.

Do I need an MCP gateway for one developer?

Usually not. One developer with one or two local servers can use direct stdio connections, with secrets in environment variables. Add a gateway when you share servers, need per-identity permissions, or want a central log.

Does an MCP gateway add latency?

It adds a network hop for tool calls. For most tools the upstream call dominates. Measure p95 tool-call latency per tool from the gateway's metrics before and after.

Can an MCP gateway protect against prompt injection?

It limits the damage. Per-key tool allow-lists mean a hijacked agent cannot reach tools outside its grant, and explicit execution sends tool calls back to your code for approval. It does not stop the model from reading injected text, so approvals and egress limits still matter.

πŸ“° Read the original article on Dev.to AI

Originally published by Dev.to AI. Aggregated on AIWithGhost for educational purposes β€” full credit and traffic to the original publisher.