MCP Gateway with Curated GraphQL Persisted Operations

Ahmet Soormally
MCP is great for connecting APIs to LLMs, but dumping raw REST endpoints into it makes models inefficient, insecure, and hard to control. A better approach is to create a GraphQL facade and lock it down with Persisted Operations (POs)—curated, versioned queries and mutations that give LLMs predictable, safe tools to work with.
The Model Context Protocol (MCP) is quickly becoming the standard for connecting APIs to Large Language Models (LLMs). On the surface, it sounds easy: plug your REST API into MCP and let the model figure it out.
But LLMs don't handle raw REST APIs well. They get lost in sprawling endpoints, waste context with irrelevant data, and struggle to stitch multiple microservices into a coherent answer. Asking a model to orchestrate all that is impractical.
What you really need is a facade: a backend-for-frontend (BFF) that exposes safe, task-level operations designed for MCP tools. The simplest way to build that facade is with curated GraphQL Persisted Operations (also called persisted queries or trusted documents).
REST APIs are great for developers and internal services, but not for LLMs.
Too granular: Microservices expose details, not tasks. An LLM shouldn't have to chain /invoices
, /usage
, and /tickets
just to answer "What's this customer's renewal risk?".
Context pollution: REST often over-fetches, filling the model's memory with irrelevant fields and increasing hallucinations.
Poor discoverability: No unified schema makes it hard for models to know how endpoints relate.
Security risks: Exposing many raw endpoints expands the attack surface.
REST-to-MCP tools can work for demos and proof of concepts, but in production it pushes complexity onto the model instead of abstracting it away.
LLMs don't care about your microservice layout. They think in terms of tasks:
- What's this customer's renewal risk?
- Generate an invoice preview.
- Summarize account health.
To support these, your API must:
- Aggregate across services.
- Hide implementation details.
- Return exactly the data needed.
- Enforce security at the operation level.
You could build this in REST, but most REST APIs weren't designed with LLMs in mind. For MCP, you need a curated, task-oriented layer.
GraphQL already solves many of these problems:
- Combines microservices into one typed schema.
- Allows fetching exactly the needed fields.
- Provides a machine-readable, LLM-friendly contract.
If your API surface spans multiple services, a federated GraphQL supergraph gives you one schema to manage, even as individual services evolve. Cosmo Connect gives you that, turning separate schemas into a single graph so your Persisted Operations keep working even as services change.
This blog post is a good starting point to learn how Connect handles federation and keeps one graph stable as services change.
But leaving GraphQL fully open isn't safe. An LLM could invent queries (only desirable for discovery and in development), over-fetch, or access sensitive data. That's where Persisted Operations come in.
Persisted Operations lock down GraphQL by allowing only predefined queries and mutations. This makes them secure, cacheable, auditable, and it improves GraphQL security by reducing the attack surface and keeping behavior predictable.
When you curate those operations for MCP, you get:
- Task-level granularity: Instead of plumbing endpoints, you expose operations like
getRenewalRisk
orsummarizeAccountHealth
alongside appropriate descriptions. - Tight context control: Each operation returns only the essential fields.
- Security by design: Inputs and outputs are controlled, with policy checks at the boundary.
- Governance: Operations can be versioned, observed, and safely deprecated.
In short, REST exposes data. Curated Persisted Operations expose outcomes.
Instead of giving an LLM the raw ingredients and hoping it cooks the right dish, POs serve it a prepared plate: AccountHealthSummary
.
This keeps tool usage stable over time. Even as LLMs evolve, your operation contracts remain constant. The model doesn't need to "rediscover" how to orchestrate services - it just calls the curated operation. That same predictability is critical for query planning in GraphQL federation, where even small schema changes can ripple into downstream behavior.
MCP tools map naturally to POs:
- Each tool corresponds to one or a few curated operations.
- Tools expose tasks, not microservice plumbing.
- Models don't guess orchestration - they just call the right tool.
This gives you:
- Bounded contracts: Models can’t deviate.
- Predictable behavior: Stable across model updates.
- Observability & control: Useful for SRE, security, and product teams.
Exposing raw REST APIs to MCP is like giving an LLM a box of spare parts and asking it to build a machine. Sometimes it works, but often it breaks.
Exposing Curated GraphQL Persisted Operations is like giving it a safe, labeled control panel: every switch does exactly what it should, every output is clean, and the complexity stays hidden.
That's why POs aren’t just a nice abstraction - I think that they are particularly useful and amongst the most efficient and effective ways to connect your APIs to LLMs through MCP.
Define your first Persisted Operation .
For full use with MCP, see the MCP Gateway Documentation
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.