EXPERIMENT_043 // MCP.TOOL.GATEWAY

MCP Tool Gateway

This experiment gates every MCP tool call behind a policy engine that checks agent, server, and tool identity before proxying to a real in-repo demo server, denying by default whenever the ruleset is corrupted or a real fleet server has no live credentials in this public deployment.

🖱MOUSE OR TOUCH INPUTCREATED 2026.09.14BETA

LOADING EXPERIMENT...

A single gateway stands between a dozen of Diana's fleet agents and the MCP tool servers configured on her own machine — Slack, Perplexity, Railway, Stitch, Remotion documentation, Open Brain, and a local-inference lane — plus one real, in-repo demo server this deployment can actually call. The dashboard renders a live agent-by-tool permission matrix computed from a JSON policy ruleset: green ALLOW chips and red DENY chips, clickable to fire the real call. Every real fleet server renders for grounding but returns a structured `SERVER_UNAVAILABLE` error rather than a live call this public page holds no credentials for; corrupting the policy ruleset denies every call, including ones the matrix still shows as allowed.

HOW IT WORKS

The Server Registry

registry.ts is a sanitised snapshot of Diana's own fleet MCP configuration — the seven servers actually declared in `~/.claude/.mcp.json` and `~/.claude.json` (Slack, Perplexity, Railway, Stitch, Remotion documentation, Open Brain, and a local-inference lane), with every credential stripped before the entry is ever written. Six of the seven are marked `reference-only`: real identities, grounding the dashboard in the fleet's actual tool surface, but never called live from this public deployment. The seventh, `labs-demo`, is the only `demo-live` entry — a real MCP-shaped server this experiment built and actually proxies calls to.

The Policy Engine

policyEngine.ts loads a JSON ruleset of (agent, server, tool) rules and evaluates every call against it. Deny is the only reachable outcome when the ruleset fails its Zod schema check, throws unexpectedly, or is deliberately corrupted through the dashboard's demo toggle — there is no code path back to allow once the ruleset is unreadable. Rules not explicitly listed also deny by default: an agent gets no access to a tool the ruleset never mentions, not implicit trust.

The Proxy

gateway.ts is the sole entry point: it checks policy, resolves the target server in the registry, and — only for `labs-demo` — proxies the call to a real in-repo MCP server exposing three genuine tools (`get_server_time`, `get_repo_stats` reading this repo's own bundled `experiments.json`, and `echo`). Every other registered server returns a structured `SERVER_UNAVAILABLE` error instead of a live call, logged and never silently dropped — the honest boundary for a public page holding no per-server credentials.

The Permission Dashboard

GET /matrix recomputes the full agent-by-tool grid from the live registry and ruleset on every request — no caching, so a policy edit is visible on the next page load. The dashboard renders it as clickable ALLOW/DENY chips per server; clicking one fires the real POST /call round trip and shows the structured response, success or rejection, exactly as the gateway returned it.

WHAT THIS PROVES

MCP crossed 97 million monthly downloads before moving under Linux Foundation governance, and a single organisation running a dozen agents against seven or more MCP servers needs the same thing a public API gateway has always needed: one place where every call is authorised before it's proxied, not a dozen separate trust decisions scattered across each agent's own config. This experiment builds that choke point end to end against Diana's actual fleet server list, not an invented one, while being explicit about which calls it can and cannot make live.

Deny-by-default is a structural property here, not a convention someone has to remember to apply: `evaluate()` has no branch that returns `allow` when the ruleset failed to load, and the dashboard's corrupted-ruleset toggle proves it live — the same cell that read ALLOW a second ago denies the very next call once the ruleset the gateway reads from is (simulated) unreadable, without touching the matrix that's already rendered on screen.

← BACK TO PLAYGROUND

SYSTEM.INT // 2026 LABS_CORE v2.117.0

LATENCY: STATUS: NOMINAL