Your AI agent isn’t broken. Your tool descriptions are.
When an MCP integration underperforms, the instinct is to go looking for a protocol bug. Teams almost never find one. AWS traced nearly every MCP tool failure back to two root causes, and neither of them lives in the transport [1]. The first is bloat: tool definitions load into the model’s context on every call, whether that tool gets used or not, so a handful of connected servers can eat the usable context window before the user has typed a question. The second is confusion: ambiguous names, semantically overlapping tools, and undocumented parameter vocabularies make the model pick the wrong tool or the wrong value, then retry.
The trap is that the obvious fix for one is fuel for the other. Richer descriptions cure confusion and cause bloat. Trimming definitions cures bloat and causes confusion. There is no single knob, which is why “we’ll just write better docstrings” stops working around the third connected server.

Figure 1 - Two failure modes, one dial: Bloat is paid on every call regardless of use. Confusion is paid in wrong choices and retries, which are themselves paid in bloat. The arrow between them is the reason tool design is a tradeoff exercise rather than a checklist of best practices applied independently.
Neither cost is proportional to use. A tool called once a week costs exactly what a tool called forty times an hour costs, on every single turn, and as context fills, the model’s ability to reason across it degrades, a mechanism we walked in detail in Your 1M-Token Context Window Is a Lie After 120K [2]. From there the loop closes on itself: bloat degrades reasoning, degraded reasoning produces wrong calls, wrong calls produce retries, and retries produce bloat [1]. AWS is explicit that this is a context engineering problem rather than a documentation problem. The question is what the model sees, and when it sees it [1].

Figure 2 - The loop that makes both problems one problem: Each failure mode manufactures the other. A tool catalog that is merely large is survivable. A tool catalog that is large and ambiguous degrades faster than either property predicts on its own, because the retries are drawn from the same budget the definitions already spent.
KEY INSIGHT: Any tool-design change that improves one failure mode without measuring the other is a guess. Enriching a description and watching accuracy improve tells you nothing until you also measure what the larger definition cost every call that never used that tool.
This article walks six things, in order: how the protocol ground shifted under everyone on 2026-07-28, why MCP exists at all once the deprecated parts are subtracted, the six tool designs AWS built against the same backend and published as a runnable teardown, the production token math from a second AWS case study, an independent evaluation in which the most accurate arm was the one with no tool catalog at all, and the identity gate that decides how wide any of it is allowed to reach. It closes on a checklist you can run against your own server this afternoon.
The ground moved on 2026-07-28
Before any of the design tiers make sense, the protocol they sit on needs a status check, because it changed materially in July and MCP advice written before that date describes a version that no longer exists.
On 2026-07-28 MCP shipped its largest revision since launch [3]. The headline is that protocol-level sessions are gone. SEP-2567 removes the session concept and the Mcp-Session-Id header, replacing implicit session-scoped state with explicit, server-minted state handles that the model carries and threads through subsequent calls [4]. Its companion, SEP-2575, removes the initialize handshake entirely and carries protocol version and capabilities per request instead [5]. Together they make a remote MCP server an ordinary stateless HTTPS endpoint: no sticky routing, no shared session store, no handshake to replay. SEP-2243 finishes the job for the infrastructure layer by mirroring method into an Mcp-Method header and params.name or params.uri into an Mcp-Name header, so load balancers and observability tools can route MCP traffic “without deep packet inspection” [6].
That is genuinely good news for anyone running a server, and it is also the one part of this revision that costs somebody a sprint. If a server kept application state in the session, that state now has nowhere to live, and two consecutive requests from the same client can land on different instances. A server that was correct under sessions can be quietly incorrect without them.
The useful thing about SEP-2567 is that it quantifies how many servers that actually describes. An automated classified survey of a random 1000-repo sample of open-source MCP servers found 90.0% with no application-level reference to the session ID at all, and only about 3.7% using it for application semantics: 2.5% for session-keyed application state, 0.7% for gateway sticky routing, and 0.5% for auth binding [4]. Most servers were already stateless and did not know it. A small minority have real work to do.
Be careful with the reassurance that circulated after the announcement. The 2026-07-28 revision is a breaking change and says so repeatedly. SEP-2575 calls itself “a fundamental, backward-incompatible change” requiring a new protocol version [5]. SEP-2567 says sessions are removed “with no deprecation window” and that this “is a breaking change for servers that rely on protocol-level session state” [4]. SEP-2322 says the same of its own replacement for server-initiated requests [7]. The “no existing implementations break” line is real, but it belongs to exactly one SEP and one scope, which is the next item.

Figure 3 - What actually changed: Removals (sessions, the initialize handshake, the old server-initiated request path) are breaking and immediate. Deprecations (Roots, Sampling, Logging) are advisory and long-dated. Additions (full JSON Schema 2020-12, cacheable list results, header-based routing) are the parts that change how you design tools rather than how you deploy them.
Three primitives deprecated, and why that is a reason to trust the protocol
SEP-2577 deprecates exactly three things: Roots (roots/list and notifications/roots/list_changed), Sampling (sampling/createMessage and the corresponding client capability), and Logging (logging/setLevel and notifications/message) [8]. It offers alternatives in its motivation rather than mandating replacements. Working directory context “can be provided through tool parameters, resource URIs, server configuration, or environment variables,” all of which SEP-2577 calls “more explicit” [8]. Servers needing LLM capability “can integrate directly with LLM provider APIs, giving them full control over model selection, parameters, and streaming” [8]. For logging, “stderr for stdio transports, OpenTelemetry for structured observability” [8].
Two clarifications matter here, because both get mangled in retellings. Sampling was a server-side capability: a mechanism for a server to ask the connected client to run a completion, so the server needed no model credentials of its own. Its deprecation has no bearing on how a person or a host application authenticates to a model, and none on subscriptions or billing. It also was not widely used. SEP-2577 cites “low adoption,” noting that the feature support matrix shows few clients supported sampling despite its availability since November 2024, with correct implementation requiring human-in-the-loop approval, model selection logic, security handling, and tool-loop support [8].
The maintainers’ own argument for the pruning is security, and it is the strongest framing available: “Deprecating these features has a net positive effect on security” [8]. Sampling “allows servers to request LLM completions through the client, which creates attack surface for prompt injection and data exfiltration” [8]. Roots “exposes information about the client’s filesystem to servers” [8]. That is a protocol deprecating three of its own primitives, in public, with a stated rationale. Protocols that can do that are the ones worth building on.
For the deprecations specifically, and only for them, SEP-2577 states that “wire-level behavior is unchanged. No types are removed, no capability negotiation changes, and no existing implementations break” [8]. That sentence is scoped to the deprecation period of those three features. It does not describe the revision.
Not a countdown
The removal policy lives in a separate SEP, and reading it is what keeps this from turning into false urgency. SEP-2596 requires a minimum deprecation window of “at least twelve” months measured from the specification revision that first marks a feature deprecated, after which the feature becomes eligible for removal [9]. Eligible is not scheduled. The same document says plainly that “features may remain Deprecated, without removal, for much longer than the minimum deprecation window,” and that “once a feature is set for removal, the removal is executed at the discretion of the Core Maintainers” [9].
So there is no twelve-month clock ticking on anyone’s Roots implementation. There is a floor below which removal cannot happen, and a discretionary decision above it. Plan the migration on your own schedule and stop building new things on the three deprecated primitives.

Figure 4 - Eligibility is not a deadline: SEP-2596 names the three feature states Active, Deprecated, and Removed. The twelve-month window is the earliest point at which removal becomes possible, not the date it happens. The policy explicitly allows a deprecated feature to sit in that state indefinitely, and removal is a maintainer decision taken separately.
Why MCP exists at all
With Sampling subtracted, the case for MCP over a conventional REST API is narrower than the early pitches, and it holds up better for being narrower. Three properties survive.
Runtime self-description. An agent can ask a server what it can do, in a machine-readable form, at the moment it needs to know. A REST API published behind an OpenAPI document describes itself to a developer at build time. That is a different consumer with different needs.
M plus N instead of M times N. Every agent that needs every system is a wiring problem that multiplies. One practitioner walkthrough puts the arithmetic bluntly: “the math collapses. M * N becomes M + N. 500 cables become 60” [11]. The exact numbers are illustrative rather than measured, and the shape is right. A shared contract turns a grid into two lists.
One governed contract. Auth, approval, logging, and revocation attach to one surface rather than to every point-to-point integration separately. That is the property the identity section below is really about.
The single-question test for which side you are on is still the cleanest framing available: “Who is consuming this interface? If the consumer is code, code you write, test, and deploy, use the API deterministic, fast, proven. If the consumer is a model making choices at runtime… that is MCP” [11].

Figure 5 - The wiring argument, minus the deprecated parts: The surviving case for MCP is a shared runtime-discoverable contract, not any single interactive primitive. Two of the three interactive client primitives are now deprecated, and the wiring argument is untouched by that.
The adoption record supports the wiring argument rather than the primitive argument: released by Anthropic on 2024-11-25, adopted by Microsoft in Copilot Studio on 2025-03-19, by OpenAI, and by Google DeepMind on 2025-04-09, then donated on 2025-12-09 to the Agentic AI Foundation, a directed fund under the Linux Foundation co-founded by Anthropic, Block, and OpenAI [12][13][14][15].
Six tool designs against the same backend
AWS built the comparison properly. Daniel Wells and Raian Osman built six versions of the same MCP tool, each wrapping an identical simulated K-12 content search API with 14 filterable fields, each field carrying a controlled vocabulary [1]. Same backend, same task, six different answers to the bloat-versus-confusion tradeoff. AWS’s own labels, in order:
| Version | AWS’s label | What it does | What it costs |
|---|---|---|---|
| V1 | Raw passthrough | Internal field names, one-line docstring, no valid values published | Smallest definition, worst outcomes. Wrong-value guesses trigger retries that consume more context than the definition ever saved |
| V2 | Rich descriptions | Same structure, no backend change. Docstring lists valid values and synonym mappings, distinguishes fuzzy search from strict filters, drops rarely-used parameters, returns actionable errors | Accuracy jumps immediately. The definition is noticeably larger, though fewer retries often make total context lower than V1 |
| V3 | Schema and defaults | Parameters renamed to match how the model thinks, finite fields constrained to enums in the schema, sensible defaults for the common case, drill-down split into a separate tool | Definition gets smaller than V2 because names and enums do the work the prose was doing. Accuracy improves while context drops |
| V4 | Lazy loading (restructuring) | Enums and detailed descriptions move behind a separate get_taxonomy tool; the search tool keeps short hints only | Leanest baseline context. Costs an extra round trip on ambiguous queries; the saving compounds as the number of connected tools grows |
| V5 | LLM introspection | An introspect_query tool backed by a small developer-controlled model interprets the user’s phrasing server-side and returns recommended filter values | You pay for an extra inference call. In exchange, weaker client models stop guessing and behavior stays consistent across clients |
| V6 | Agent-as-tool | One tool, agentic_search_content(question: str), backed by a full agent with its own prompt and internal tools the client never sees | Highest infrastructure cost and latency, in exchange for direct control over behavior regardless of which client connects |
The labels and the design of each version are AWS’s; the cost column combines AWS’s stated tradeoffs with our own read of what each one costs in practice.

Figure 6 - The six designs as a tradeoff, not a ladder: Relative positions are illustrative rather than AWS-measured. AWS publishes the tradeoffs qualitatively, not as per-version numbers. Moving right does not strictly dominate. V3 is the only step that reduces bloat and confusion simultaneously, which is why it is the highest-value single change most teams have not made. V5 and V6 buy consistency across client models with infrastructure cost, not with context savings.
AWS’s summary judgment is refreshingly unheroic: no version wins across all dimensions [1]. The right pick depends on field count, vocabulary stability, latency budget, and how much you care about behaving identically across different client models.
Two of these tiers gained real capability in the July revision, which is why the spec section came first.
V3 got a bigger schema vocabulary. SEP-2106 aligns inputSchema and outputSchema with JSON Schema 2020-12, enabling composition keywords anyOf, oneOf, allOf, and not, plus reference schemas $ref and $defs [16]. There is an asymmetry worth knowing: inputSchema still requires type: "object" because tool arguments are objects, while outputSchema “fully supports JSON Schema 2020-12 since MCP servers may return any valid JSON” [16]. The caveat is a hard security requirement rather than a footnote. Implementations “MUST NOT automatically dereference $ref values that resolve to a network URI,” on SSRF and fetch-amplification grounds, and SHOULD bound schema depth and subschema count against pathological composition [16].
V4 got cacheable discovery. SEP-2549 requires servers to provide a ttlMs on results returned by tools/list, prompts/list, resources/list, resources/read, and resources/templates/list, alongside a cacheScope of "public" or "private" [17]. Progressive disclosure is now cacheable without a persistent connection, which removes the main operational objection to splitting a taxonomy out into its own tool. TTL supplements the existing change-notification mechanism rather than replacing it [17].
The lazy-loading tier is also the one with the hardest number attached to it, from the platform side. Anthropic measured its Tool Search Tool, which excludes tool definitions from the initial context and expands them only when the model searches for them, and reported that the traditional approach consumed roughly 77,000 tokens before any work began against roughly 8,700 tokens with search enabled: “an 85% reduction in token usage while maintaining access to your full tool library” [18]. Accuracy moved in the same direction rather than trading against it, from 49% to 74% on one model and from 79.5% to 88.1% on another [18]. That is the same “Reduce” strategy we mapped across retrieval and decision memory in The Context Engineering Stack [19], arriving one layer down in the protocol.
The rules AWS publishes separately
Alongside the six-version teardown, AWS Prescriptive Guidance publishes concrete tool rules across two pages, and the split matters because people quote them as one list. “Best practices for MCP tool scoping” gives five [20]:
- Think in user stories, and bundle common operations that would otherwise require three or more separate calls.
- Limit parameters to eight or fewer.
- Separate read and write operations.
- Provide sensible defaults.
- Prefer deterministic execution.
The sibling “Tool definitions” page gives four more [21]:
- Follow the MCP tool specification.
- Write descriptions as prompts.
- Provide concrete examples.
- Document dependencies explicitly.
The parameter rule is the one everyone quotes, and everyone quotes half of it. The rule reads: “Limit parameters to eight or fewer. If a tool exceeds eight parameters, decompose it into multiple tools. LLMs struggle with parameter selection as complexity increases” [20]. The very next line overrides it: “If bundling operations requires more than eight parameters, prioritize bundling over parameter count because simplifying the workflow is more valuable than strict parameter limits” [20]. Eight is a decomposition trigger, not a ceiling, and splitting a tool that bundles a real workflow just to satisfy the number makes the catalog worse.
One more rule is widely quoted with the wrong pedigree. AWS says shifting to on-demand detail cuts response tokens by roughly two-thirds and attributes that to Anthropic’s research [1]. Anthropic’s actual sentence is narrower: in a worked Slack-tool example, “we use ~1/3 of the tokens with concise tool responses,” measured on one response that went from 206 tokens to 72 [22]. The advice is sound and the pattern is right. Treat the two-thirds figure as a worked example that AWS generalized, not as a measured research finding.
KEY INSIGHT: V3 is the tier most teams skip and the only one that improves both failure modes at once. Renaming parameters to match how the model thinks about the domain, constraining finite fields to enums, and defaulting the common case makes the definition smaller and the choices better in the same edit.
What it is worth in production
The six-version teardown is a controlled demo against a simulated backend. A second AWS post, co-authored with Smartsheet, runs the same disciplines at production traffic and publishes numbers [23]. Every figure below is Smartsheet-reported internal telemetry published through AWS’s blog, and the post says so explicitly. Treat it as a vendor case study, not as an audited result.
Progressive disclosure with a per-response token budget is the lazy-loading tier operationalized. Smartsheet reports that “each tool response targets a token budget. The server dynamically calculates how many rows fit based on column count and data density” [23]. Whether a sheet holds 50 rows or 50,000, response size stays bounded. The part that makes this legible rather than merely truncated is the metadata contract: “is_sampled indicates whether data was truncated, rows_in_sheet gives the full count, rows_actual shows how many were returned, and filters_applied describes active filters” [23]. The model is told what it is missing, so it narrows with filters rather than assuming it has the whole set.
Strict generated schemas are the schema-and-defaults tier operationalized, with a second benefit the AWS framework does not name. Parameters are constrained to valid enums, column names are validated against the actual sheet before execution, and mismatches return structured errors listing valid options. Smartsheet’s framing is the useful one: “Schema validation catches hallucinations at the boundary and means agents navigate the tool catalog reliably without trial and error” [23]. A strict schema is not just a bloat-versus-confusion tuning knob. It is a containment boundary for a class of failure.
Response serialization is where the reported numbers land. Smartsheet reports that JSON’s structural overhead typically consumes 15% to 25% of a response’s token count, and that it built a proprietary serialization format in which key names appear once instead of repeating per row, with structural syntax replaced by delimiters that tokenize more efficiently [23]. The post gives no name for the format and publishes no schema, so that description is the whole of what is known about it. On a representative 33-item filtered query the optimized response runs about 3,900 tokens against over 6,000 for equivalent JSON, and the post’s overall claim is “a proprietary serialization format that reduces token count by 35-47 percent on data-heavy responses” [23]. The headline: “Since launch, Smartsheet saved over 3 billion tokens, based on internal telemetry, through these optimizations” [23].

