Safelist GraphQL Operations for AI Agents | Cosmo MCP Gateway

cover
Ahmet Soormally

Ahmet Soormally

Principal Solutions Engineer at WunderGraph

min read

The Cosmo Router MCP Gateway exposes your federated GraphQL schema to AI agents as reviewed, OAuth-scoped MCP tools. This is the implementation companion to Don't Let AI Agents Improvise Against Production GraphQL, which makes the case for the pattern: let agents discover in development, but only let them execute reviewed operations in production. Here we build it on the Cosmo Router MCP Gateway, end to end: the two postures, how operations become tools, OAuth scopes, and what happens when your schema changes.

One MCP server, two postures

The MCP Gateway is a feature of the Cosmo Router. It speaks the 2025-06-18 MCP specification over Streamable HTTP, and AI platforms like Claude, Cursor, and Windsurf connect to it directly. It operates on your composed supergraph, so a single tool call can resolve data across every subgraph in your federation. There is no separate service to deploy.

Two configuration flags define its posture:

  • expose_schema controls whether agents can read your full schema.
  • enable_arbitrary_operations controls whether agents can compose and run GraphQL you never reviewed.

Open both in development. Close both in production. The operations you safelist in between are the contract that survives the transition.

How it works

The gateway reads .graphql operation files from a storage provider directory, validates each one against your composed schema, generates a JSON Schema for its variables, and exposes it as a discrete MCP tool. It runs inside the router and executes operations against the same composed supergraph and federation engine that serves your GraphQL traffic, so there is no separate sidecar or translation service to deploy and keep in sync. Because operations are validated at load time and re-validated on hot reload, a malformed or stale operation is caught before an agent can ever call it.

The tools an agent sees depend entirely on your configuration:

ToolWhen it existsWhat it does
execute_operation_<name>One per safelisted .graphql fileRuns a single pre-approved operation. Inputs are typed from the operation's variables.
get_operation_infoAlwaysReturns an operation's input schema and execution guidance so the agent calls it correctly.
get_schemaOnly when expose_schema: trueReturns the full GraphQL schema as a string for the agent to introspect.
execute_graphqlOnly when enable_arbitrary_operations: trueExecutes any query or mutation the agent composes. Marked as a destructive, open-world tool.

get_schema and execute_graphql are the only two tools that open the graph beyond your safelist, and both are off by default. A production gateway with both disabled exposes nothing but the operations you placed in the directory.

Development: design against the live schema

In development you want maximum leverage. Turn both flags on:

1
2
3
4

Now an agent connected through Cursor or Claude can call get_schema, understand your federated types, and use execute_graphql to draft, run, and refine queries against real data. You and the agent converge on the handful of operations that actually matter, and you save each one as a .graphql file.

The promotion boundary: operations become software artifacts

A discovered query becomes a reviewed artifact when you save it as a named operation, with a triple-quoted block-string description that becomes the tool description the agent reads:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

That file is now a persisted operation, a trusted document, and it goes through the same review as any other code: right fields, no unintended PII, the correct authorization scopes, safe for repeated execution, and query-only versus mutation-capable. The exploratory phase produces a tangible, reviewable artifact: a directory of operations. That directory is the contract.

Production: collapse to the safelist

Close both flags and point the gateway at your reviewed operations:

1
2
3
4
5
6

In this posture the agent can only call execute_operation_* tools, one per file you approved. It cannot read the full schema. It cannot compose a query. Every tool maps to an operation a human reviewed, and GraphQL's type system guarantees the agent can only pass inputs your operation declares. This collapses the attack surface from "the whole schema" to the queries you ship, and production rejects anything not on the allowlist.

The safelist is not a proprietary artifact. It is nothing but standard GraphQL operations. Move off this router tomorrow and those .graphql files are still valid GraphQL against your schema. You are encoding your AI-facing surface in the same language as your API, not in a format you can only read with one vendor's tooling.

OAuth: per-operation authorization

