Skip to main content
Glama

MCP Gateway

Tests Release PyPI version Python License Code Style: Ruff PyPI Downloads MCP Protocol Code Mode Local-First Security Observability Built-in Sponsor

One endpoint for every MCP server your agent needs — fetch tool schemas on demand instead of loading everything upfront.

MCP Gateway aggregates multiple MCP servers behind a single headless HTTP/SSE endpoint. Its Code Mode exposes five MCP meta-tools (listToolFiles, readToolFile, getToolDocs, executeTool, callManyTool) so agents discover signatures lazily and fan out bounded parallel calls without leaving the MCP surface. The host-side Python call_many helper remains available for direct code use, but the MCP contract exposes callManyTool as the fifth meta-tool.

Why MCP Gateway

  • Fewer wasted tokens — Agents fetch only the schemas they need, when they need them.

  • One connection to manage — Add, remove, or refresh servers in a single registry; agents connect to one endpoint.

  • Safe local-first defaults — Binds to 127.0.0.1 by default, screens local commands via an allowlist, masks secrets, and CSRF-protects the admin dashboard.

Related MCP server: MCPHub

Who It's For

  • Agent developers wiring Pi, Antigravity, Claude Desktop, Cursor, or any MCP-compatible client to multiple MCP servers through one gateway.

  • Operators running local-first infrastructure who want a CLI and dashboard with health probes, Prometheus metrics, and structured JSON logs.

Quick Start

  1. Install: pip install mcp-gway

  2. Add a server: mcp-gway add files --type local --command "npx -y @modelcontextprotocol/server-filesystem /path/to/dir"

  3. List servers: mcp-gway list

  4. Serve HTTP: mcp-gway serve --transport http

  5. Connect: Point your agent to http://127.0.0.1:8080/mcp

For more examples and transports, see the CLI Reference and Integrations.

Features

  • Multi-Server Aggregation — Connect to multiple MCP servers (local or remote) and expose them through a single endpoint. One URL for every agent; one registry to manage.

  • Code Mode — Five MCP meta-tools let LLMs discover schemas on demand, execute them in a hermetic sandbox, and fan out bounded parallel calls without loading all tool definitions upfront.

  • OAuth 2.0 Support — Built-in OAuth flow with Dynamic Client Registration (RFC 7591), secure token storage, and automated /.well-known/oauth-protected-resource discovery metadata (RFC 8707) for OAuth-capable MCP clients.

  • Hexagonal Architecture — Strict separation between pure domain models/ports, application use cases, and infrastructure adapters for isolated unit testability without running servers.

  • Hermetic Sandbox — Starlark-based sandbox for safe, constrained code execution.

  • MCP Protocol Compliant — Implements the Model Context Protocol over HTTP, SSE, and stdio.

  • Local-First Security — Local-first design with SSRF guards, command allow-lists, and CSRF protection.

  • Built-In Observability — Structured JSON logs, Prometheus metrics, and health probes built in.

Documentation

Development

uv sync --all-groups
uv run pytest -v   # 688 tests

See docs/development.md for checks, probes, and pre-commit.

Repobeats analytics

License

MIT

Available Tools

5 tools
callManyToolA

Runs up to 50 tool calls in one bounded fan-out (8 concurrent) and returns results in input order. Use it when several calls are independent - across servers or within one - and you want one round trip instead of N. Each item is {server, tool, arguments}; server and tool names are the ones readToolFile shows. A failed item returns ok=false with its error and never cancels its siblings, so a partial result is still usable. Do NOT use it when one call depends on another call's result: write an executeTool script for that.

NameRequiredDescriptionDefault
callsYesIndependent tool calls to run in parallel. Results come back in this order.

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does well: it discloses the 50-call cap, 8-way concurrency, result ordering, and failure isolation ("ok=false with its error and never cancels its siblings"). It stops short of timeout behavior, recursion/nesting rules, and whether calls count against any quota.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core behavior, then usage, then failure semantics, then the exclusion — a sensible ordering with no filler sentences. It runs five sentences where four would do, and the readToolFile reference introduces noise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers usage conditions, limits, ordering, and partial-failure behavior, which is most of what an agent needs to call this safely. With no output schema, the description should say what a successful item looks like (it only documents the ok=false case).

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the schema already documents the calls array and its server/tool/arguments members, making 3 the baseline. The description adds item shape and ordering semantics, but its claim that server and tool names are "the ones readToolFile shows" is at odds with the schema, which points to listToolFiles — a small ambiguity rather than clear added value.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Runs up to 50 tool calls in one bounded fan-out") plus the two defining traits: 8-way concurrency and input-order results. An agent can distinguish it from executeTool and from the file-listing siblings without opening the schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit use condition ("when several calls are independent - across servers or within one") and an explicit exclusion plus the alternative ("Do NOT use it when one call depends on another call's result: write an executeTool script"). Names the sibling to switch to.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

executeToolA

