Skip to content

feat(gateway): add unified MCP gateway with per-domain enable/disable#39

Merged
MKartaviciute merged 2 commits into
CesiumGS:mainfrom
gaopengbin:feat/gateway-server
May 4, 2026
Merged

feat(gateway): add unified MCP gateway with per-domain enable/disable#39
MKartaviciute merged 2 commits into
CesiumGS:mainfrom
gaopengbin:feat/gateway-server

Conversation

@gaopengbin
Copy link
Copy Markdown
Contributor

Unified MCP Gateway (@cesium-mcp/gateway)

This PR introduces @cesium-mcp/gateway, a new server that aggregates the tools from all existing domain servers (camera, entity, animation, imagery, tiles, terrain) behind a single MCP endpoint, and exposes meta-tools for runtime domain discovery and enable/disable.

Motivated by #35 — when many domain servers are connected at once, the active tool surface balloons and starts competing with the assistant's context budget. The gateway lets users start only the tools they need for the current task and flip others on as the conversation evolves, without restarting.

Design

  • DomainRegistry monkey-patches mcpServer.registerTool during each domain's registerTools() call (wrapped in try/finally so a throwing domain registration cannot permanently pollute the MCP server). The wrapper captures the returned RegisteredTool and stores it in a per-domain map.
  • Three meta-tools are exposed:
    • gateway_list_domains — lists every domain with [ON] / [OFF] status and tool counts
    • gateway_enable_domain — calls RegisteredTool.enable() on every tool in a domain
    • gateway_disable_domain — calls RegisteredTool.disable() on every tool in a domain
    • The MCP SDK's enable/disable emits listChanged automatically, so the assistant's visible tool surface updates live.
  • GATEWAY_DOMAINS environment variable controls which domains are enabled at boot (comma-separated, case-insensitive, whitespace-tolerant; unknown names log a warning; empty/unset means enable all).

Sub-path exports

To let the gateway import each domain's tool-registration function without reaching into build/, every existing domain server now also declares a "./tools" subpath export that points at its tools/index.ts barrel. These barrels were already the de facto organisation — this PR only makes them part of the package API.

Port

3010 (next free slot after 3007 for terrain; leaves room for future domain servers).

Tests

  • test/domain-registry.test.ts (12) — monkey-patch capture, try/finally restore, cross-domain isolation, enable/disable idempotency, unknown-domain handling, snapshots
  • test/domains.test.ts (14) — getEnabledDomains across undefined / empty / whitespace / case / trimming / unknown-warning / order-preservation
  • test/tools/discovery.test.ts (7) — discovery tools registration, list formatting, enable/disable happy path, isError on unknown domain

Full monorepo suite: 1462 / 1462 passing including the 33 new tests.

Checklist

  • pnpm run build clean
  • pnpm test (all packages) — 1462 / 1462
  • ESLint clean on new code
  • Prettier clean on new code
  • README updated — gateway row in packages table, new tool table, GATEWAY_DOMAINS note, structure tree, build/dev scripts, MCP client config block
  • .env.example shipped
  • Unit tests shipped

Refs #35

Introduces @cesium-mcp/gateway, a new server that aggregates tools from all existing domain servers (camera, entity, animation, imagery, tiles, terrain) behind a single MCP endpoint. Inspired by the 'unified gateway' pattern requested in issue CesiumGS#35 to keep the active tool surface small when many servers would otherwise be connected at once.

Design:

- Monkey-patches mcpServer.registerTool during each domain's registration (wrapped in try/finally) to capture the returned RegisteredTool and store it in a per-domain registry.

- Exposes three meta-tools: gateway_list_domains, gateway_enable_domain, gateway_disable_domain. These call RegisteredTool.enable()/disable() so the set of advertised tools changes at runtime without server restart.

- GATEWAY_DOMAINS environment variable controls which domains are enabled at boot (comma-separated, case-insensitive, whitespace-tolerant; unknown names log a warning).

Each domain server now also exports its tool-registration function via a './tools' subpath so the gateway can import it without reaching into build/.

Tests: 33 new unit tests across domain-registry, domains, and discovery-tools. Full monorepo suite: 1462/1462 passing.

Refs CesiumGS#35
Comment thread mcp/cesium-js/README.md Outdated
Comment thread mcp/cesium-js/README.md Outdated
Comment thread mcp/cesium-js/servers/gateway/vitest.config.ts
Comment thread mcp/cesium-js/servers/gateway/src/domain-registry.ts Outdated
- README: fix tool name (cesium_*) and env var name (CESIUM_DOMAINS)
- vitest: alias workspace tools packages to TS source for unbuilt test runs
- domain-registry: extract setDomainEnabled helper to dedupe enable/disable
@gaopengbin
Copy link
Copy Markdown
Contributor Author

Thanks @MKartaviciute for the detailed review! All 4 points addressed in 7e68e7b:

  1. Tool name mismatch in README — fixed to cesium_list_domains / cesium_enable_domain / cesium_disable_domain to match the actual tool names registered by the server.
  2. Env var mismatch in README — fixed GATEWAY_DOMAINS to CESIUM_DOMAINS to match src/index.ts.
  3. vitest aliases for workspace tools packages — added 6 aliases (camera/entity/animation/imagery/tiles/terrain -server/tools → respective src/tools/index.ts), so tests run against TS source without a prior build.
  4. Dedupe enable/disableDomain — extracted private setDomainEnabled(name, enabled) helper; both methods now delegate to it.

All 33 tests still pass locally (pnpm --filter @cesium-mcp/gateway test).

@MKartaviciute MKartaviciute merged commit 2606b49 into CesiumGS:main May 4, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants