Back to Blog
AI & Automation8 min read

Designing MCP Tools That Don't Blow Up the Context Window

By Waseem Ahmad — Full Stack Developer & AI Engineer ·

TL;DR

  • Returning every row, every field, every tool schema upfront is the most common MCP design mistake, and it silently degrades model performance before any real work starts.
  • Cursor-based pagination should be the default for any tool that touches a collection, even if you think the result set will stay small.
  • Field projection — accepting a fields parameter and stripping unrequested keys server-side — is one of the highest-leverage optimizations available and is almost never implemented.
  • Tool scoping (only loading definitions relevant to the current task) addresses the often-overlooked schema-side of the token budget, not just the response side.
  • The MCP spec has cursor pagination for list operations; tool-level response pagination is still an open community discussion, so you must handle it yourself today.

Why does an MCP tool response kill the context window?

Context overflow in MCP agents comes from two directions at once, and most teams only notice one of them.

The first direction is tool definitions. As MCP host applications connect to more servers and accumulate access to hundreds or thousands of tools, naive approaches to tool management break down. Loading every tool definition into the model's context window upfront wastes tokens, increases latency, and degrades model performance. The numbers are not theoretical: with three servers and 30 tools per server, that is 90 tool definitions injected before the model reads a single character of the user's prompt. At 200 tokens per definition, you are paying for 18,000 tokens of overhead on every call.

The second direction is response payloads. A single tool call that returns a JSON blob with 50 fields — when you only needed 3 — can consume thousands of tokens in one shot. Multiply that across a multi-step workflow and you are burning context window before the agent has done anything useful. Compound the two problems and you arrive at the failure mode described in a public GitHub discussion on the MCP repo: context limit exceeded errors that may reset or break the active agent session, unnecessary token usage and increased credit consumption, and failure of chained tool executions in multi-step AI workflows.

These are not edge cases. Large tool and resource outputs overrunning the model's context window, degrading quality and causing truncation or hard errors, is the most common cause of context overflow — unbounded list operations. The fix is not one trick; it is three disciplines applied together: pagination, projection, and scoping.

Discipline 1: Pagination — never return an unbounded list

An MCP tool that returns 10,000 database rows in a single response will overwhelm any AI agent's context window. The tokens get consumed, the model loses focus, and the user gets a slow, expensive, unhelpful answer.

The Model Context Protocol specification states clearly: MCP supports paginating list operations that may return large result sets. Pagination allows servers to yield results in smaller chunks rather than all at once. The built-in mechanism uses cursor-based pagination: a nextCursor token in the response tells the client there are more results, and the client passes cursor on the next request to advance the page.

The catch is that MCP currently provides pagination only for list operations. However, many tools can return large datasets that risk overwhelming clients or models if delivered in a single response. The 2026 MCP Roadmap acknowledges the need for streamed and reference-based result types but places this in the "On the Horizon" category. Until tool pagination is standardized, cursor parameters, server caps, summary-detail splits, and ResourceLink cover the practical needs.

So today, you implement tool-level pagination yourself. The pattern is straightforward: accept cursor and limit parameters in your tool's input schema, enforce a hard cap server-side regardless of what the caller passes, and always return a nextCursor when results are truncated. Set your default limit conservatively — 20 to 50 rows is usually right for analytical tools; 100 for identifier-only lists. Never let the caller request unlimited rows, even if they ask nicely.

Axiom, whose MCP server handles petabyte-scale observability data with deeply nested JSON, took this further with a cell-budget approach. They set a global cell budget on the maximum number of cells returned per result set, prioritize totals and summary tables first as they give the model the most important context for reasoning, then distribute the remaining budget evenly across data tables, trimming rows where necessary. Every trimmed table includes a clear, actionable note such as "Showing 100 of 2,340 rows". That pattern — summarise first, detail second, always annotate truncation — is worth copying directly.

Discipline 2: Field projection — strip the response before it hits context

Pagination controls row count. Projection controls column count. Both matter.

The solution is field filtering at the MCP server layer. Before the response hits the context window, strip it down to the fields your agent workflow requires. This can be as simple as a projection function that whitelists specific keys. For a response that typically returns 50 fields, filtering to 3–5 relevant ones can reduce payload tokens by 80–90%.

The implementation pattern: accept a fields array in the tool's input schema, default to a small curated set of high-signal fields, and only expand to the full schema when the caller explicitly asks. Implement a field-projection layer at the MCP server that accepts a fields parameter and strips unrequested keys before serialization. This is genuinely not much code — a single recursive pick function applied before JSON.stringify — but almost no servers do it.

The anti-pattern to avoid is described clearly: move computation to the server, not the model. A common anti-pattern is the MCP server returning a large dataset, the agent processing it in context — sorting, filtering, aggregating — and then producing a result. You have paid for every token of that dataset. Expose aggregation-level tools alongside raw-fetch tools. A get_sales_summary_by_region tool will almost always serve the model better than get_all_sales_records filtered in context.

There is a limit to how aggressively you should compress. The tradeoff is accuracy. At high compression, a tool called create_jira_issue has no description — only parameter names remain. If another tool called create_confluence_page shares the same parameter names, the model has to guess which one creates a Jira task and which creates a Confluence wiki page. Strip responses, not schemas.