Executes Python-like (Starlark) code in a sandboxed interpreter with MCP tool access as Server.tool_name(param=value) (e.g., result = Filesystem.read_file(path=".")). Final step of listToolFiles -> readToolFile -> (optional) getToolDocs -> executeTool; read the stub first and use the exact callable name shown. Security: L1 code validation (no imports/classes/file-IO/network primitives), L2 sandboxed runtime (no external modules, no filesystem/network/process access except via MCP tools, memory isolation), L3 bounded execution timeout, L4 Tool ACL (only tools_to_execute-allowed CodeMode servers/tools are visible). STARLARK RULES: no try/except/raise, no classes, no imports, no f-strings (use % formatting), no is (use ==), synchronous calls only, dict access via result["key"], assign output to result. Each call runs in a FRESH ISOLATED SCOPE (no state persists); print() output is captured to logs. Returns {"result": ..., "logs": [...]}.

NameRequiredDescriptionDefault
codeYesStarlark code calling tools as result = Server.tool_name(param="value") — assign `result` to your final answer

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden and does so: it discloses the four security layers (validation, sandbox, timeout, Tool ACL), states that each call runs in a fresh isolated scope with no persistence, that print() is captured to logs, and that it returns {result, logs}. That is exactly the mutation/execution-risk context an agent needs.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with what the tool does, then workflow, then security, then syntax rules – a logical order with no filler sentences. It is dense and long for a one-param tool, but each block (workflow, ACL, Starlark rules) maps to a distinct failure mode an agent would otherwise hit.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Despite having no output schema and no annotations, the description specifies the return shape ({result, logs}), the isolation model, the timeout bound, and the ACL gate. Nothing material is missing for an agent to call this correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single param's description already says to assign `result`, so the baseline would be 3. The description adds real value by constraining the code syntax (no imports/classes/try-except, % formatting, == not `is`, dict access via result["key"]), which genuinely shapes what goes into `code`.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Executes Python-like (Starlark) code in a sandboxed interpreter') plus the distinctive capability of calling MCP tools as Server.tool_name(param=value). Named siblings (listToolFiles, readToolFile, getToolDocs) are positioned in the workflow, so an agent can tell this apart from the discovery tools without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit ordered workflow: listToolFiles -> readToolFile -> (optional) getToolDocs -> executeTool, plus the operational instruction to read the stub first and use the exact callable name shown. It effectively names the alternatives and the precondition that selects this one over them.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

getToolDocsA

Get detailed documentation for a specific tool including full parameter descriptions, types, and usage examples. Use this when the compact signature from readToolFile is not sufficient to understand how to use a tool. Requires both server name and tool name as parameters (e.g., server="filesystem", tool="read_file").

NameRequiredDescriptionDefault
toolYesThe tool you want to explore, like read_file
serverYesThe server that owns the tool, like filesystem

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are present, so the description carries the burden; it discloses that both server and tool are required and shows the keying convention (server+tool) needed to address a doc record. It doesn't state whether unknown tool names error or return empty, which is the one behavioral gap for a lookup tool.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, front-loaded with what is returned before the routing condition. The inline server/tool example partly duplicates the schema's own examples, a small redundancy, but nothing is padded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter documentation lookup with a fully described schema and no output schema, the description says what comes back (param descriptions, types, examples), when to use it, and what it requires. An agent has everything needed to call it correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so both parameters are already documented with the same filesystem/read_file examples. The description repeats that both are required but adds no format, casing, or ambiguity-resolution guidance beyond the schema, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource ('Get detailed documentation for a specific tool') and enumerates what the output contains (full parameter descriptions, types, usage examples). It also explicitly contrasts with the sibling readToolFile's compact signature, so an agent can distinguish the two without opening a schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit trigger ('when the compact signature from readToolFile is not sufficient') and names the alternative tool that covers the other case. Nothing is left to inference about when to escalate from readToolFile to this tool.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

listToolFilesA

Lists the virtual .pyi stub files for connected CodeMode MCP servers (CodeMode VFS). Default server-level binding returns servers/.pyi per server (e.g., servers/filesystem.pyi); tool-level binding returns servers//.pyi per tool. The filename stem is the exact callable name for executeTool. Workflow: listToolFiles -> readToolFile -> (optional) getToolDocs -> executeTool. In code, call tools as Server.tool_name(param=value) (e.g., Filesystem.read_file(path=".")). CALL THIS FIRST when the user names a server, tool, or capability not in your visible tool list — connected MCP servers are only discoverable here. Do NOT claim a server or capability is unavailable until listToolFiles confirms it is unavailable, then offer the closest alternative from the visible list or explain that it is not connected.

NameRequiredDescriptionDefault

