Skip to main content

What the MCP gateway does

GoModel can sit between your agent clients (Claude Code, Claude Desktop, Cursor, VS Code, …) and the MCP (Model Context Protocol) servers they use — the same way it already sits between your apps and model providers:
  • One endpoint, one key. Clients connect to https://your-gateway/mcp with a GoModel API key. They never hold upstream MCP credentials; the gateway injects each server’s headers itself.
  • Aggregation with namespacing. Tools and prompts from every configured server appear in one catalog as {server}_{name} (for example github_create_issue), in a stable, deterministic order.
  • Least-privilege discovery. A server can be scoped to user_paths; callers outside the subtree do not merely get errors — the tools never appear in their tools/list at all. Operator-level allowed_tools / disallowed_tools filters trim noisy servers, which keeps agent context small.
  • Observability. Every tool call becomes a usage entry (server, tool, duration, sizes, error flag, labels, user path) and MCP requests appear in the audit log and request log like any other model traffic — labelled with the JSON-RPC method, and with the tool or prompt name for calls, so a tools/call row reads github_create_issue, not a bare path. User-path rate limits and budgets gate MCP requests too.

Connect a client

Point any streamable-HTTP MCP client at the gateway and pass your GoModel key as a bearer token:
{
  "mcpServers": {
    "gomodel": {
      "type": "http",
      "url": "https://your-gateway/mcp",
      "headers": {
        "Authorization": "Bearer sk-your-gomodel-key"
      }
    }
  }
}
Three ways to narrow what a client sees:
  • /mcp — everything the key’s user path may see, namespaced.
  • /mcp/{server} — a single server with its original tool names.
  • X-MCP-Servers: github,jira header — a comma-separated subset on /mcp.

Declare servers

Servers can be managed in the dashboard (MCP Servers page) or declared as infrastructure-as-code — declarative entries override same-name dashboard rows and are read-only there:
mcp:
  enabled: true # default; MCP_ENABLED=false disables the endpoints
  servers:
    github:
      url: https://api.githubcopilot.com/mcp
      headers:
        Authorization: "Bearer ${GITHUB_PAT}"
      user_paths: ["/engineering"] # optional visibility scope
      disallowed_tools: ["delete_repo"]
    local-files:
      transport: stdio # declarative-only; see security notes
      command: npx
      args: ["-y", "@modelcontextprotocol/server-filesystem", "/data"]
Or via the MCP_SERVERS env var (a JSON object, merged over YAML per name):
MCP_SERVERS='{"github":{"url":"https://api.githubcopilot.com/mcp","headers":{"Authorization":"Bearer ${GITHUB_PAT}"}}}'
Per-server fields:
FieldDefaultMeaning
urlEndpoint for http (streamable HTTP) and sse transports
transporthttphttp, sse (legacy), or stdio (config-only)
headersSent verbatim upstream; values support ${ENV}
command, args, envstdio subprocess definition
enabledtrueToggle without deleting
allowed_toolsallAllowlist of upstream tool names
disallowed_toolsnoneBlocklist, applied after the allowlist
user_pathseveryoneVisibility subtrees, like virtual models
tool_timeout30sUpper bound for one tools/call
Invalid declarations (bad name, missing url/command, unknown transport) abort startup with a clear error rather than silently dropping the server.

Health and lifecycle

The dashboard shows each server as connected, degraded, connecting, or disabled, with tool counts and the last error, and the Overview page summarizes MCP server health whenever servers are configured. A server whose listing fails keeps its previous catalog (marked degraded) and is re-probed every 60 seconds; healthy catalogs re-list every 5 minutes and refresh immediately when the upstream sends a list_changed notification. Reconnect on the dashboard (or POST /admin/mcp-servers/{name}/reconnect) forces a redial.

Inspect a server’s catalog

The dashboard’s catalog inspector (or GET /admin/mcp-servers/{name}/catalog) lists exactly what a server currently exposes through the gateway — tools, prompts, resources, and resource templates with their descriptions, after your allowed_tools / disallowed_tools filters. Names are the upstream originals; the aggregated /mcp endpoint serves them as {server}_{name}.

Security notes

  • Credential boundary. The MCP spec forbids token passthrough; GoModel terminates the client’s bearer token and injects per-server credentials from configuration. Client keys never reach an upstream.
  • stdio is declarative-only. stdio servers spawn subprocesses on the gateway host, so they can only be declared in config.yaml / MCP_SERVERS. The admin API and dashboard reject them — a dashboard login must never be equivalent to code execution on the gateway.
  • stdio subprocesses get a minimal environment. Only PATH, HOME, TMPDIR, USER, and LANG are inherited — never the gateway’s provider API keys or master key. Pass anything else explicitly via the server’s env: map (values support ${VAR}).
  • Dashboard-managed credentials live in the gateway database. Headers of admin-created servers are stored in the configured storage backend (they are only redacted at the API/UI layer). If your threat model excludes secrets in the database, declare those servers in config.yaml / MCP_SERVERS instead — ${ENV} references keep the secret in the environment, and declarative servers never touch the store.
  • Sessions are not authentication. Every request is bearer-authenticated, and a session is additionally bound to the user path that initialized it; presenting a leaked session ID under another identity returns 404.
  • Secret header values are shown redacted (***) in the admin API and dashboard; saving a form with *** preserves the stored secret.

Protocol coverage

Tools, prompts, resources, and resource templates are aggregated and relayed with raw schemas and results untouched. Upstream instructions are merged into the gateway’s initialize response. Server-initiated features (sampling, elicitation, roots) and resource subscriptions are not negotiated in this version, which downstream clients handle transparently.