Layer OAuth 2.1 on top and the control becomes per-operation. The gateway enforces JWT-based authorization on the MCP methods tools/list and tools/call, and applies per-tool scope requirements for the built-in tools such as get_schema and execute_graphql. It honors @requiresScopes directives so that each tool inherits the exact scopes its underlying GraphQL fields require. An agent does not just see fewer tools; it is authorized for exactly the ones its credentials permit. And because every agent presents its own JWT, each call carries an agent identity you can attribute in logs and traces, so machine-to-machine access stays investigable when an incident demands it.

Loading diagram...

For operations that need a stronger bar at call time, the gateway supports OAuth 2.1 scope step-up flows.

There is also a recognized safe middle ground. Keep expose_schema: true in production while leaving enable_arbitrary_operations: false. Introspection stays on, so agents can reason about your API surface, but execution is still restricted to the operations you safelisted. This is safe precisely because only registered operations ever run: schema visibility grants no execution capability.

Schema evolution does not become operation maintenance

The objection every platform team raises next is maintenance: if the schema changes, do I have to rewrite all my operations? No, not for additive changes, and that is the reason the model holds up over time.

Adding fields, types, or arguments to your schema does not break or require updating your safelisted operations. The Cosmo Router re-validates every operation against the new schema on each hot reload. Operations that still validate are re-registered automatically. Your safelisted queries keep working untouched; they simply do not use the new capabilities.

The maintenance contract is narrow and predictable:

  • Additive schema changes are free. New fields, new types, new arguments. Existing operations are unaffected.
  • New capabilities are exposed only on purpose. A new field becomes reachable by an agent only when you add or extend an operation that selects it. Nothing is auto-exposed. This is least-privilege as a default, not as a discipline you have to remember.
  • You touch an operation only when a change breaks it. If a field an operation selects is removed or changes type incompatibly, the router logs the error and skips that one operation. The rest keep serving. You update the file to match and it re-registers on the next reload.

The hot-reload path means none of this requires a redeploy: push a new schema, the gateway re-validates and re-registers, and your scope requirements are recomputed from the current @requiresScopes directives automatically. This is governance as a guardrail rather than a review queue. The rule that new capabilities are exposed only on purpose cannot be quietly skipped by any team, so schema owners stop being the manual approval gate everyone routes around.

Why not build a separate AI-safe API?

The reflex when you hit this problem is to build a second, "AI-safe" API: a curated REST surface that exposes only the approved slice of data. It works, and it is a trap. You now own two sources of truth that drift, and the curated one ages into exactly the legacy layer you will be migrating off in three years.

The safelist gives you the same safety without the second system.

Parallel AI-safe APICosmo Router MCP Gateway
Source of truthA second API that drifts from the firstYour existing supergraph
Time to first safe operationA new build-and-review cycleDesign in dev, save a .graphql file
Governance granularityWhatever you hand-buildPer-operation, with OAuth scopes and @requiresScopes
Schema evolutionManual sync across two surfacesAutomatic re-validation on hot reload
Federation supportRe-implement aggregationNative; operations span subgraphs
PortabilityLogic locked in a bespoke serviceStandard .graphql persisted documents, valid against your schema anywhere
What the agent can reachWhatever the second API exposesExactly the safelisted operations, nothing more

You are not standing up infrastructure to make your API safe for AI. You are configuring a posture on infrastructure you already run.

Get started

Start with the MCP Gateway quickstart to have a server running in five minutes, then read the operations guide to design your first safelist. For the reasoning behind this whole setup, read the companion: Don't Let AI Agents Improvise Against Production GraphQL.

Ahmet Soormally
Ahmet Soormally

Principal Solutions Engineer at WunderGraph

Ahmet is a Principal Solutions Engineer at WunderGraph, helping teams adopt Cosmo. He leads technical evaluations, builds prototypes, and runs workshops to accelerate adoption, while improving SDKs, documentation, and onboarding to enhance the developer experience.