Figure 7 - Reported production token math: Smartsheet reports 3,900 tokens against over 6,000 on the same 33-item result, a 35% to 47% reduction on data-heavy responses, and over 3 billion tokens saved since launch. All three figures are self-reported internal telemetry rather than independently audited measurements, which is how AWS’s post presents them.
One aside from the same post is worth carrying into your test plan: an MCP tool response passes through a model before anyone sees it, and “that layer of non-determinism changes what ‘correct’ means for testing” [23]. A conventional API response is rendered deterministically by a UI. A tool response is interpreted. Schema mistakes that a UI would surface immediately can instead surface as a model quietly misreading a field.
When not to reach for MCP at all
Here is the part of the tool-design conversation that most tool-design writing skips. Sometimes the correct number of MCP tools for a job is zero.
Arize AI ran an evaluation comparing MCP against CLI-based agent skills on the same task set, and published the arms [24]. Correctness came out close to level: MCP 0.834, the Vault CLI skill 0.833, the LobeHub CLI skill 0.826. The fourth arm is the one worth dwelling on, and it is the most interesting number in the study. A bare model with no MCP server and no skills at all scored 0.845, higher than any tooled arm, though Arize reports that “on cost and latency, the skills still beat the baseline” [24].

Figure 8 - The arm everyone drops: On this benchmark the model with no tool catalog was the most accurate arm. That does not mean tools are useless. It means the accuracy case for adding a tool catalog has to be made per task rather than assumed, because on a task set the model can already handle, tools cost accuracy as well as tokens.
Arize is careful about why: gh is documented across thousands of pages the model saw in pretraining, so “the training data is doing most of the work.” Their own warning is that your company’s CLI is not GitHub’s, and against an unfamiliar surface you will need a skill or you will need MCP [24].
Cost is where the arms separate. On the hardest tier of tasks, Arize reports that “MCP cost more than six times what the skills cost and took five times longer” [24], and that “on average, MCP made about twelve tool calls per tier-4 task. The skills made five” [24]. The worst single case is dramatic and gets quoted as though it were the study: on one analysis task, MCP took “71 tool calls, eight minutes of wall-clock time, and burned two dollars” where the Vault skill took “seven tool calls, under a minute, 19 cents” [24]. Only three of those 71 calls were actually MCP, the rest was bash parsing JSON [24]. That is one task. The study’s own average is 12 against 5, and the aggregate ratio is roughly 6x cost and 5x time. Quote the 71 if you like, as the worst case, next to the average. Arize also reports why the call counts diverge: on tier-4 tasks the skills held above 99% tool fidelity while the MCP arm sat at 0.33, falling back to bash whenever the API could not compose the task [24].
Two units are easy to get wrong when this study is relayed. Arize counts tool calls, not round trips. The comparison arms are named CLI skills (Vault and LobeHub), not a bare shell handed to an agent.
The mechanism behind the gap is the same one this whole article is about, pushed one layer out. Tool definitions are paid per turn, and the number of turns is itself inflated because the model re-decides on every step instead of running a sequence it already worked out. Anthropic measured the definition half of this directly: having an agent write code against MCP servers, loading only the definitions the task needs instead of the whole catalog upfront, “reduces the token usage from 150,000 tokens to 2,000 tokens,” which Anthropic puts at “a time and cost saving of 98.7%” [25]. That comparison is code execution against direct tool calls, both over MCP, so it is not a verdict on MCP versus a CLI. It is a verdict on how many times the model gets put back in the loop.
KEY INSIGHT: The per-call definition tax is multiplied by turn count, so the cheapest fix for a bloated catalog is often not a better tool description. It is a design where the model writes a sequence once instead of being consulted on every step.
The gate side: who the tool is acting as
A tool catalog can be perfectly named, tightly schema’d, lazily loaded, and still be a bad design, because every caller reaches the backend as the same god-mode service account. Identity is a tool-design constraint, not an infrastructure detail bolted on afterwards.
The pattern worth copying is per-user OAuth attribution at the connector. In a build-along demonstration of connecting an existing private web app to Claude, Leon van Zyl shows the agent authenticating as the specific signed-in human: “Claude first needs to authenticate itself in the app so that we know who the actual user is that’s using this agent” [26]. When the agent then assigns a task, the app’s own UI attributes it correctly, because “this agent via this OAuth connection actually knows who you are. It’s kind of acting on your behalf in this application” [26]. Every existing per-user authorization rule in the app keeps applying, since the agent is that user’s session rather than a privileged bypass of it.
Three structural properties fall out of that, and all three shape the tool catalog:
- Approval is two-sided and per-tool. Access can be narrowed from the server or from the client’s connector settings: “We can just choose if this needs approval. Maybe this tool should be blocked entirely, or certain tools could just be automatically approved” [26]. A perfectly written tool can be gated shut for one organization without touching its definition.
- Blast radius equals the exposed function list. The agent never holds database credentials. It calls named tools the backend implements, so the reachable surface is exactly as wide as the catalog and no wider. Narrowing the catalog is a security control, which is the same argument we made about removing capabilities rather than guarding them in Multi-Tenant Agent Security [27].
- Revocation is explicit and two-sided. Access can be revoked at the server or the connection broken at the client [26]. Governability after deployment is a design property, not an operational afterthought.
That gate matters more than usual here because tool descriptions are themselves an injection surface. OWASP catalogues tool poisoning as MCP03:2025, in which instructions hidden in a tool’s own description steer the model, following the April 2025 Invariant Labs demonstration [28][29]. The supply chain has already produced a critical example: CVE-2025-6514 in mcp-remote allowed OS command injection when a client connected to an untrusted or malicious MCP server [30]. Adding a tool adds text that the model reads as instructions and code that runs on somebody’s behalf. Both halves are reasons to keep the catalog small.

