Skip to main content

GraphQL Finally Found Its Client, and It Isn't Human

· 10 min read
Tian Pan
Software Engineer

GraphQL's core bet was that clients should compose their own data requirements. For a decade, that bet mostly lost — because the clients were human teams who didn't want to compose anything. Frontend engineers wanted a stable endpoint they could call and forget. The flexibility GraphQL sold was a tax they paid in resolver complexity, caching workarounds, and security review, in exchange for a benefit — per-request field selection — that a known, slow-changing web app barely needed. By 2024, the practitioner consensus had visibly cooled: most internal APIs serve two or three known clients, and a well-shaped REST endpoint or a BFF layer covers them fine.

Then a new kind of client showed up. An AI agent doesn't have a fixed set of screens. It decides, per task, what data it needs, and it pays for every byte of the response — literally, in tokens, and cognitively, in degraded reasoning as the context window fills with fields nobody asked for. The client that actually composes its own data requirements finally exists. It just isn't human.

The uncomfortable twist: the same properties that make GraphQL a natural fit for agents also make its historic weaknesses worse. Unbounded resolver cost, single-endpoint authorization, queries you can't allowlist — every reason GraphQL lost the human-client war compounds when the client is a token-sampling process that can emit a pathological query with total confidence. The answer isn't "point the agent at your graph." It's a narrower pattern: let the agent compose queries, then review and pin them like code.

REST tools force agents into two bad shapes

Watch an agent work against a typical REST-backed tool set and you'll see one of two failure modes, often both.

The first is the chatty N+1 loop. The agent calls get_orders, gets back a list of order IDs, then calls get_order_details ten times, then get_customer for each order's customer. Every round trip is a full inference cycle: the model reads the tool result, reasons about it, emits the next call. What a GraphQL client would do in one request, the agent does in twenty — and each hop adds latency, cost, and a fresh opportunity to lose the thread.

The second is the kitchen-sink response. To avoid the loop, someone builds a get_order_with_everything endpoint that returns the order, its line items, the customer, the shipping history, and forty other fields. Now every call dumps kilobytes of JSON into the context window regardless of what the task needed. The agent wanted a delivery date; it got a novella. Practitioners consolidating REST tool sets behind a GraphQL layer report token reductions in the 70–80% range, which matches intuition: most of a fixed-shape response is irrelevant to any given question.

Both failure modes are the over-fetching/under-fetching problem GraphQL was designed to solve in 2015. The difference is the stakes. When a web app over-fetches, you waste bandwidth. When an agent over-fetches, you pollute the very working memory it reasons with. Irrelevant fields aren't just dead weight — they're distractors that measurably degrade the model's ability to pick out what matters. Token cost is the visible tax; reasoning degradation is the hidden one.

There's a third, subtler cost: tool-definition sprawl. Every REST endpoint you expose becomes a tool schema the model must hold in context before it does anything. Teams hit a Goldilocks problem — too few tools and the agent can't do its job; too many and you've burned thousands of tokens on definitions alone. A typed graph collapses this: one schema describes the whole surface, and the model requests exactly the slice it needs in one round trip.

Everything that killed GraphQL for humans gets worse for agents

If the story ended there, the advice would be simple: expose an execute_graphql tool, hand the model your schema, done. Several MCP servers do exactly this. It works in demos and is a liability in production, because every unsolved problem from GraphQL's first decade returns with the volume turned up.

Unbounded resolver cost. A nested query that fans out across resolvers can generate thousands of database hits from a few lines of text. Security audits have repeatedly found that a large majority of deployed GraphQL APIs are vulnerable to some form of complexity-based denial of service. Human clients trigger this occasionally, by accident or malice. An agent composing queries at runtime explores the schema the way a fuzzer does — not because it's adversarial, but because it doesn't know your database topology and has no instinct for what's expensive. It will happily nest orders { customer { orders { customer } } } because the schema says it can.

Authorization at every node. REST lets you authorize at the endpoint: this route needs this role, done. GraphQL's single endpoint pushes authorization down to the field level, and field-level authorization is the most commonly botched part of real deployments — one forgotten resolver check and a traversal path exposes data the client should never see. With human clients, the set of queries in the wild is effectively finite; the paths through your graph get exercised and audited. An agent generates novel traversals on demand. Every unaudited path through your graph is now reachable on the first day.

Queries you can't allowlist. The mature answer to both problems has always been persisted queries: pin the exact operations clients may run, reject everything else. But that discipline existed in tension with GraphQL's pitch — if clients can only run pre-approved queries, why bother with a query language? For human teams, the honest answer was often "don't bother," which is how a lot of GraphQL installations quietly became REST with extra steps. For agents, the tension is sharper: the whole point was runtime composition, and the allowlist forbids exactly that.

So the naive architecture — schema in, arbitrary queries out — hands a fuzzer the keys to your most expensive and least-audited API surface. The teams that shipped this are the ones now writing incident reviews.

Persisted queries as tools: compose at dev time, pin at deploy time

Loading…
References:Let's stay in touch and Follow me for more thoughts and updates