No parameters

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden and does so: it discloses that the files are virtual VFS stubs, the exact path shape for both server-level and tool-level binding, and the naming contract tying the filename stem to the callable name for executeTool. It also states the discovery scope limit (connected servers only) and the call syntax used downstream.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core statement, then workflow, then the invocation-syntax note; the ordering is good and no sentence is filler. The 'In code, call tools as Server.tool_name(param=value)' sentence drifts into executeTool's territory and is the one piece that could be trimmed or moved.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Zero params, no output schema, and no annotations — so the description must supply everything, and it does: what is returned (path patterns per binding mode), how those paths map to callable names, and where this tool sits in the discovery sequence. Nothing needed to invoke it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes zero parameters, so there is nothing for the description to disambiguate and the baseline of 4 applies. The description does useful adjacent work by explaining that output shape varies by binding mode, but that is return-value context rather than parameter meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Lists the virtual .pyi stub files for connected CodeMode MCP servers') and immediately explains the two binding modes that determine what gets listed. This clearly separates it from readToolFile, getToolDocs, and executeTool, which all operate on files this tool enumerates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit ordered workflow (listToolFiles -> readToolFile -> optional getToolDocs -> executeTool) plus a hard trigger: 'CALL THIS FIRST when the user names a server, tool, or capability not in your visible tool list.' It also supplies a negative rule — do not claim unavailability until this tool confirms it — which is exactly the when-not guidance agents need.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

readToolFileA

Reads a virtual .pyi stub: servers/.pyi for the full server signature list, or servers//.pyi for a single tool (both listed by listToolFiles). Matching is case-insensitive and the .pyi extension is optional. Returns the authoritative callable name and arguments for executeTool as Server.tool_name(param=value). If the compact signature is insufficient, use getToolDocs. Workflow: listToolFiles -> readToolFile -> (optional) getToolDocs -> executeTool.

NameRequiredDescriptionDefault
endLineNoWhere to stop reading — useful for large servers (leave empty for full view).
fileNameYesStub to read - e.g., servers/filesystem.pyi or servers/filesystem/read_file.pyi
startLineNoWhere to start reading — useful for large servers (leave empty for full view).

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden and does disclose key behavior: case-insensitive matching, optional .pyi extension, and that the returned signatures are authoritative for executeTool calls. It stops short of error behavior (what happens for an unknown fileName) and does not restate that the operation is non-mutating beyond the verb 'Reads'.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action and path forms, then constraints, then the workflow sequence. Dense but every sentence carries information; the only mild redundancy is restating the two path shapes that also appear in the schema example.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

No output schema and no annotations, so the description must supply the return semantics, which it does ('returns the authoritative callable name and arguments'). Workflow and alternatives are covered; the remaining gap is failure behavior for an invalid or unlisted fileName.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds semantics the schema lacks: fileName values must come from listToolFiles, matching is case-insensitive, and the extension is optional. startLine/endLine are covered by the schema descriptions, so no further description text is required.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb ('Reads') and a specific resource (a virtual .pyi stub), and enumerates the two accepted path shapes (servers/<server>.pyi and servers/<server>/<tool>.pyi). It also names the sibling (listToolFiles) that produces valid inputs, so an agent can distinguish it from listToolFiles and getToolDocs immediately.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives an explicit workflow chain: listToolFiles -> readToolFile -> (optional) getToolDocs -> executeTool, plus a concrete condition for escalating ('If the compact signature is insufficient, use getToolDocs'). Both when-to-use and when-to-use-an-alternative are stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv6.1.1
    • RemovedcallMany
    • AddedcallManyTool
    • AddedexecuteTool
    • RemovedexecuteToolCode
  2. 5 tool updatesv4.10.2
    • First observedcallMany
    • First observedexecuteToolCode
    • First observedgetToolDocs
    • First observedlistToolFiles
    • First observedreadToolFile

TDQS

A4.6/5.0

Scored across 5 tools

Disambiguation5/5

Each tool occupies a distinct step in the discovery-to-execution workflow: listing stubs, reading signatures, fetching detailed docs, executing a script, and fan-out execution. The boundaries between executeTool and callManyTool are explicitly clarified by dependency/fan-out guidance. No two tools appear to do the same thing.

Naming Consistency4/5

All names use camelCase with a verb+object pattern (get, list, read, execute, call). There are minor deviations in object naming, such as singular/plural differences and the inserted 'Many' in callManyTool, but the convention is still readable and predictable.

Tool Count5/5

Five tools is well-scoped for a gateway server that needs discovery, documentation inspection, single execution, and batch execution. Each tool has a clear role and none feels redundant or missing from the core workflow.

Completeness5/5

The surface covers the full gateway lifecycle: discover connected servers/tools, read authoritative callable signatures, fetch deeper documentation, execute a single script, and fan out independent calls. No obvious operational gap or dead end is apparent for the stated CodeMode gateway purpose.

Maintenance

ActivityActive
ResponsivenessWithin a week

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Aggregates multiple MCP servers via a single interface with token optimization and multiple operating modes (Gateway, Meta, Proxy, Search, Code).
    7
    8
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Centralized management and routing of multiple MCP servers via unified Streamable HTTP/SSE endpoints, with granular group visibility, smart routing, and authentication.
    2,698 npm
    Apache 2.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables aggregating and routing multiple backend MCP resource servers so clients can access their combined tools and resources through a unified SSE, Streamable HTTP, or Stdio interface, with optional authentication and web-based management.
    105 npm
    MIT