Figure 9 - The catalog is the blast radius: On the left, one credential reaches everything the backend can reach, and tool quality is irrelevant to the security outcome. On the right, the agent acts as the signed-in user through named functions, so the reachable surface equals the tool list and every existing authorization rule still applies.
KEY INSIGHT: Identity design decides which tools are safe to expose, so it belongs upstream of tool wording. A catalog reached through a shared service account cannot be made safe by better descriptions, and a catalog reached as the signed-in user is bounded by the function list you chose to publish.
The discipline that stops bloat from starting
The cheapest correct mechanism wins, and an agent tool is rarely the cheapest. Nate Herk ranks his own decision order for automating any task in three rungs. Go for an API first, because “it’s the fastest, it’s usually the cheapest, it’s usually just the most consistent” [31]. If no API exists, “see if I could use like a deterministic macro script” [31]. Only when the task genuinely needs judgment, “because there is an element of vision or reasoning,” do you reach for browser use or an agent [31]. That is one practitioner’s heuristic rather than any vendor’s published policy, and it is a good one. He also notes he picked browser automation over an existing API on one workflow because the API was worse in practice, which is the right lesson: fitness for the task, not dogma.
Run that ladder before every new tool. A tool that exists because an agent was available, rather than because the task needed runtime judgment, is pure bloat charged to every call that never uses it.
The audit checklist
Run this against your own MCP server. In our experience three or four items fail on a first pass, and the fixes tend to be a single afternoon each.
Bloat
- Sum the serialized byte size of every tool definition your server advertises, then multiply by turns per session. That number is your fixed tax before a single question is asked.
- Count tools that are called in fewer than 5% of sessions. Every one of them is charged on every call. Move them behind a lazy-loaded companion tool or drop them.
- Move enums and long value vocabularies out of the always-loaded definitions and behind a taxonomy tool, then set
ttlMsandcacheScopeon yourtools/listresult so discovery is cacheable without a persistent connection [17]. - Cap response size with a token budget and publish metadata telling the model what was truncated, the full count, and which filters were applied [23].
Confusion
- Rename every parameter that carries an internal column name to the word the model would use for it.
disciplinebecomessubject[1]. - Constrain every finite-vocabulary field to an enum in the schema, and default the common case so the model only specifies what varies [1].
- Count parameters per tool. Above 8, decompose, unless the tool bundles a genuine multi-call workflow, in which case bundling wins [20].
- Separate read from write, and give every write tool a name no read tool could plausibly be mistaken for [20].
- Replace every bare “no results” error with one that names what to change. “search requires 2 or more terms in query” is a working instruction; “no results” is a guess prompt [1].
- Check for semantically overlapping tools across all connected servers, not just your own. Confusion is a property of the union.
The gate
- Confirm the agent authenticates as the end user, not as a shared service account, and that writes attribute to a real identity [26].
- Confirm per-tool approval and blocking exist on both the server and the client side, and that revocation works from both [26].
- Read every tool description as though an attacker wrote it, because on a third-party server one might have. Tool poisoning is catalogued as OWASP MCP03:2025 [28].
The 2026-07-28 protocol audit
- Grep for protocol sessions used to carry application state. That state now needs an explicit home, and this is the one migration in the revision that costs real engineering time [4].
- Grep for
logging/setLeveland any dependence on Roots, Sampling, or Logging. No emergency, no countdown, and stop building new work on them [8][9]. - Grep client code for literal matches on the
-32002error code, which AWS flags as an audit target for gateway-era assumptions [32]. - If you rely on server-initiated requests, confirm they are associated with an originating client request, and move elicitation to
InputRequiredResultwith an opaquerequestStateyou revalidate server-side on every call [7][10].
Should this be a tool at all
- For each tool, ask whether an API call or a deterministic script would do the job. If yes, that tool is bloat with extra steps [31].
- For each multi-step workflow, ask whether the model could write the sequence once instead of being consulted on every turn [25].

