{"slug": "from-use-case-to-graphql-operation-a-layered-approach-for-agents", "title": "From Use Case to GraphQL Operation: A Layered Approach for Agents", "summary": "A layered approach for AI agents to build GraphQL operations should start with the cheapest option — a small set of local operations stored as persisted query IDs with descriptions and variable definitions — and escalate to more expensive, dynamic generation only when a use case does not fit, according to a blog post on agentic GraphQL. The post cites Anthropic's engineering writeup reporting that a five-server MCP setup loaded 58 tools taking around 55K tokens before a conversation started, with tool definitions reaching 134K tokens before optimization, and notes Anthropic identified wrong tool selection and incorrect parameters as the most common failures, especially when tools have similar names. The author argues a GraphQL schema is a typed, discoverable API surface where one operation can replace several tool calls, but warns local operations can go stale, drift from their descriptions, cover only anticipated use cases, and recreate the long-list context problem as they multiply.", "body_md": "If you've plugged a few MCP servers into an agent lately, you might have noticed that tools are not exactly free. Tool definitions\noften get loaded into context, and that can add up quickly. Anthropic [shared](https://www.anthropic.com/engineering/advanced-tool-use) an example of a five-server setup where\n58 tools took around **55K tokens** before the conversation even started, and mentioned seeing tool definitions reach 134K tokens before optimization. Yikes.\n\nTokens are one thing, but it also seems like agents can get worse at picking the right tool as the list grows. The same post mentions wrong tool selection and incorrect\nparameters as the most common failures they see, especially when tools have similar names. [Some research](https://arxiv.org/abs/2505.03275) seems to point the same way:\nin their experiments, giving a model fewer, more relevant tools helped it pick the right one a lot more often.\n\nSome of the proposed fixes seem to be heading a particular way: let agents discover capabilities on demand, and let them\n[write code against a typed API](https://www.anthropic.com/engineering/code-execution-with-mcp) instead of picking from a giant list of tools.\nI don't know about you, but that sounds a lot like something we already have 👀. A GraphQL schema is a typed, discoverable API surface, and a single\noperation can do the work of a handful of tool calls.\n\nThat doesn't make GraphQL free for agents either (good luck fitting a large schema in context), and as I mentioned in my\n[last post](https://magiroux.com/posts/is-graphql-the-panacea-for-agentic-ai), it's not a panacea. But I do think it's a pretty great foundation **if** we're deliberate about\nhow agents build their operations. In this post, I want to go over the different ways agents can do that, from the cheapest to the most dynamic.\n\n## From Use Case to Operation\n\nApproaches for agents to build GraphQL operations, from cheapest and least dynamic to most expensive and most dynamic: skills / local operations, persisted operations search / modification, operation build against schema, schema modification workflow, ad-hoc optimized endpoint end-to-end generation\n\nWhat I'm proposing is some sort of layered approach to go from use case (what the agent wants to do / retrieve) to operation (a valid GraphQL operation against a schema). Similar to how we approach most things with LLMs, it tries the cheapest and fastest approaches first when the use case fits, only turning to more expensive or slower approaches when the use case is more dynamic in nature or requires \"creativity\" for the API call itself. We'll cover each approach in order.\n\n## Skills / Local Operations\n\nAside from actual scripts running GraphQL (let's call those the base of our layered approach), a relatively small set of local operations is most likely the cheapest and fastest way to retrieve GraphQL operations for an agent. A good description of the operation, along with its variable definitions and persisted query ID (rather than inlining large documents), seems like a great, compact way to represent use cases.\n\nI see this approach as being primarily useful for simpler, repeatable workflows. However, it runs into limitations similar to those of other local memories and skills:\n\n- They can be annoying to distribute/share with teammates.\n- They can get out of date. Either the schema changes underneath them (deprecations, removed fields), or worse, the description drifts away from what the operation actually does. The agent trusts the description.\n- They only cover the use cases someone thought of ahead of time. When nothing quite fits, the agent needs to realize it and move up a level, rather than force-fitting an operation that *almost* does the job.\n\nAnd of course, the more of them we have, the more we're back to the problem from the intro: a long list of similar-looking options for the agent to pick from, eating up context. That's a good hint it's time to look at the next level.\n\n## Persisted Operation Index\n\nOnce we hit too many of these problems, there's an additional layer I seldom see used before having an LLM generate an operation against the schema: we can have it look for existing work rather than spend too much time building from scratch.\n\nMany of us already leverage persisted operations in production. In fact, you may already have a large corpus of examples ready to be searched and used. A few things can make this work even better:\n\n- We need to capture more metadata on persist. Let's not forget that GraphQL operations can [have descriptions too](https://spec.graphql.org/September2025/) !\n\n```\n\"\"\"\nFetches the active user profile along with their most recent posts\n\"\"\"\nquery GetUserProfile($id: ID!) {\n  user(id: $id) {\n    id\n    name\n    posts(first: 5) {\n      title\n    }\n  }\n}\n```\n\n- We need to store / index them a bit differently, so we can fetch the top k operations matching our use case (hybrid BM25 / embeddings?).\n\n### Partial Matches\n\nPersisted queries still lock the agent into a particular query shape. This can be problematic in two ways:\n\n- The query almost matches the use case but is **underfetching** .\n- The query matches the use case but is **overfetching** .\n\nThe overfetching case is the easier one. An LLM can prune a query without needing complex tool calls. The underfetching case is harder and starts resembling what would be required to build an operation from the schema. Still, I'd be willing to bet we can do slightly better than generating an operation from scratch. The reason is that we start from valid paths, which in theory allows us to find the schema paths or members we're interested in with fewer tool calls / less compute.\n\n### The Gift that Keeps on Giving\n\nThere's something else quite powerful about this approach, which I covered in my last post too. This index is an ever-growing corpus of use cases. Operations generated from other layers can end up here, and the persist step serves as a great checkpoint for automated review, linting, human oversight, or even training some sort of model / refining the index.\n\n## Agentic GraphQL Operation Building\n\nThis layer is the one we generally think of when trying to solve this problem today (at least for cases where the schema is too large to fit into context windows, which is what I'm assuming throughout this post). We give the LLM the necessary tools so it can find what it needs and build a valid operation. There is a ton to be said about this layer, but let's try to cover the main points.\n\nAssuming we can't load the schema into context, we need to find the relevant parts of the schema first, and then ask the agent to construct an operation against it. The fact that we can validate queries against the schema (including any custom lints / hints) is of great use to the agent.\n\nThere are various strategies for finding the relevant schema members, like walking the schema from the root types, finding relevant types/fields and backtracking, splitting the schema into various sub-domains, etc. It might\nbe best to think of how you'd attempt to construct a query given enough time. Overall, to make a good set of tools for operation construction, I think we need to take care of a few key points. They end up sounding similar\nto the tools **you** would use to build an operation:\n\n- Translating the use case into a schema search\n- Searching for (and ranking) candidate schema members (usually types and fields)\n- Finding paths from the root types to those candidates\n- Transmitting paths and candidates to the agent in a token-efficient way (GraphQL SDL is pretty verbose)\n- Providing ways for the agent to augment and/or combine paths (tool calls to get type info or merge trees)\n- Constructing and validating the final operation (looping if necessary)\n\nI find a workflow of this kind avoids many pitfalls seen in other approaches. For example, an approach walking from roots could fail to find relevant paths early on, needing to explore a lot of the schema (more tool calls, more tokens). Transmitting paths also avoids sending large parts of the schema that happen to come along with our \"matches\".\n\nWhile writing this post and reviewing the offerings out there, I realized [Apollo seems to use a very similar approach](https://www.apollographql.com/blog/apollo-mcp-server/smart-schema-discovery-how-apollo-mcp-server-maximizes-ai-context-efficiency). Their approach pretty much\ncovers all our goals. They also share some nice heuristics for the search and ranking step (types/fields closer to the roots score higher!). Highly recommended read if you are building something like this yourself.\n\nThere are various other heuristics I can think of that could greatly improve query generation, like:\n\n- Using schema-usage statistics as a way to score how commonly used types/fields are\n- Using performance data\n- Indexing documentation and examples, not only the schema itself\n\nOverall, this is the most complex but also the most powerful layer. Of course, this one can feed into other layers. After constructing an operation, agents can persist it along with metadata, making similar use cases faster and cheaper the next time.\n\n## LLM-Driven Schema Evolution\n\nWhen an LLM can't find what it needs from an existing schema, we potentially get a great piece of feedback. This can be used to drive schema evolution. Of course, the devil's in the details. How do we avoid getting spammed with low-quality schema changes? Who actually implements, reviews, and deploys the changes? Something like a Schema Update Proposal workflow (many platforms have adopted this idea) would be a great place to do so.\n\n## Moving Up a Layer\n\nPutting all of these layers together, we end up with something like this:\n\nDecision flow for fulfilling an agent's data need: if a local script, operation or skill exists, use skills / local operations; otherwise, if a persisted operation fits or nearly fits, use persisted operations search / modification; otherwise, if the current schema can serve it efficiently, build an operation against the schema; if not, go through the schema modification workflow\n\nIt looks simple on paper, but that decision tree is one of the hard parts. For example, how does the LLM decide the schema search didn't give results that are good enough? How does it decide whether existing operations are \"too far\" from a good operation? Each layer probably needs some kind of fit evaluation before the agent commits to it. It could compare what the use case needs with what the operation actually selects, or ask a cheap model for a yes or no. Also, misses could get expensive. We'd need to be careful that our initial layers actually get good \"cache hits\".\n\n## Conclusion\n\nOf course, as I mentioned in my last post, there's always the possibility that agents don't even need a schema and can just write their own, highly optimized client and server ad-hoc API implementations. I don't think we're quite there yet, but it's a possibility. Until then, I think a layered approach makes a ton of sense from an accuracy, performance, and cost perspective.\n\nWe've only scratched the surface of each of these \"layers\". I'm currently playing around with implementing something like this myself, and I'd love to actually benchmark the different layers against each other (tokens, latency, tool calls, and of course, whether the agent got it right). I'm curious to see if the numbers back up my intuition here, or if I'm completely wrong 😅. Expect a follow-up post on that!\n\nThanks for reading!", "url": "https://wpnews.pro/news/from-use-case-to-graphql-operation-a-layered-approach-for-agents", "canonical_source": "https://magiroux.com/posts/from-use-case-to-graphql-operation", "published_at": "2026-10-20 18:35:29+00:00", "updated_at": "2026-10-20 18:46:58.258573+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "large-language-models"], "entities": ["Anthropic", "GraphQL", "MCP", "Claude"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/from-use-case-to-graphql-operation-a-layered-approach-for-agents", "markdown": "https://wpnews.pro/news/from-use-case-to-graphql-operation-a-layered-approach-for-agents.md", "text": "https://wpnews.pro/news/from-use-case-to-graphql-operation-a-layered-approach-for-agents.txt", "jsonld": "https://wpnews.pro/news/from-use-case-to-graphql-operation-a-layered-approach-for-agents.jsonld"}}