Discipline 3: Tool scoping — only load definitions the current task needs

Two patterns address the challenge of tool definition bloat: progressive discovery, which controls when tool definitions enter context, and programmatic tool calling, which controls how tools are invoked.

Okta quantified what identity-based tool scoping looks like in practice: Okta's proposed control filters the list of tools before it reaches the model, using permissions assigned to an agent identity and the user associated with it. Internal modelling found that some permission scenarios reduced the number of visible tools by more than 90%, with tool-schema costs falling by roughly the same proportion.

You do not need an identity platform to apply this principle. A simpler approach: tag each tool with one or more workflow categories in your server's tool metadata, then expose a lightweight discover_tools meta-tool that accepts a workflow parameter and returns only the relevant subset of definitions. The agent calls discover_tools(workflow="billing") first, gets 6 definitions instead of 60, and never burns tokens on tools it will never touch. How you design and present tools to an AI model matters. The recommendation is to give tools clear schemas, scope them to actual workflows instead of raw endpoints, and limit information in the context window.

How do the three disciplines compare?

Discipline What it controls When to apply Implementation cost Main failure mode
Cursor pagination Row count in responses Any tool that queries a collection Low — cursor encode/decode + limit enforcement Client does not follow nextCursor and stops at page 1
Field projection Column count in responses Any tool returning wide objects Low — server-side pick function Default field set is too aggressive; model misses needed context
Cell budgeting Total data volume per response Analytics / observability tools with variable result shapes Medium — requires priority logic for which tables to favour Trimming without annotation confuses the model about completeness
Tool scoping Schema tokens per turn Servers with more than ~15 tools Medium — tagging + discovery meta-tool Scoping too narrow; model requests a tool that is not in context
Aggregation tools Processing done in context vs. server Whenever the model is likely to filter or aggregate data High — requires domain knowledge of likely queries Aggregation granularity does not match what the model actually needs

What does this look like in practice?

The Biz365 AI project is a useful reference point here. It involved building an AI-driven reporting layer on top of business data — exactly the scenario where an MCP tool naively wired to a database table would return thousands of rows per call. The right shape for that kind of tool is: accept date range, dimension filters, and a fields projection parameter; return a paginated cursor response capped server-side; and expose a parallel summary tool that pre-aggregates the data the model will most likely want for reasoning. None of that is complicated; it just requires thinking about the token budget before writing the handler, not after the context starts overflowing.

For token cost considerations more broadly, the patterns here connect directly to what I covered in LLM Cost Optimization: Caching, Routing, and the Token Waste Hiding in Your Prompts — MCP response bloat is one of the largest sources of that waste in agentic systems, and it compounds with every tool call in a multi-step workflow.

If you are building MCP integrations from scratch or hardening an existing server, the MCP development work I do covers all three disciplines: schema design, response shaping, and client-side progressive discovery. Most engagements start around $5K; smaller well-scoped work is considered case-by-case.

A note on the current state of the spec

The 2026-07-28 Model Context Protocol release represents a significant leap forward in enterprise AI scalability, evolving into a stateless architecture that removes friction from deploying agentic workflows at scale. The stateless shift is welcome — it makes horizontal scaling straightforward — but it does not solve unbounded payloads. That remains a design problem at the tool level, not the protocol level. A proposal in active community discussion would allow the client to declare something like max_response_bytes in its capabilities, giving servers the opportunity to handle the payload size limit with strategies including pagination, summarization, or error responses. Until that lands in the spec, every MCP server author is on their own.


FAQ

Does cursor pagination work the same way for tool responses as it does for resource listing?

Not yet. The MCP specification defines cursor-based pagination for protocol-level list operations such as resources/list and tools/list. For the actual data your tool returns, pagination is not standardised; you implement it yourself via input parameters (cursor, limit) and output fields (nextCursor, hasMore). A spec enhancement proposal exists in the community to extend pagination to tool responses, but it had not merged as of this writing.

If I add a fields projection parameter, won't the model just request all fields anyway?

In practice, models are good at requesting a minimal field set when the tool description explains why projection exists and what the default set contains. The important design choice is to make the default set small and useful rather than exhaustive. If you default to returning every field and require the caller to opt into projection, it will never get used. Default narrow, allow expansion.

How many tools is too many to load into context at once?

Naive MCP host implementations pass the tool definitions of every connected server directly to the model at the start of each conversation. For a handful of tools, this is perfectly reasonable. Reasonable here means roughly 10 to 15. Beyond that, the schema tokens start competing meaningfully with the actual task context, and the model's tool-selection accuracy tends to drop. The threshold is lower for models with smaller context windows and higher for very large ones, but planning for progressive discovery above 15 tools is a safe default.

Should I return an error or a truncated response when a result set is too large?

Return a truncated response with a clear annotation, not an error. An error forces the agent to re-plan from scratch, which is expensive and often just repeats the same call. A truncated response with a note like "showing 50 of 4,200 results — use cursor to page" gives the model enough signal to decide whether the first page answers the question or whether it should paginate further. Errors should be reserved for genuinely invalid requests, not for size limits you chose to enforce.

mcpai agentstoken optimizationcontext windowtool design

Hire me for similar projects

Looking for a developer who can build what you just read about? Let's talk.

Get in Touch