Figure 10 - The audit as five questions: Bloat and confusion are the two failure modes, the gate decides how far either one can reach, the protocol audit catches assumptions the July revision invalidated, and the last group is the one that prevents the other four from being needed at all.
If you run this and want a second pair of eyes on the result, that is exactly the work we do. Send us the tool definitions and we will tell you what they cost you per session and which three changes buy the most back.
Conclusion
Tool design is a context engineering problem wearing a documentation problem’s clothes. Bloat and confusion are the two failure modes, they manufacture each other, and every fix for one is a cost against the other. That is why AWS’s six versions are a tradeoff space rather than a maturity ladder, and why the honest answer to “which tier should we be on” is that it depends on your field count, your vocabulary stability, your latency budget, and your client mix.
Three things are worth carrying past the specifics: the schema-and-defaults tier is the only step that improves both failure modes at once, the per-call definition tax multiplies by turn count, and the Arize arm with no tool catalog at all scored highest on correctness, which is the strongest available argument for treating every new tool as a cost that has to justify itself rather than a capability that is free to add.
The protocol underneath all of this is in better shape than it was in July, and it is being pruned in public with a published lifecycle policy. Sessions are gone, the handshake is gone, and three primitives are deprecated with a stated security rationale and no deadline attached. None of that changes the thesis. It just means the ground you are designing on is firmer than it was, and the parts of the old advice that no longer apply are now clearly marked.
References
[1] D. Wells and R. Osman, “MCP tool design: Practical approaches and tradeoffs,” AWS Machine Learning Blog, Jul 2026. https://aws.amazon.com/blogs/machine-learning/mcp-tool-design-practical-approaches-and-tradeoffs/
[2] G. Dotzlaw, K. Dotzlaw, and R. Dotzlaw, “Your 1M-Token Context Window Is a Lie After 120K: Budgeting Sessions with /handoff,” 2026. /insights/claude-code-14-context-lifecycle/
[3] “The 2026-07-28 Specification,” Model Context Protocol Blog, Jul 2026. https://blog.modelcontextprotocol.io/posts/2026-07-28/
[4] P. Alexander, “SEP-2567: Sessionless MCP via Explicit State Handles,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2567-sessionless-mcp
[5] J. Hefner, M. Roth, S. Smith, H. Tuch, and K. Van Gent, “SEP-2575: Make MCP Stateless,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2575-stateless-mcp
[6] MCP Transports Working Group, “SEP-2243: HTTP Header Standardization for Streamable HTTP Transport,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2243-http-standardization
[7] M. Roth, C. McCaffrey, and G. Zimmerman, “SEP-2322: Multi Round-Trip Requests,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2322-MRTR
[8] K. Van Gent, “SEP-2577: Deprecate Roots, Sampling, and Logging,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2577-deprecate-roots-sampling-and-logging
[9] D. Delimarsky, “SEP-2596: Specification Feature Lifecycle and Deprecation Policy,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2596-spec-feature-lifecycle-and-deprecation
[10] MCP Transports Working Group, “SEP-2260: Require Server requests to be associated with a Client request,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2260-Require-Server-requests-to-be-associated-with-Client-requests
[11] Hyperautomation Labs, “MCP vs API: The 5 Ways Traditional APIs Fail AI Agents,” YouTube, Jul 2026. https://www.youtube.com/watch?v=zWvBRDdpILs
[12] Anthropic, “Introducing the Model Context Protocol,” Anthropic News, Nov 2024. https://www.anthropic.com/news/model-context-protocol
[13] Z. Desai, “Introducing Model Context Protocol (MCP) in Copilot Studio,” Microsoft Copilot Blog, Mar 2025. https://www.microsoft.com/en-us/microsoft-copilot/blog/copilot-studio/introducing-model-context-protocol-mcp-in-copilot-studio-simplified-integration-with-ai-apps-and-agents/
[14] D. Hassabis, post on X, Apr 2025. https://x.com/demishassabis/status/1910107859041271977
[15] “MCP joins the Agentic AI Foundation,” Model Context Protocol Blog, Dec 2025. https://blog.modelcontextprotocol.io/posts/2025-12-09-mcp-joins-agentic-ai-foundation/
[16] J. McBride and O. Hungerford, “SEP-2106: Tools inputSchema and outputSchema Conform to JSON Schema 2020-12,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2106-json-schema-2020-12
[17] C. McCaffrey, “SEP-2549: TTL for List Results,” Model Context Protocol, Final, 2026. https://modelcontextprotocol.io/seps/2549-TTL-for-list-results
[18] B. Wu, “Introducing advanced tool use on the Claude Developer Platform,” Anthropic Engineering Blog, Nov 2025. https://www.anthropic.com/engineering/advanced-tool-use
[19] G. Dotzlaw, K. Dotzlaw, and R. Dotzlaw, “The Context Engineering Stack: Compression, Retrieval, and Decision Memory,” 2026. /insights/ai-16-context-engineering-stack/
[20] “Scoping MCP tools,” Model Context Protocol strategies on AWS, AWS Prescriptive Guidance. https://docs.aws.amazon.com/prescriptive-guidance/latest/mcp-strategies/mcp-tool-strategy-scoping.html
[21] “Tool definitions,” Model Context Protocol strategies on AWS, AWS Prescriptive Guidance. https://docs.aws.amazon.com/prescriptive-guidance/latest/mcp-strategies/mcp-tool-strategy-definitions.html
[22] K. Aizawa, “Writing effective tools for AI agents,” Anthropic Engineering Blog, Sep 2025. https://www.anthropic.com/engineering/writing-tools-for-agents
[23] V. Kosturski, R. Blum, G. Jordanowa, and P. Thant Win, “How Smartsheet built a remote MCP server on AWS,” AWS Machine Learning Blog, Jul 2026. https://aws.amazon.com/blogs/machine-learning/how-smartsheet-built-a-remote-mcp-server-on-aws/
[24] L. Voss, “MCP vs. CLI Skills for agents: what our eval found (and which you should use),” Arize AI, May 2026. https://arize.com/blog/mcp-vs-cli-skills-for-agents-what-our-eval-found-and-which-you-should-use/
[25] A. Jones and C. Kelly, “Code execution with MCP: building more efficient agents,” Anthropic Engineering Blog, Nov 2025. https://www.anthropic.com/engineering/code-execution-with-mcp
[26] L. van Zyl, “Claude Can Use Your Apps Now,” YouTube, Aug 2026. https://www.youtube.com/watch?v=N2Ogvx_U8uM
[27] G. Dotzlaw, K. Dotzlaw, and R. Dotzlaw, “Multi-Tenant Agent Security: The LLM Is Not Your Security Boundary,” 2026. /insights/ai-26-multi-tenant-agent-security/
[28] “MCP03:2025, Tool Poisoning,” OWASP MCP Top 10, OWASP Foundation. https://owasp.org/www-project-mcp-top-10/2025/MCP03-2025%E2%80%93Tool-Poisoning
[29] “MCP Security Notification: Tool Poisoning Attacks,” Invariant Labs, Apr 2025. https://invariantlabs.ai/blog/mcp-security-notification-tool-poisoning-attacks
[30] “CVE-2025-6514,” CVE Program record, 2025. https://www.cve.org/CVERecord?id=CVE-2025-6514
[31] N. Herk, “Codex’s Browser Agent Automates Literally Anything,” YouTube, Aug 2026. https://www.youtube.com/watch?v=CB5bG4mvnS0
[32] “How AgentCore Gateway supports the MCP 2026-07-28 spec,” AWS Machine Learning Blog, Jul 2026. https://aws.amazon.com/blogs/machine-learning/how-agentcore-gateway-supports-the-mcp-2026-07-28-spec/
Building production AI, or modernizing a legacy system?
That is the kind of work we do at Dotzlaw Consulting. Book a free 20-minute intro call and tell us what you are trying to build, or what is slowing you down.