<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gaurav Dadhich</title>
    <description>The latest articles on DEV Community by Gaurav Dadhich (@gaurav_dadhich).</description>
    <link>https://dev.to/gaurav_dadhich</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3739855%2F2c23ebe1-927c-4ca9-b99a-1a21f939a0ad.png</url>
      <title>DEV Community: Gaurav Dadhich</title>
      <link>https://dev.to/gaurav_dadhich</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gaurav_dadhich"/>
    <language>en</language>
    <item>
      <title>Claude API Pricing in 2026: Every Model per Million Tokens, and What Pro and Max Cost</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Sat, 26 Sep 2026 09:12:27 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/claude-api-pricing-in-2026-every-model-per-million-tokens-and-what-pro-and-max-cost-406n</link>
      <guid>https://dev.to/gaurav_dadhich/claude-api-pricing-in-2026-every-model-per-million-tokens-and-what-pro-and-max-cost-406n</guid>
      <description>&lt;p&gt;# Claude API Pricing in 2026: Every Model per Million Tokens, and What Pro and Max Cost *Published 26 September 2026 · Every price below was read from Anthropic's pricing documentation, the &lt;a href="https://www.maximem.ai/synap/pricing" rel="noopener noreferrer"&gt;Claude plans page&lt;/a&gt; and the Claude Help Center on 26 September 2026, four days after Claude Opus 5.5 launched.* The Claude API costs between $1 and $10 per million input tokens and between $5 and $50 per million output tokens on Anthropic's current models: Claude Haiku 4.5 at $1 and $5, Claude Sonnet 5 at $2 and $10, Claude Opus 5.5 at $4 and $20, and Claude Fable 5.1 at $10 and $50. Cached input is billed at a small fraction of those rates, the &lt;a href="https://www.maximem.ai/glossary/kv-cache" rel="noopener noreferrer"&gt;Batch API&lt;/a&gt; halves them, and none of the current models charges a premium for long context. Claude's apps are priced separately from the API: Free is $0, Pro is $20 a month ($17 a month billed annually), and Max is $100 or $200 a month for five or twenty times Pro's usage. Those rates are the easy part. What decides a Claude bill is how many tokens each request carries, and in a multi-turn product that number grows with every turn, because the whole conversation is sent again each time. The worked example further down shows a 40-turn chat on Sonnet 5 costing $1.09 without &lt;a href="https://www.maximem.ai/glossary/prompt-caching" rel="noopener noreferrer"&gt;prompt caching&lt;/a&gt; and $0.29 with it, from the same rate card. ## Claude API price per million tokens, current models | Model | Input | Output | 5-minute cache write | 1-hour cache write | Cache read | Batch input | Batch output | |---|---|---|---|---|---|---|---| | Claude Haiku 4.5 | $1 | $5 | $1.25 | $2 | $0.10 | $0.50 | $2.50 | | Claude Sonnet 5 | $2 | $10 | $2.50 | $4 | $0.20 | $1 | $5 | | Claude Opus 5.5 | $4 | $20 | $5 | $8 | $0.20 | $2 | $10 | | Claude Fable 5.1 | $10 | $50 | $12.50 | $20 | $0.25 | $5 | $25 | All figures are US dollars per million tokens, from [Anthropic's pricing documentation](&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/about-claude/pricing&lt;/a&gt;). Claude Mythos 5.1 carries the same rates as Fable 5.1. Opus 5.5, released on 22 September 2026, is the change most pricing pages have not caught up with yet. [Anthropic's launch post](&lt;a href="https://www.anthropic.com/claude-opus-5-5" rel="noopener noreferrer"&gt;https://www.anthropic.com/claude-opus-5-5&lt;/a&gt;) puts its input and output rates 20% below Opus 5 ($5 and $25) and its cache reads 60% below ($0.20 against $0.50). Sonnet 5 launched on 30 June 2026 at an introductory $2 and $10, and [Anthropic made that price permanent](&lt;a href="https://www.anthropic.com/news/claude-sonnet-5" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/claude-sonnet-5&lt;/a&gt;) in August. Choosing between them on price alone is simple arithmetic: Sonnet 5 costs half of Opus 5.5 per token, Haiku 4.5 costs half of Sonnet 5, and Fable 5.1 costs two and a half times Opus 5.5. Sonnet 5 is the default model in the Free and Pro apps. Which model is good enough for a given job is a quality question the rate card cannot answer, so run your own prompts through two adjacent tiers before committing a workload to either. ## Older models still on the price sheet Anthropic still lists earlier models, and several of them cost more than their replacements. | Model | Input | Output | Cache read | |---|---|---|---| | Claude Opus 5, Opus 4.8, 4.7, 4.6, 4.5 | $5 | $25 | $0.50 | | Claude Opus 4.1 and Opus 4 | $15 | $75 | $1.50 | | Claude Sonnet 4.6, 4.5 and 4 | $3 | $15 | $0.30 | | Claude Haiku 3.5 | $0.80 | $4 | $0.08 | | Claude Fable 5 and Mythos 5 | $10 | $50 | $1 | A workload still pinned to Opus 4.1 pays $15 and $75; the same tokens on Opus 5.5 cost 73% less. A workload on Sonnet 4.6 pays $3 and $15, so moving it to Sonnet 5 cuts the token bill by a third, although a model change is a quality decision as well as a price one and deserves the same evaluation as any other. ## What one request actually bills Every request is billed as input tokens plus output tokens, and input is more than the user's latest message. [Anthropic's context window documentation](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-windows" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-windows&lt;/a&gt;) lists what counts: the &lt;a href="https://www.maximem.ai/glossary/system-prompt" rel="noopener noreferrer"&gt;system prompt&lt;/a&gt;, every message in the &lt;code&gt;messages\&lt;/code&gt; array (including tool results, images and documents), the tool definitions, and Claude's own earlier output. In a conversation, "previous turns are preserved completely", which means turn 40 pays again for turns 1 to 39. Thinking tokens are billed as output. The [extended thinking documentation](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/extended-thinking" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/extended-thinking&lt;/a&gt;) reports them in &lt;code&gt;usage.output\_tokens\_details.thinking\_tokens\&lt;/code&gt; as part of the billed output, so a reasoning-heavy request can cost several times what its visible answer suggests. On Opus 4.5 and later, Sonnet 4.6 and later, and the Fable and Mythos models, earlier thinking blocks also stay in the conversation and count toward the &lt;a href="https://www.maximem.ai/glossary/context-window" rel="noopener noreferrer"&gt;context window&lt;/a&gt; like any other input, while Haiku models and older Opus and Sonnet models have them stripped automatically. The tokenizer matters too. [Anthropic's Opus 4.7 announcement](&lt;a href="https://www.anthropic.com/news/claude-opus-4-7" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/claude-opus-4-7&lt;/a&gt;) says its updated tokenizer can map the same input to roughly 1.0 to 1.35 times as many tokens depending on content, with the per-token price unchanged. When you compare a bill across model generations, count tokens rather than characters, using the [token counting endpoint](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/token-counting" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/token-counting&lt;/a&gt;) before you send and the &lt;code&gt;usage\&lt;/code&gt; fields on every response after. ## When prompt caching pays for itself Prompt caching stores a prompt prefix so that later requests read it instead of paying full input price for it. The [prompt caching documentation](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/prompt-caching&lt;/a&gt;) sets the multipliers against the base input rate: a 5-minute cache write costs 1.25 times, a 1-hour cache write costs 2 times, and a cache read costs 0.1 times. Opus 5.5 reads at 0.05 times and Fable 5.1 and Mythos 5.1 at 0.025 times, which is why their cache-read prices sit so close to Sonnet 5's. The break-even follows directly. Two requests sharing a 5-minute cached prefix pay 1.35 times the prefix instead of 2 times, so caching saves money from the first reuse. A 1-hour write pays 2.1 times across two requests against 2 times uncached, so it loses on one reuse and wins from the second. The 1-hour cache is for traffic that returns after more than five minutes but less than an hour, such as a user who pauses between messages; the 5-minute cache suits rapid turns and agent loops. Four details decide whether caching works in practice: - **Minimum length.** A prefix shorter than the model's minimum is not cached, and the API returns no error. The minimum is 512 tokens on Opus 5.5, Opus 5 and Fable 5.1, 1,024 tokens on Sonnet 5 and Sonnet 4.6, and 4,096 tokens on Haiku 4.5. - **Order of invalidation.** The cache follows the order tools, then system, then messages. Changing a tool definition invalidates everything after it, and adding an image or changing &lt;code&gt;tool\_choice\&lt;/code&gt; invalidates the message cache. - **Breakpoints.** A request can carry up to four cache breakpoints, and automatic caching (a top-level &lt;code&gt;cache\_control\&lt;/code&gt; setting) uses one of them and moves forward as the conversation grows. - **Rate limits.** Cache hits do not count against your rate limit; only uncached tokens do. Check &lt;code&gt;cache\_read\_input\_tokens\&lt;/code&gt; and &lt;code&gt;cache\_creation\_input\_tokens\&lt;/code&gt; in the response. A cache that silently misses costs at least ten times the read price on every request (twenty times on Opus 5.5, forty on Fable 5.1), and the only place it shows up is the usage object. ## Batch API, long context and the smaller line items **Batch API.** Asynchronous batch requests cost 50% of the standard input and output rates on every model, as the table above shows. Anything that does not need an answer within the conversation, such as nightly summarisation, evaluation runs or back-filling a &lt;a href="https://www.maximem.ai/glossary/dataset" rel="noopener noreferrer"&gt;data set&lt;/a&gt;, belongs there. **Long context.** Claude 4.6 and later models include the full 1 million token context window at standard pricing. Claude Sonnet 5, Opus 5.5, Fable 5.1 and every Opus model from 4.6 onward take 1 million tokens, and every model can generate up to 128,000 output tokens per request. **Fast mode.** A research-preview speed setting runs Opus 5.5 at $8 and $40 per million tokens, twice its standard rate. **US-only &lt;a href="https://www.maximem.ai/glossary/inference" rel="noopener noreferrer"&gt;inference&lt;/a&gt;.** Setting &lt;code&gt;inference\_geo\&lt;/code&gt; to &lt;code&gt;"us"\&lt;/code&gt; applies a 1.1 times multiplier to every token category on Claude 4.6 and later models. **Tools and runtime.** Web search costs $10 per 1,000 searches plus the tokens it adds, web fetch costs only its tokens, code execution costs $0.05 an hour after 50 free hours a day, and Claude Managed Agents sessions cost $0.08 per session-hour. ## What a real conversation costs Take a chat assistant with a 2,000-token system prompt, where each user message is 150 tokens and each reply is 350 tokens. The first turn sends 2,150 tokens. By turn 40 a single request carries 21,650 tokens, because it includes the 39 exchanges before it, and the whole 40-turn conversation has consumed 476,000 input tokens to produce 14,000 output tokens. | Model | 40 turns, no caching | 40 turns, cache warm | 100 turns, no caching | 100 turns, cache warm | |---|---|---|---|---| | Claude Haiku 4.5 | $0.55 | $0.14 | $2.87 | $0.50 | | Claude Sonnet 5 | $1.09 | $0.29 | $5.73 | $1.01 | | Claude Opus 5.5 | $2.18 | $0.48 | $11.46 | $1.49 | | Claude Fable 5.1 | $5.46 | $1.08 | $28.65 | $3.06 | "Cache warm" assumes automatic caching with a 5-minute cache and replies arriving inside that window, so each turn writes only the new exchange and reads everything before it. Two things stand out. Input tokens, not output, make up most of the bill once a conversation passes a few turns. And the cost per conversation grows faster than the number of turns: going from 40 to 100 turns multiplies turns by 2.5 and the uncached bill on Sonnet 5 by more than five, because each turn carries every turn before it. At 10,000 such 40-turn conversations a month on Sonnet 5, that is roughly $10,900 without caching and $2,900 with it. Caching is the first lever. It stops working when users leave and come back after the cache has expired, and the history has to be written again at the higher write price. We build [Maximem Synap](&lt;a href="https://www.maximem.ai/synap" rel="noopener noreferrer"&gt;https://www.maximem.ai/synap&lt;/a&gt;), a memory layer that sends a bounded context block (2,000 tokens by default) instead of the full transcript, so this cost is the problem we work on every day. The arithmetic for when that beats caching, and when it does not, is in [how to reduce LLM token costs in long conversations](&lt;a href="https://www.maximem.ai/blog/reduce-llm-token-costs-long-conversations" rel="noopener noreferrer"&gt;https://www.maximem.ai/blog/reduce-llm-token-costs-long-conversations&lt;/a&gt;). ## How much Claude costs per month: the plans Claude's apps (web, desktop, mobile, Claude Code and the Office and browser extensions) are sold as subscriptions, priced per person, from the [Claude plans page](&lt;a href="https://claude.com/pricing):" rel="noopener noreferrer"&gt;https://claude.com/pricing):&lt;/a&gt; | Plan | Monthly billing | Annual billing | Usage | |---|---|---|---| | Free | $0 | $0 | Base allowance | | Pro | $20 | $17 a month | More than Free | | Max 5x | $100 | n/a | 5 times Pro per session | | Max 20x | $200 | n/a | 20 times Pro per session | | Team, Standard seat | $25 per seat | $20 per seat a month | More than Pro | | Team, Premium seat | $125 per seat | $100 per seat a month | 5 times a Standard seat | | Enterprise | n/a | $20 per seat a month, plus usage | Usage cost scales with model and task | Annual billing saves $36 a year on Pro and $60 a seat on Team Standard. Enterprise adds SCIM, audit logs, a &lt;a href="https://www.maximem.ai/glossary/compliance" rel="noopener noreferrer"&gt;compliance&lt;/a&gt; API, custom data retention and a HIPAA-ready offering on top of Team. ## Free vs Pro vs Max: what actually changes The three individual plans differ mainly in how much you can use, not in what you can use it for. **Free** covers chat on web, desktop and mobile with web search, file creation, code execution, memory and app connections. **Pro** adds Claude Code, Claude Design, Slides and Docs, Claude Science, Projects, more models and the Chrome and Microsoft 365 extensions, with more usage per session than Free. **Max** keeps every Pro feature and raises the allowance to five or twenty times Pro's per-session usage, with higher output limits, early access to new features and priority access when traffic is high. The [Max plan article](&lt;a href="https://support.claude.com/en/articles/11049741-what-is-the-max-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11049741-what-is-the-max-plan&lt;/a&gt;) is explicit that the two Max tiers differ in usage, not in models. Anthropic does not publish message counts for any plan. Usage depends on conversation length and complexity, the model, the effort level and the tools you use, and [connectors are called out as token-intensive](&lt;a href="https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work&lt;/a&gt;). On [Pro](&lt;a href="https://support.claude.com/en/articles/8325606-what-is-the-pro-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/8325606-what-is-the-pro-plan&lt;/a&gt;) and Max, the session allowance resets every five hours, and a separate weekly limit applies across all models and resets at a fixed time assigned to your account. Chat and Claude Code draw from the same allowance, so a long coding session reduces what is left for chat. The practical rule: stay on Free until you hit its limits regularly, move to Pro when you want Claude Code or Projects, and move to Max only when you run out of Pro's weekly allowance often enough that the extra $80 or $180 a month is cheaper than waiting. ## Subscription or API? A Pro or Max plan does not include API usage. The Pro plan article says API access "requires separate Console access and billing", so a developer who wants both pays for both. Two billing surprises follow from that separation: - **Claude Code and the API key.** If &lt;code&gt;ANTHROPIC\_API\_KEY\&lt;/code&gt; is set in your environment, [Claude Code authenticates with it instead of your subscription](&lt;a href="https://support.claude.com/en/articles/11145838-use-claude-code-with-your-pro-or-max-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11145838-use-claude-code-with-your-pro-or-max-plan&lt;/a&gt;) and bills your API account at token rates, even while you are paying for Max. Unset the variable if you meant to use the plan. - **The Agent SDK credit that is not there.** Anthropic announced a separate monthly credit for Agent SDK and &lt;code&gt;claude -p\&lt;/code&gt; usage on paid plans ($20 on Pro, $100 on Max 5x, $200 on Max 20x), then [paused that change on 15 June 2026](&lt;a href="https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan&lt;/a&gt;). Until further notice, Agent SDK and third-party app usage draw from your plan's normal usage limits. Several pricing pages still describe the credit as live. For a team building a product, the question mostly answers itself. Plans are priced per person for people using Claude's own apps; a product that serves your users runs on the API, billed per token, and the useful comparison is between API configurations (model, caching, batch) rather than between an API bill and a subscription. For an individual developer, Pro or Max is usually the cheaper way to use Claude Code heavily, and the API is the right way to run anything automated in production. ## Frequently asked questions **How much does the Claude API cost per million tokens?** On current models, $1 input and $5 output for Claude Haiku 4.5, $2 and $10 for Claude Sonnet 5, $4 and $20 for Claude Opus 5.5, and $10 and $50 for Claude Fable 5.1. Cache reads cost $0.10 to $0.25 per million tokens, and the Batch API halves the input and output rates. **How much does Claude cost per month?** Free is $0, Pro is $20 a month or $17 a month billed annually, Max is $100 (five times Pro usage) or $200 (twenty times), Team is $25 a seat a month or $20 billed annually, with Premium seats at $125 or $100, and Enterprise is $20 a seat a month billed annually plus usage. **What is the difference between Claude Free, Pro and Max?** Pro adds Claude Code, Projects, more models and the Office and browser extensions to Free, with more usage per session. Max keeps every Pro feature and multiplies Pro's per-session usage by five or twenty, with priority access at busy times. Pro and Max limits reset every five hours and also carry a weekly limit. **Is API usage included in Claude Pro or Max?** No. API usage is billed separately through a Claude Console account. Claude Code on a Pro or Max plan uses the plan's allowance unless an &lt;code&gt;ANTHROPIC\_API\_KEY\&lt;/code&gt; environment variable is set, in which case it bills the API. **Is there a free Claude API tier?** Anthropic's pricing page does not list one. The Free plan covers the Claude apps, not the API. **What is the cheapest way to use Claude?** For personal use, the Free plan. For API workloads, Claude Haiku 4.5 through the Batch API at $0.50 input and $2.50 output per million tokens, with prompt caching on any repeated prefix. **Does long context cost more on Claude?** Not on Claude 4.6 and later models, which bill their full 1 million token context window at standard rates. The cost of long context comes from volume: every token in the window is billed on every request that carries it. **How do I estimate my monthly Claude API bill?** Multiply tokens by rate for each part of a request: uncached input, cache writes, cache reads and output, including thinking tokens. For conversations, remember that input per turn grows with the history, as the worked example above shows. Count tokens with the token counting endpoint before launch, then read the &lt;code&gt;usage\&lt;/code&gt; fields on live traffic, which is where a cache that is not hitting will show up. ## What this means for your bill The rate card sets the price of a token, and your architecture sets how many tokens you buy. Prompt caching and the Batch API are the two largest discounts Anthropic offers, and both are configuration rather than engineering. Past that, the bill is decided by how much of each conversation you choose to send again on every turn, which is a design decision about what your product remembers and how. --- *Sources, all retrieved 26 September 2026: [Anthropic pricing documentation](&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/about-claude/pricing&lt;/a&gt;); [Claude plans](&lt;a href="https://claude.com/pricing" rel="noopener noreferrer"&gt;https://claude.com/pricing&lt;/a&gt;); Claude Help Center articles on the [Pro plan](&lt;a href="https://support.claude.com/en/articles/8325606-what-is-the-pro-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/8325606-what-is-the-pro-plan&lt;/a&gt;), the [Max plan](&lt;a href="https://support.claude.com/en/articles/11049741-what-is-the-max-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11049741-what-is-the-max-plan&lt;/a&gt;), [usage limits](&lt;a href="https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11647753-how-do-usage-and-length-limits-work&lt;/a&gt;), [Claude Code on Pro and Max](&lt;a href="https://support.claude.com/en/articles/11145838-use-claude-code-with-your-pro-or-max-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/11145838-use-claude-code-with-your-pro-or-max-plan&lt;/a&gt;) and [the Agent SDK on paid plans](&lt;a href="https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan" rel="noopener noreferrer"&gt;https://support.claude.com/en/articles/15036540-use-the-claude-agent-sdk-with-your-claude-plan&lt;/a&gt;); Claude Platform documentation on [prompt caching](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/prompt-caching&lt;/a&gt;), [extended thinking](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/extended-thinking" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/extended-thinking&lt;/a&gt;) and [context windows](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-windows" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-windows&lt;/a&gt;); Anthropic's announcements of [Claude Opus 5.5](&lt;a href="https://www.anthropic.com/claude-opus-5-5" rel="noopener noreferrer"&gt;https://www.anthropic.com/claude-opus-5-5&lt;/a&gt;), [Claude Sonnet 5](&lt;a href="https://www.anthropic.com/news/claude-sonnet-5" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/claude-sonnet-5&lt;/a&gt;) and [Claude Opus 4.7](&lt;a href="https://www.anthropic.com/news/claude-opus-4-7" rel="noopener noreferrer"&gt;https://www.anthropic.com/news/claude-opus-4-7&lt;/a&gt;). Worked examples are our own arithmetic on those rates.*&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How to Reduce LLM Token Costs in Long Conversations: What Caching Saves, and Where It Stops</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Sat, 26 Sep 2026 09:10:34 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/how-to-reduce-llm-token-costs-in-long-conversations-what-caching-saves-and-where-it-stops-19na</link>
      <guid>https://dev.to/gaurav_dadhich/how-to-reduce-llm-token-costs-in-long-conversations-what-caching-saves-and-where-it-stops-19na</guid>
      <description>&lt;p&gt;# How to Reduce LLM Token Costs in Long Conversations: What Caching Saves, and Where It Stops *Published 26 September 2026 · Prices are Anthropic's list rates as of 26 September 2026. The method behind every cost figure is at the end of the article.* A long conversation costs far more than its number of turns suggests, because a language model holds nothing between calls: every request carries the &lt;a href="https://www.maximem.ai/glossary/system-prompt" rel="noopener noreferrer"&gt;system prompt&lt;/a&gt; and the entire history again, so total input grows with the square of the number of turns. The fixes, in the order to apply them, are &lt;a href="https://www.maximem.ai/glossary/prompt-caching" rel="noopener noreferrer"&gt;prompt caching&lt;/a&gt;, which cut a 40-turn chat on Claude Sonnet 5 from $1.09 to $0.29 in our worked example, then shrinking what each turn adds, then trimming or compacting old turns, and finally bounding the context with a &lt;a href="https://www.maximem.ai/glossary/memory-optimization" rel="noopener noreferrer"&gt;memory layer&lt;/a&gt; once conversations span sessions. Caching loses its grip when users return after the cache has expired, and in our arithmetic a bounded context becomes cheaper than cached full history at around 200 turns and 100,000 tokens of history on Sonnet 5, even after paying for the memory layer itself. The rest of this piece is the arithmetic behind that ordering, including the cases where the cheaper-sounding option is the more expensive one. ## Why a long conversation costs more than its turns An LLM API is stateless. [Anthropic's context window documentation](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-windows" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-windows&lt;/a&gt;) describes each turn's input as "all previous conversation history plus the current user message", with previous turns "preserved completely". If a turn adds S tokens and the system prompt is P tokens, the request at turn k carries roughly P + (k − 1)·S tokens, and a conversation of N turns sends N·P + S·N(N − 1)/2 input tokens in total. The second term is quadratic, and past a handful of turns it is most of the bill. A concrete conversation makes it tangible: a 2,000-token system prompt, 150-token user messages and 350-token replies. Turn 1 sends 2,150 tokens. Turn 40 sends 21,650. The 40-turn conversation consumes 476,000 input tokens to produce 14,000 output tokens, and on [Claude Sonnet 5 at $2 input and $10 output per million tokens](&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/about-claude/pricing&lt;/a&gt;) it costs $1.09, of which 87% is input. Going from 40 to 100 turns multiplies the turns by 2.5 and the bill by 5.2, to $5.73. Two things make the curve steeper on modern models. Thinking tokens are billed as output, and on Claude Opus 4.5 and later, Sonnet 4.6 and later and the Fable and Mythos models, earlier thinking blocks stay in the conversation and count as input on every later turn. In agent loops, tool results do the same: a search result or file read added at turn 5 is paid for again on every turn after it. ## Lever 1: prompt caching, and what it saves Prompt caching stores a prompt prefix so that later requests read it instead of paying full price for it. On Claude, [a 5-minute cache write costs 1.25 times the base input rate and a cache read costs 0.1 times](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/prompt-caching&lt;/a&gt;), with Claude Opus 5.5 reading at 0.05 times and Claude Fable 5.1 at 0.025 times. Automatic caching (a top-level &lt;code&gt;cache\_control\&lt;/code&gt; setting) places the breakpoint on the last cacheable block and moves it forward as the conversation grows, so each turn writes only the new exchange and reads everything before it. For the 40-turn conversation above, that takes the Sonnet 5 cost from $1.09 to $0.29 and the input share of the bill from 87% to about half. It needs no change to what the model sees, which is why it comes first. Cache hits also do not count against your rate limit. The 5-minute cache suits rapid turns and agent loops. The 1-hour cache costs 2 times the input rate to write and pays back from the second reuse, so it suits chat where users pause for more than five minutes but return within the hour. ## Where caching stops working Caching discounts the history; it does not shrink it. Four things limit how far it goes. - **Users leave and come back.** When a user returns after the cache has expired, the first request of the new session writes the entire history again at 1.25 times the input rate. For an assistant used in short sessions over days or weeks, that rewrite happens every session and grows with the history. - **Changes invalidate it.** The cache follows the order tools, then system, then messages. Changing a tool definition invalidates everything; adding an image or changing &lt;code&gt;tool\_choice\&lt;/code&gt; invalidates the message cache. A cache that misses returns no error, so the only place it shows up is &lt;code&gt;cache\_read\_input\_tokens\&lt;/code&gt; in the usage object. - **The window still fills.** Current Claude Opus, Sonnet and Fable models take 1 million tokens, and a cached history counts toward the window at full size. - **Quality does not improve with volume.** Anthropic's own [compaction documentation](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/compaction" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/compaction&lt;/a&gt;) justifies the feature by noting that "response quality degrades as a conversation grows". A cheaper token is still a token the model has to read past. ## Lever 2: shrink what each turn adds Before touching the history, cut what each turn contributes. **Clear old tool results.** Claude's [context editing](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-editing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-editing&lt;/a&gt;) (beta header &lt;code&gt;context-management-2025-06-27\&lt;/code&gt;) clears tool results once the input passes a threshold (100,000 tokens by default) and keeps the three most recent tool uses, replacing the rest with a placeholder. It can also clear old thinking blocks. Clearing breaks the prompt cache at the point it clears, so the &lt;code&gt;clear\_at\_least\&lt;/code&gt; setting exists to make sure each clearing removes enough tokens to be worth a fresh cache write. **Cap output and thinking.** Output costs five times input on current Claude models, and thinking tokens bill as output. A &lt;code&gt;max\_tokens\&lt;/code&gt; limit and a lower effort setting on turns that do not need deep reasoning reduce both what you pay now and what later turns carry. **Route by task.** A summarisation or classification step inside a conversation rarely needs the model that holds the conversation. Claude Haiku 4.5 costs half of Sonnet 5 per token, and anything that can wait belongs on the Batch API at half price. ## Lever 3: trim or compact the history **A sliding window** keeps the last K exchanges and drops the rest. It is free and caps per-turn input, and it forgets everything outside the window, including the user's name if they gave it at turn 2. Keep a pinned block for facts that must survive (identity, standing constraints, open tasks), or the window will drop them. **Compaction** replaces older turns with a summary. Claude now does this server-side: [compaction](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/compaction" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/compaction&lt;/a&gt;) can run on demand or automatically when input tokens reach a threshold you set, with no summarisation code of your own. A summary costs a model call to produce and pays for itself quickly once the history is long, because every later turn reads the summary instead of the transcript. What compaction risks is detail. A summary that turns "takes 20mg of Atorvastatin daily" into "takes a cholesterol medication" has saved tokens and lost the fact that mattered. Whatever compacts your history should tell you what it kept. &lt;a href="https://www.maximem.ai/synap" rel="noopener noreferrer"&gt;Maximem Synap&lt;/a&gt;'s compaction, which we build, returns a validation score and a count of preserved facts on every pass, runs when a conversation passes 3,000 tokens, 10 messages or 5 minutes idle, targets 1,500 tokens, and keeps the last three exchanges verbatim. ## Lever 4: bound the context with a memory layer A memory layer changes the unit that is resent. Instead of replaying the transcript, it extracts what is worth keeping (facts, preferences, decisions, open tasks) as the conversation happens, stores them outside the prompt, and returns a ranked block of the relevant ones within a &lt;a href="https://www.maximem.ai/glossary/token-budget" rel="noopener noreferrer"&gt;token budget&lt;/a&gt; on each turn. Per-turn input stops growing with the history: system prompt, a memory block (2,000 tokens by default in Maximem Synap), the last few exchanges verbatim and the new message. That is not free, and the comparison is only honest if the memory layer's own cost is counted. The table below does that. It uses the same conversation as above, split into sessions of 10 turns with the user returning after the cache has expired, on Sonnet 5. The bounded column includes Maximem Synap's published usage cost for storing each exchange and fetching context every turn (3 credits a turn at $0.00175 a credit). | Conversation length | No caching | Cached, cache cold at each session | Cached, cache never expires | Bounded context, memory layer included | |---|---|---|---|---| | 10 turns, 1 session | $0.12 | $0.06 | $0.06 | $0.16 | | 50 turns, 5 sessions | $1.61 | $0.51 | $0.38 | $0.84 | | 100 turns, 10 sessions | $5.73 | $1.56 | $1.01 | $1.68 | | 200 turns, 20 sessions | $21.46 | $5.27 | $3.01 | $3.37 | | 500 turns, 50 sessions | $128.65 | $29.29 | $15.02 | $8.45 | Read it in both directions. For conversations under about 100 turns, caching alone is cheaper, and a memory layer is not a cost decision there; if you adopt one at that length, adopt it for what it remembers across sessions, not for the bill. Around 200 turns, where the history passes 100,000 tokens, the bounded context overtakes cached history whose cache goes cold between sessions. At 500 turns it costs 29% of the cold-cache figure and 56% of a cache that never expires, and the gap keeps widening because one column grows with the square of the turns and the other grows linearly. The crossover moves with the model. Claude Opus 5.5 reads cache at 0.05 times its input rate, which makes cached history unusually cheap: on Opus 5.5 the bounded context beats the cold-cache case from 200 turns ($5.62 against $8.67) but only beats a cache that never expires at 500 turns ($14.09 against $17.40). An independent cost study, [arXiv 2603.04814](&lt;a href="https://arxiv.org/abs/2603.04814" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2603.04814&lt;/a&gt;), reached a consistent shape on different assumptions: at a 100,000-token context a fact-based memory system became cheaper than long-context prompting after about ten turns, with the break-even arriving sooner as context grows. The same study, with GPT-5-mini answering and a three-vote GPT-5-mini judge, found long-context prompting recalled more facts on two of its three benchmarks, which is the quality trade to test on your own conversations before you move a workload. ## Which technique for which workload | Workload | Start with | Add when | Watch for | |---|---|---|---| | Short chats, one sitting | Prompt caching | Rarely needs more | Silent cache misses | | Agent loops with heavy tool use | Caching plus tool-result clearing | Compaction past the window threshold | Clearing breaking the cache too often | | Long single sessions (research, coding) | Caching, then server-side compaction | A pinned block for facts the summary must keep | Detail lost in summaries | | Assistants people return to over days or weeks | Caching within sessions | A bounded context once histories pass about 100,000 tokens | Retrieval missing a fact the transcript had | | Support or sales agents serving many users | Caching plus a bounded context | Organisation context held separately from user memory | Scoping between users and tenants | ## How to measure it Measure per conversation, not per request. For every turn, log &lt;code&gt;input\_tokens\&lt;/code&gt;, &lt;code&gt;cache\_creation\_input\_tokens\&lt;/code&gt;, &lt;code&gt;cache\_read\_input\_tokens\&lt;/code&gt; and &lt;code&gt;output\_tokens\&lt;/code&gt; from the response, keyed by conversation and session. From that you get the three numbers that matter: cost per conversation by length bucket, cache read share per turn (a sudden drop means something is invalidating the cache), and the input tokens carried at the median and the 95th percentile turn. The distribution matters more than the average, because the longest conversations are where the quadratic term lives. Use the [token counting endpoint](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/token-counting" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/token-counting&lt;/a&gt;) to size prompts before launch. Set a context budget explicitly: the number of tokens a turn is allowed to carry beyond the system prompt. Without one, the budget is whatever the history happens to be, and it only ever grows. ## What this means for pricing your own product If your product charges a flat fee per user, your heaviest users cost you the most, and on unmanaged context they cost you disproportionately more, since a user with five times the conversation length can cost up to roughly twenty-five times as much to serve. Either bound the context so cost per turn stays flat, or price in a way that acknowledges length, through usage tiers or credits. Doing neither means your best-retained customers are your least profitable ones. ## Frequently asked questions **How do I reduce LLM token costs in long conversations?** Turn on prompt caching first; on Claude Sonnet 5 it cut a 40-turn conversation from $1.09 to $0.29 in our example. Then cap output and clear old tool results, compact or trim old turns once a single session runs long, and bound the context with a memory layer for assistants that users return to across sessions, where caching stops helping once the cache expires between visits. **Why do chatbot conversations get more expensive as they go on?** Because the API is stateless, each request resends the system prompt and every previous turn, so input per turn grows with the conversation and total input grows with the square of the number of turns. A 40-turn chat with a 2,000-token system prompt and 500 tokens per exchange sends 476,000 input tokens. **Does prompt caching solve the cost of long conversations?** Within a sitting, mostly. It bills the repeated history at a tenth of the input rate on most Claude models. It does not shrink the history, it has to rewrite the whole history when a user returns after the cache expires, and it does nothing for the &lt;a href="https://www.maximem.ai/glossary/context-window" rel="noopener noreferrer"&gt;context window&lt;/a&gt; limit or for answer quality on very long inputs. **Is summarising the conversation cheaper than sending the full history?** Once the history is long, yes, because every later turn reads the summary instead of the transcript. The risk is losing specific details, so check what each summary kept. **When is a memory layer cheaper than prompt caching?** In our arithmetic on Claude Sonnet 5, at around 200 turns spread over sessions, when the history passes roughly 100,000 tokens, including the memory layer's own cost. Below about 100 turns, caching alone is cheaper. On Claude Opus 5.5, whose cache reads are cheaper, the crossover comes later. **Does reducing context make responses faster?** Every input token has to be processed before the first output token, so a smaller prompt starts answering sooner. Caching reduces cost more than it reduces the amount the model reads, while trimming, compaction and a bounded context reduce both. ## Method Every cost figure comes from one synthetic conversation: a 2,000-token system prompt, 150-token user messages and 350-token replies, priced at Anthropic's list rates on 26 September 2026 (Claude Sonnet 5: $2 input, $10 output, $2.50 for a 5-minute cache write and $0.20 for a cache read per million tokens; Claude Opus 5.5: $4, $20, $5 and $0.20). "Cache warm" and "cache never expires" assume automatic caching where each turn writes the new exchange and reads the prefix. "Cache cold at each session" assumes sessions of 10 turns with the cache expired at the start of each, so the first request of a session writes the full prefix at the write rate. The bounded context sends the system prompt (cached within a session), a 2,000-token memory block, the last three exchanges and the new message at the full input rate, plus Maximem Synap's published usage cost of 3 credits a turn (2 credits to store a 500-token exchange and 1 for a fast context fetch) at the list rate of $0.00175 a credit; plan credits cost less than that. Output cost is included everywhere. Real conversations vary in length and shape, and whether a 2,000-token memory block holds enough for a given product is a quality question this arithmetic does not answer. --- *Sources, retrieved 26 September 2026: [Anthropic pricing](&lt;a href="https://platform.claude.com/docs/en/about-claude/pricing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/about-claude/pricing&lt;/a&gt;); Claude Platform documentation on [context windows](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-windows" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-windows&lt;/a&gt;), [prompt caching](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/prompt-caching" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/prompt-caching&lt;/a&gt;), [compaction](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/compaction" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/compaction&lt;/a&gt;), [context editing](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/context-editing" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/context-editing&lt;/a&gt;), [extended thinking](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/extended-thinking" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/extended-thinking&lt;/a&gt;) and [token counting](&lt;a href="https://platform.claude.com/docs/en/build-with-claude/token-counting" rel="noopener noreferrer"&gt;https://platform.claude.com/docs/en/build-with-claude/token-counting&lt;/a&gt;); Pollertlam and Kornsuwannawit, [Beyond the Context Window](&lt;a href="https://arxiv.org/abs/2603.04814" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2603.04814&lt;/a&gt;), March 2026. Maximem Synap figures come from its published documentation and &lt;a href="https://www.maximem.ai/synap/pricing" rel="noopener noreferrer"&gt;pricing&lt;/a&gt;. For every Claude rate in one place, see [Claude API pricing in 2026](&lt;a href="https://www.maximem.ai/blog/claude-api-pricing-2026).%5C*" rel="noopener noreferrer"&gt;https://www.maximem.ai/blog/claude-api-pricing-2026).\*&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>What is WebMCP? When and How to Use WebMCP in a Browser Agent?</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Wed, 23 Sep 2026 06:37:16 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/what-is-webmcp-when-and-how-to-use-webmcp-in-a-browser-agent-53l0</link>
      <guid>https://dev.to/gaurav_dadhich/what-is-webmcp-when-and-how-to-use-webmcp-in-a-browser-agent-53l0</guid>
      <description>&lt;h1&gt;
  
  
  What is WebMCP? When and How to Use WebMCP in a Browser Agent?
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Published 23 September 2026&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://webmachinelearning.github.io/webmcp/" rel="noopener noreferrer"&gt;WebMCP&lt;/a&gt; lets a web page hand an agent a list of named, typed actions instead of making it work them out from the rendered page. If you already run a scraper or a browser agent, the thing worth knowing before anything else is that the decision to use it is per step, not per site. A page can expose a clean search tool and leave its account settings as ordinary DOM controls, so an agent that picks one mode per domain gets the worst of both. Your existing reader stays primary, WebMCP becomes a fast path in front of it, and the arbitration happens at each step of the task.&lt;/p&gt;

&lt;p&gt;That is the whole architecture. Everything below is what the parts cost you, starting with the one that will eat an afternoon if you take it from a guide written three weeks ago.&lt;/p&gt;

&lt;h2&gt;
  
  
  What WebMCP is
&lt;/h2&gt;

&lt;p&gt;A page calls &lt;code&gt;document.modelContext.registerTool()&lt;/code&gt; with a name, a plain-language description and a JSON Schema for the inputs. Any agent running in that tab can then list what is registered and call it directly. The specification puts it plainly: a page using WebMCP can be thought of as a Model Context Protocol server that implements its tools in client-side script rather than on a backend.&lt;/p&gt;

&lt;p&gt;What it replaces is guessing. An agent today works a site by screenshotting it, reading the DOM or the accessibility tree, inferring which control does what, and simulating clicks; rename a CSS class and the sequence breaks. A registered tool states the contract instead, so &lt;code&gt;search_products&lt;/code&gt; takes a query string and hands back a result, rather than a button somewhere on the page that might be the search button.&lt;/p&gt;

&lt;p&gt;Two properties matter more than the API surface. Tools live in the tab and die on navigation, so they are scoped to the page rather than to your session. They also execute inside the user's existing signed-in session. That is how they reach a cart, a filter state or a half-finished form that a server-side integration would need its own authentication to touch.&lt;/p&gt;

&lt;h2&gt;
  
  
  When it is worth reaching for
&lt;/h2&gt;

&lt;p&gt;Lifetime decides most of it. WebMCP does not replace an MCP server: its tools exist only while the page is open, so anything that must run without a live tab belongs in a server-side capability. Chrome frames the inversion well when it says that instead of your application being a guest inside an agent, the agent becomes a guest on your platform.&lt;/p&gt;

&lt;p&gt;Within that boundary, reach for WebMCP when the action belongs to the page the user already has open and depends on live tab state, which covers a cart, an applied filter, a document being edited, a dashboard date range. Use your existing reader everywhere else, and everywhere else is still most of the web.&lt;/p&gt;

&lt;p&gt;How often the fast path actually fires is genuinely unknown, which is worth settling before you plan around it. Largest published figure is a directory count rather than a crawl, at 462 live sites and demos as of 5 September. Against that, &lt;a href="https://shopify.dev/docs/api/web-mcp" rel="noopener noreferrer"&gt;Shopify&lt;/a&gt; switched tools on for every Liquid storefront effective 21 August, a very large installed base arriving in one step, and Cloudflare's edge bridge lets a site enable it without touching its origin. Nobody has a reliable denominator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with the part that is already stale
&lt;/h2&gt;

&lt;p&gt;Every article-format guide currently published shows this call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That shape no longer validates. A &lt;a href="https://webmachinelearning.github.io/webmcp/" rel="noopener noreferrer"&gt;Draft Community Group Report dated 17 September 2026&lt;/a&gt; defines the second argument as &lt;code&gt;optional any inputObject&lt;/code&gt; and specifies that if it is not an Object, the call returns a promise rejected with a &lt;code&gt;TypeError&lt;/code&gt;; the browser serializes internally. Chrome's &lt;a href="https://developer.chrome.com/docs/ai/webmcp/imperative-api" rel="noopener noreferrer"&gt;imperative API documentation&lt;/a&gt;, last updated 11 September, now documents only the object form and carries a deprecation note on the other: JSON stringified input arguments are deprecated from Chrome 155.&lt;/p&gt;

&lt;p&gt;So the current call passes an object:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executeTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;mechanical keyboard&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;None of those guides were wrong when they published. &lt;a href="https://freshman.tech/webmcp/" rel="noopener noreferrer"&gt;freshman.tech&lt;/a&gt; and &lt;a href="https://flaviocopes.com/webmcp/" rel="noopener noreferrer"&gt;flaviocopes&lt;/a&gt;, both updated 9 September, even flag the divergence and tell you to use whichever form your browser supports; they predate the resolution by about a week. That is the real lesson, and it is worth more than the API detail: published integration guidance in this corner of the platform has a shelf life measured in days, and anything you hardcode from an article inherits it.&lt;/p&gt;

&lt;h2&gt;
  
  
  The four calls you need
&lt;/h2&gt;

&lt;p&gt;Detection first, because two separate gates produce a silent &lt;code&gt;undefined&lt;/code&gt; even on a browser that supports the feature. The page has to be origin-isolated, so a document opting out through &lt;code&gt;document.domain&lt;/code&gt; or an &lt;code&gt;Origin-Agent-Cluster: ?0&lt;/code&gt; response header does not get the API at all, and registration is governed by the &lt;code&gt;tools&lt;/code&gt; Permissions Policy with a default allowlist of &lt;code&gt;self&lt;/code&gt;, which means cross-origin iframes are excluded unless the parent delegates with &lt;code&gt;allow="tools"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;modelContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* use your reader */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Global names have moved too. It was &lt;code&gt;navigator.modelContext&lt;/code&gt;, an earlier draft carried a &lt;code&gt;provideContext()&lt;/code&gt; method since removed, and &lt;code&gt;document.modelContext&lt;/code&gt; is current. If a sample uses either older name, check its date before you trust anything else in it.&lt;/p&gt;

&lt;p&gt;Listing is &lt;code&gt;await document.modelContext.getTools()&lt;/code&gt;. Note the scope carefully, because it decides which API you actually write against: &lt;code&gt;getTools()&lt;/code&gt; is a discovery surface for agents running inside the page, and a browser-integrated agent never calls it, since the browser hands it tools through an internal channel. If you drive a browser from outside, you use your driver instead. &lt;a href="https://docs.stagehand.dev/v3/basics/webmcp" rel="noopener noreferrer"&gt;Stagehand&lt;/a&gt; exposes &lt;code&gt;page.listWebMCPTools()&lt;/code&gt; and &lt;code&gt;page.invokeWebMCPTool()&lt;/code&gt;; &lt;a href="https://github.com/vercel-labs/agent-browser" rel="noopener noreferrer"&gt;agent-browser&lt;/a&gt; exposes &lt;code&gt;webmcp list&lt;/code&gt; and &lt;code&gt;webmcp invoke&lt;/code&gt;; &lt;a href="https://pptr.dev/" rel="noopener noreferrer"&gt;Puppeteer&lt;/a&gt; documents &lt;code&gt;page.webmcp&lt;/code&gt;. Cross-origin listing takes an options bag, &lt;code&gt;getTools({ fromOrigins: ['https://shop.example'] })&lt;/code&gt;, and it only returns anything if the registering page also named your origin in &lt;code&gt;registerTool(tool, { exposedTo: [...] })&lt;/code&gt;. Both keys have to turn.&lt;/p&gt;

&lt;p&gt;Calling is &lt;code&gt;executeTool(tool, inputObject)&lt;/code&gt;, passing the tool object itself rather than its name, and the result comes back as a JSON string even though the input is an object.&lt;/p&gt;

&lt;p&gt;Cancellation is two different mechanisms that are easy to confuse. Registration lifetime rides on an &lt;code&gt;AbortSignal&lt;/code&gt; handed to &lt;code&gt;registerTool(tool, { signal })&lt;/code&gt;, so aborting the controller unregisters the tool. Execution cancellation is separate: &lt;code&gt;execute&lt;/code&gt; receives a signal as its second argument, which you pass through to &lt;code&gt;fetch()&lt;/code&gt;. freshman.tech notes the gap between them, and it is the kind of thing that surfaces in a live demo: as of Chrome 153, unregistering a tool does not cancel an execution already in flight.&lt;/p&gt;

&lt;h2&gt;
  
  
  Per step, not per site
&lt;/h2&gt;

&lt;p&gt;Here is the gap in the published material. Every article-format treatment decides per site or at design time. The one project with genuine per-step arbitration, &lt;a href="https://github.com/aralroca/gui-agent" rel="noopener noreferrer"&gt;gui-agent&lt;/a&gt;, hands the model a single merged tool list of registered WebMCP tools plus synthesized DOM tools, instructs it to prefer the page's tools, and resolves name collisions in favour of the app tool; its decision node reads "Is there a purpose-built WebMCP tool for this step?" That is exactly right, and it is scoped to applications you own, which leaves the reader driving somebody else's site without a published answer.&lt;/p&gt;

&lt;p&gt;Generalising it is not complicated. For each step, match against the tool's name, description and input schema, then fall through to your reader for that step when nothing fits or when you cannot fill the schema from data you already hold. Four conditions send you to the fallback and only one of them is "this site has no WebMCP": no API, no matching tool, a schema you cannot satisfy, or a call that throws. Treat them identically, including when a tool vanishes mid-task, which is normal rather than exceptional given that registrations follow routes and permissions.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://aident.ai/blog/webmcp-vs-mcp-browser-automation" rel="noopener noreferrer"&gt;Aident&lt;/a&gt; comes closest among the articles, with a per-action preference order running from a structured tool contract owned by the application, to a direct API or MCP capability for durable external work, to browser automation for whatever interface remains uninstrumented. Their caveat deserves repeating, because it cuts against the obvious reading: that order is not a universal reliability ranking, and a poorly designed tool can be more dangerous than careful automation.&lt;/p&gt;

&lt;p&gt;For the fallback itself, accessibility-tree-with-refs is the strongest documented default. agent-browser marks its accessibility-tree snapshot as the best option for AI and treats annotated screenshots as optional and secondary, with change thresholds to control token spend; gui-agent builds a compact text snapshot carrying roles, labels, values and stable refs, and states plainly that it needs no screenshots and no multimodal model. Vision costs the most context and is the least stable under redesign.&lt;/p&gt;

&lt;h2&gt;
  
  
  The list moves under you
&lt;/h2&gt;

&lt;p&gt;Tools follow routes, permissions and authentication state, so a catalogue read at page load goes stale quickly. The current spec defines three events, not one: &lt;code&gt;toolchange&lt;/code&gt; when the list changes, &lt;code&gt;toolactivated&lt;/code&gt; when an execution begins, and &lt;code&gt;toolcancel&lt;/code&gt; when one is cancelled. Published guidance covers the first and has not caught up with the other two.&lt;/p&gt;

&lt;p&gt;How you observe changes depends again on where you sit. In-page agents subscribe. External drivers re-list, and Stagehand makes this a guarantee rather than a convention: &lt;code&gt;listWebMCPTools()&lt;/code&gt; returns a fresh snapshot on every call and never reuses tools from a previous page or a previous call. agent-browser pushes catalogue changes into context through a &lt;code&gt;data.webmcp&lt;/code&gt; field and warns about the case that quietly breaks caching, which is that a full record can change while the brief description stays identical, so a previously fetched schema needs refreshing after any catalogue update.&lt;/p&gt;

&lt;p&gt;Annotations are worth reading properly, because there are four and the circulating summaries list three. &lt;code&gt;readOnlyHint&lt;/code&gt; says the tool only reads. &lt;code&gt;untrustedContentHint&lt;/code&gt; says the output contains data the registering author does not trust. &lt;code&gt;consequentialHint&lt;/code&gt; marks actions that are significant, real-world or non-reversible, with booking a flight and transferring money as the spec's own examples. The fourth, &lt;code&gt;debugging&lt;/code&gt;, marks tools meant for developer tooling rather than end-user interaction, and it appears in none of the guides I read. It is spelled &lt;code&gt;debugging&lt;/code&gt;, not &lt;code&gt;debuggingHint&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;One genuinely open question: whether tools registered declaratively through HTML form attributes show up in &lt;code&gt;getTools()&lt;/code&gt; is undefined today. Section 4.3 of the spec reads, in full, that the section is entirely a TODO. The &lt;a href="https://github.com/webmachinelearning/webmcp/blob/main/declarative-api-explainer.md" rel="noopener noreferrer"&gt;declarative explainer&lt;/a&gt; addresses the exact question and leaves it open, saying that declarative tools should almost certainly be invokable from that interface but the details are still to be determined. Chrome's declarative documentation, the stalest WebMCP page at 18 May, documents the attributes without stating the answer. Plan for imperative registration and treat declarative discovery as unavailable until the TODO closes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting it to run at all
&lt;/h2&gt;

&lt;p&gt;For local development, enable &lt;code&gt;chrome://flags/#enable-webmcp-testing&lt;/code&gt; and relaunch. For production traffic, the origin trial received approval for &lt;a href="https://groups.google.com/a/chromium.org/g/blink-dev/c/gmYffo5WOE8" rel="noopener noreferrer"&gt;Chrome M149 through M156 inclusive&lt;/a&gt;, with shipping estimated at 157; Edge runs a parallel trial from 150 that expires 17 November 2026. If you drive Chrome externally over DevTools you also need launch features, and Stagehand is the only source that prints them: Chrome or Chromium newer than 149, launched with &lt;code&gt;--enable-features=WebMCPTesting,DevToolsWebMCPSupport&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Skip &lt;a href="https://chromestatus.com/feature/5117755740913664" rel="noopener noreferrer"&gt;ChromeStatus&lt;/a&gt; as a source on current state; that record was last edited 12 August and still reports the feature as proposed with no origin trial and no engine signals, which the live trial and the filed positions both contradict.&lt;/p&gt;

&lt;p&gt;Headless agents cannot reach the API directly, since it lives in a live tab, and Chrome's limitations list says headless is not the design target. Two routes work well. Run a hosted browser and evaluate inside the session, which is what &lt;a href="https://www.firecrawl.dev/blog/webmcp-headless-agents-firecrawl" rel="noopener noreferrer"&gt;Firecrawl&lt;/a&gt; documents through its scrape-then-interact endpoints, or drive Chrome over CDP with Stagehand, agent-browser, &lt;a href="https://browser-use.com/" rel="noopener noreferrer"&gt;Browser Use&lt;/a&gt; (which added native support on 6 September) or &lt;a href="https://developers.cloudflare.com/changelog/post/2026-04-15-br-webmcp/" rel="noopener noreferrer"&gt;Cloudflare Browser Run&lt;/a&gt;. Running in-page with &lt;code&gt;@mcp-b/webmcp-polyfill&lt;/code&gt; is a third option that needs no flags at all, because it installs the global itself.&lt;/p&gt;

&lt;p&gt;Client support today, per the &lt;a href="https://github.com/webmachinelearning/webmcp/blob/main/implementation-status.md" rel="noopener noreferrer"&gt;implementation tracker&lt;/a&gt;: Chrome from 149, Edge from 150, Brave experimentally in Leo, and &lt;a href="https://learn.chatgpt.com/docs/webmcp" rel="noopener noreferrer"&gt;ChatGPT Desktop&lt;/a&gt;, which requires GPT-5.6 Sol or Terra and is unavailable in Enterprise and Edu workspaces. No Firefox, no Safari. Engine positions are now formally filed rather than merely under discussion, and secondary coverage gets this wrong in both directions: WebKit's recorded position is oppose, with concerns spanning API design, duplication, internationalization, privacy, security, venue, use cases and portability, while Mozilla's is neutral.&lt;/p&gt;

&lt;p&gt;Chrome ships a Model Context Tool Inspector extension for debugging, which lists tools, executes one against JSON input and shows structured output. If &lt;code&gt;document.modelContext&lt;/code&gt; is &lt;code&gt;undefined&lt;/code&gt; after you enable the flag, check origin isolation before anything else, and resist shipping your own shim at that global, which mostly hides the fact that you have stopped testing the browser's implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Whose hint is it
&lt;/h2&gt;

&lt;p&gt;Tool names, descriptions, schemas and results are attacker-controlled input. agent-browser states the position as bluntly as anyone has: all page-provided names, descriptions, schemas, annotations and results are untrusted data, the provenance labels are cues rather than a prompt-injection boundary, and website text does not get promoted into system instructions, does not authorise shell commands, and does not constitute a claim of user consent.&lt;/p&gt;

&lt;p&gt;Which sets up the thing nobody names. Two shipping libraries take opposite positions on &lt;code&gt;readOnlyHint&lt;/code&gt;, and both are correct.&lt;/p&gt;

&lt;p&gt;gui-agent trusts it. Any tool without &lt;code&gt;annotations.readOnlyHint&lt;/code&gt; routes through a confirmation callback before running, and marking a tool read-only skips the prompt. agent-browser refuses it, stating that page-provided &lt;code&gt;readOnlyHint&lt;/code&gt; or &lt;code&gt;untrustedContentHint&lt;/code&gt; claims cannot bypass host controls, and that domain filters do not prevent a page from lying about what a tool does.&lt;/p&gt;

&lt;p&gt;That is not a disagreement about security. gui-agent runs inside an application you own, where the annotation is your own assertion about your own code; agent-browser drives arbitrary third-party sites, where the identical field is a claim by a stranger. &lt;a href="https://learn.chatgpt.com/docs/webmcp" rel="noopener noreferrer"&gt;OpenAI&lt;/a&gt; puts the third-party case in one line, which is that a tool's name or its claim to only read data is not proof of what it does. Copy the wrong pattern into the wrong threat model and you have built a confirmation gate any page can switch off by setting a boolean.&lt;/p&gt;

&lt;p&gt;Schemas do not help here either. &lt;a href="https://lite.ego.app/article/webmcp-vs-browser-automation" rel="noopener noreferrer"&gt;Ego&lt;/a&gt; ran the Chrome Labs hotel demo on 11 September in Chrome 152.0.7977.76 and found an out-of-enum value passing schema validation and reaching the application route. A schema shapes input; it does not prove the request is authorised, and it never will, because it is advisory to whoever is calling.&lt;/p&gt;

&lt;p&gt;What to actually build, drawing on &lt;a href="https://developer.chrome.com/docs/agents/security" rel="noopener noreferrer"&gt;Chrome's agent security guidance&lt;/a&gt;: cap inbound tool-response size and reject oversized payloads rather than truncating them into context; restrict callable origins to those relevant to the current task; wrap tool output so the model reads it as data rather than instruction; require confirmation for consequential actions by your own policy rather than the page's annotation; keep credentials and personal data out of tool arguments unless the tool genuinely needs them; and log origin, tool name, arguments and whether each step came from WebMCP or the fallback, because after an incident the question you will need to answer is which page told you to do that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it worth it
&lt;/h2&gt;

&lt;p&gt;One public benchmark exists, and the disclosure belongs before the numbers. &lt;a href="https://github.com/nekuda-ai/WindTunnel" rel="noopener noreferrer"&gt;WindTunnel&lt;/a&gt; is published by nekuda, which sells WebMCP products including AgentLane, a WebMCP Kit, a Chrome extension and an SDK, and which also operates the site hosting the leaderboard. The benchmark measures the interface its product line depends on.&lt;/p&gt;

&lt;p&gt;Their method is better than that framing might suggest. The harness is public under Apache-2.0, covering 49 tasks across 8 self-hosted open-source applications pinned to upstream commits, three attempts per task scored by majority verdict, with agent models including Claude Sonnet 5, Claude Opus 5, GPT-5.6 Luna, GPT-5.6 Sol, GPT-6 Astra and Gemini 3.6 Flash. No judge model is involved; scoring is a code check against real post-run application state. Current board is version 1.2, dated 18 September, at 21 configurations and 3,087 attempt rows.&lt;/p&gt;

&lt;p&gt;What it shows now is narrower than what gets quoted. Ten configurations solve 49 of 49: all nine WebMCP ones, plus GPT-6 Astra on code execution, which is a screen-driving mode. Take the median of the twelve non-WebMCP rows on the published board and it comes to 44, though the README does not print that figure itself. nekuda's own text concedes the shift: raw task-solve rate does not separate WebMCP from the best screen-driving configuration, and cost and time do. The same README discloses that projected per-thousand-run cost ranges overlap, that two drivers cannot report the model snapshot served, and that an independent review caught a merge built before corrected predicates were applied, requiring a re-score that produced nineteen false-negative promotions.&lt;/p&gt;

&lt;p&gt;Two figures in wide circulation should stop circulating. "48 of 49 against a median of 43" is the August board, retired on 6 September when a missing checkout tool in one demo store was fixed; by nekuda's own account that gap made 48 a ceiling by construction, a limitation of one store's tool surface rather than of the approach. And the pairing of 7.8 seconds against 28.1, at 0.6 cents against 5.5, matches no table currently published on either the original post or the live board. I could not source it, so I am not repeating it as fact.&lt;/p&gt;

&lt;p&gt;A quieter argument is the token bill, and exactly one project treats it seriously. agent-browser withholds schemas by default, requiring a two-stage fetch where the agent picks from a summary and then requests the single schema it needs, and it hard-budgets those summaries to sixteen tools and four kilobytes with descriptions cut to a hundred and sixty bytes. Sites can register a lot of tools; on the fallback side, a page dump or a screenshot per step is precisely what makes screen-driving expensive.&lt;/p&gt;

&lt;h2&gt;
  
  
  What breaks next
&lt;/h2&gt;

&lt;p&gt;The spec is a Community Group draft. It is not a W3C Standard and it is not on the Standards Track. Since February the global has been renamed, a method has been removed, the argument shape of &lt;code&gt;executeTool&lt;/code&gt; has changed, and the declarative section sits unwritten. Tool outputs, dynamic definitions, long-running execution and cross-document discovery are all listed by the spec itself as still moving, which is four more renames waiting to happen.&lt;/p&gt;

&lt;p&gt;Which is the argument for keeping the volatile surface in one adapter that detects, lists, calls and normalises the result, and letting the rest of your agent talk only to that adapter. When the surface moves, and it will, you change one file rather than auditing every call site. The same reasoning applies to any integration instructions you hand a coding agent: point it at the spec and at Chrome's documentation rather than hardcoding method names, because a prompt containing a method name goes stale at exactly the speed an article does.&lt;/p&gt;

&lt;p&gt;Getting the arbitration right pays off in a way that has little to do with whether any particular site adopts the standard. Your agent stops paying for a screenshot on the steps where a page has already told it what it can do, and keeps working normally everywhere else. That is the only version of this that survives the next rename. It is also the version that shows up on the inference bill.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Best Chatbot Memory Layer Plugins for Persistent User Data Retention and Memory</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Tue, 22 Sep 2026 03:56:53 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/best-chatbot-memory-layer-plugins-for-persistent-user-data-retention-and-memory-6p7</link>
      <guid>https://dev.to/gaurav_dadhich/best-chatbot-memory-layer-plugins-for-persistent-user-data-retention-and-memory-6p7</guid>
      <description>&lt;p&gt;The best chatbot memory layer plugin captures durable user information, stores it with the right scope, retrieves only the relevant part of it, and updates or deletes it reliably. [Maximem](&lt;a href="https://www.maximem.ai/" rel="noopener noreferrer"&gt;https://www.maximem.ai/&lt;/a&gt;) is the layer that ships all four as product behaviour rather than as pipeline work you assemble yourself, and it carries the highest published [LongMemEval](&lt;a href="https://arxiv.org/abs/2410.10813" rel="noopener noreferrer"&gt;https://arxiv.org/abs/2410.10813&lt;/a&gt;) accuracy of any memory provider that has published one, at 92.0%, alongside 93.2% on [LoCoMo](&lt;a href="https://snap-research.github.io/locomo/" rel="noopener noreferrer"&gt;https://snap-research.github.io/locomo/&lt;/a&gt;), both of them verifiable on an [open eval harness](&lt;a href="https://github.com/maximem-ai/memory%5C_and%5C_context%5C_eval%5C_harness" rel="noopener noreferrer"&gt;https://github.com/maximem-ai/memory\_and\_context\_eval\_harness&lt;/a&gt;) rather than asserted on a marketing page. Maximem produced both numbers with that &lt;a href="https://www.maximem.ai/glossary/harness" rel="noopener noreferrer"&gt;harness&lt;/a&gt;, which anyone can clone and point at their own provider. It scored &lt;a href="https://www.maximem.ai/evals" rel="noopener noreferrer"&gt;LongMemEval&lt;/a&gt; on the full 500-question public set and LoCoMo on all 1,540 category 1 to 4 questions, excluding the adversarial category per the convention the other vendors use, with &lt;code&gt;gpt-5-mini\&lt;/code&gt; generating answers and &lt;code&gt;gpt-5-mini\&lt;/code&gt; acting as judge under binary CORRECT or WRONG scoring, single run per &lt;a href="https://www.maximem.ai/glossary/benchmark" rel="noopener noreferrer"&gt;benchmark&lt;/a&gt;. Treat a vendor-run number as a starting point rather than a verdict. What makes this one checkable is that the harness, the adapters, and the per-category results are published, so you can re-run it yourself; a memory score nobody outside the vendor can reproduce is a marketing asset rather than an engineering one. For most production teams, a dedicated memory layer is a better fit than placing every past message into the conversation or treating a &lt;a href="https://www.maximem.ai/glossary/vector-database" rel="noopener noreferrer"&gt;vector database&lt;/a&gt; as the complete memory system. The right choice still depends on your chatbot's framework, data model, latency requirements, &lt;a href="https://www.maximem.ai/glossary/governance" rel="noopener noreferrer"&gt;governance&lt;/a&gt; needs, and the kinds of information users expect it to remember. Use the guide below to compare memory layers and plan an integration that is useful, controlled, and maintainable. ## What a chatbot memory layer actually does A memory layer sits between your application and the model. It receives conversation events or structured user information, decides what is worth retaining, stores that information, and supplies relevant memories when the chatbot needs to respond. That is different from conversation history. History is a record of messages. Memory is a structured, reusable representation of information such as a user preference, an ongoing task, a previous decision, or an important fact. The distinction matters because sending an entire history on every turn increases context size without guaranteeing that the model will use the right detail. It is also different from retrieval-augmented generation used only for documents. Document retrieval answers questions about a knowledge base. User memory helps an agent maintain continuity across sessions and interactions. A strong chatbot may use both, but they should not be confused. When comparing plugins, look for support for the complete memory lifecycle: - **Capture:** accepting messages, events, profile fields, and application data. - **Extraction:** turning raw interactions into concise, useful memories. - **Storage:** keeping memories persistent and isolated by user, tenant, agent, or application. - **Recall:** returning relevant context at response time. - **Update:** revising a memory when newer information changes it. - **Deletion:** removing a memory when the user or application requests it. - **Inspection:** allowing your team to understand what was retained and why. A plugin that only performs &lt;a href="https://www.maximem.ai/glossary/semantic-search" rel="noopener noreferrer"&gt;semantic search&lt;/a&gt; over old messages may be useful, but it is not a complete retention strategy. &lt;a href="https://www.maximem.ai/synap" rel="noopener noreferrer"&gt;Maximem covers the day-to-day half of that lifecycle&lt;/a&gt; behind two calls. Ingestion goes through &lt;code&gt;memories.create\&lt;/code&gt;, which runs extraction, &lt;a href="https://www.maximem.ai/how-agent-memory-works" rel="noopener noreferrer"&gt;entity resolution&lt;/a&gt;, and relationship mapping, and recall goes through &lt;code&gt;conversation.context.fetch\&lt;/code&gt;, which assembles ranked context for the current turn. Everything between those two calls, the vector store, the graph, the extraction pipeline, and the ranker, is operated for you rather than handed to you as components to tune. ## The capabilities to prioritize in a plugin ### 1. Clear memory types and scopes Persistent data should not be stored as one undifferentiated stream. A user's preferred writing style, a temporary support issue, and an organization-level policy have different lifetimes and access rules. Choose a layer that lets you distinguish user, session, agent, application, and organization scope where appropriate. It should also support useful categories such as facts, preferences, episodes, and time-sensitive information. Explicit types make retention easier to review and help reduce the chance that private information is exposed to the wrong agent or tenant. Maximem models this as four scope levels, USER, CUSTOMER, CLIENT, and WORLD, where wider scopes are visible to narrower ones and never the reverse. Scope is decided at write time by which identifiers you pass, so &lt;code&gt;user\_id\&lt;/code&gt; with &lt;code&gt;customer\_id\&lt;/code&gt; writes a memory private to that person inside that tenant, &lt;code&gt;customer\_id\&lt;/code&gt; alone writes organization-shared knowledge, and passing neither writes an application-wide fact. The extraction pipeline produces five typed memory categories, facts with confidence scores, preferences with strength and direction, episodes with significance scores, emotions with intensity, and temporal events covering deadlines, recurring events, and point-in-time occurrences, which is what allows retention review to happen by category rather than by keyword search over a blob. ### 2. Retrieval that is selective and explainable The plugin should return the smallest useful set of memories for the current task, rather than replaying everything it knows. Ask how it ranks memories, handles recency, resolves related entities, and deals with conflicting information. A practical test is to create a small evaluation set: a returning user changes a preference, refers to an earlier project, uses a nickname, or asks the chatbot to forget something. Measure whether the correct memory is recalled, whether an outdated memory is replaced, and whether unrelated user data stays out of the response context. Also check whether developers can inspect retrieved context during testing. Debuggable retrieval is important because a chatbot can appear inconsistent when the underlying problem is incorrect memory selection. Maximem gives you two retrieval modes on the same store. Fast mode runs vector plus graph retrieval with no LLM query decomposition and is the default for anything in the conversation hot path; accurate mode adds LLM subquery decomposition and reranking across similarity, recency, graph centrality, and confidence, which suits background jobs and multi-entity questions. Nicknames and aliases are handled by entity resolution rather than by luck: when a person is called "John", "Mr. Smith", and "my manager" across different sessions, exact, alias, semantic, and contextual matching collapse those mentions into one canonical entity, and genuinely ambiguous matches can be queued for human review instead of being merged silently. Conflicting facts resolve by scope priority, so a user-level statement wins over an organization-level default. ### 3. Explicit controls for retention and deletion "Persistent" should never mean "permanent by default." Your application needs a retention policy that defines what may be saved, how long it remains useful, and what happens when a user corrects or deletes it. Look for APIs or events for adding, searching, updating, and deleting memories. Confirm that deletion can be limited to one memory, one user, one workspace, or another appropriate boundary. A useful integration is designed to let you exclude selected fields or conversation types from memory before they are stored. Keep transient context separate from durable memory. A one-time request may help the current response without deserving storage. This separation gives product and security teams a clearer way to review what the chatbot retains. Maximem separates ordinary deletion from erasure, and the distinction is the one that matters for a data subject request. Deletion removes data through the normal path; erasure destroys the protected values irreversibly so they stop resolving everywhere at once, including in earlier backups, and it runs in two stages, a preview that reports exactly how many protected values would be destroyed, then an erase that executes only if the count still matches. Erasure is not a self-service button: you email &lt;a href="mailto:privacy@maximem.ai"&gt;privacy@maximem.ai&lt;/a&gt; with the instance, the identifier to erase, and the reason, and Maximem runs it as a support-operated action. An audit entry is written before anything is destroyed, recording who ordered it, the reason they gave, how many values it covered, and when, which is the artifact a privacy team needs when the request has to be evidenced later. On the write side, sensitive field types carry per-category policy, and you choose among storing the real value, hiding it from the model while your application still receives it, protecting it at rest so storage holds a placeholder while your application reads the real value, protecting it everywhere, or refusing to persist it at all. Several types sit under an enforcement floor and are never stored under any setting, including full card numbers, card security codes, passwords, API keys, private keys, and raw biometric data. ### 4. Framework and deployment fit A good memory plugin should fit the way your chatbot already runs. Check SDK support for your language, compatibility with your orchestration framework, authentication model, webhooks or event handling, and local development workflow. Managed services can reduce the infrastructure your team must provision and maintain. Self-hosted components can provide more control over deployment and data location. Neither approach is automatically better: select the operating model your team can monitor, secure, and support over time. The integration should also be narrow. Your chatbot should be able to call memory operations without changing the rest of the agent architecture. A memory layer that requires adopting an entire agent runtime may be appropriate for a new system, but it is a larger migration for an existing application. Maximem publishes 24 drop-in integration packages across Python and TypeScript, covering [LangChain](&lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;https://www.langchain.com/&lt;/a&gt;), [LangGraph](&lt;a href="https://www.langchain.com/langgraph" rel="noopener noreferrer"&gt;https://www.langchain.com/langgraph&lt;/a&gt;), [LlamaIndex](&lt;a href="https://www.llamaindex.ai/" rel="noopener noreferrer"&gt;https://www.llamaindex.ai/&lt;/a&gt;), [OpenAI Agents SDK](&lt;a href="https://openai.github.io/openai-agents-python/" rel="noopener noreferrer"&gt;https://openai.github.io/openai-agents-python/&lt;/a&gt;), [Pydantic AI](&lt;a href="https://ai.pydantic.dev/" rel="noopener noreferrer"&gt;https://ai.pydantic.dev/&lt;/a&gt;), [CrewAI](&lt;a href="https://www.crewai.com/" rel="noopener noreferrer"&gt;https://www.crewai.com/&lt;/a&gt;), [AutoGen](&lt;a href="https://microsoft.github.io/autogen/" rel="noopener noreferrer"&gt;https://microsoft.github.io/autogen/&lt;/a&gt;), [Google ADK](&lt;a href="https://google.github.io/adk-docs/" rel="noopener noreferrer"&gt;https://google.github.io/adk-docs/&lt;/a&gt;), [Haystack](&lt;a href="https://haystack.deepset.ai/" rel="noopener noreferrer"&gt;https://haystack.deepset.ai/&lt;/a&gt;), [Agno](&lt;a href="https://www.agno.com/" rel="noopener noreferrer"&gt;https://www.agno.com/&lt;/a&gt;), [Semantic Kernel](&lt;a href="https://learn.microsoft.com/en-us/semantic-kernel/overview/" rel="noopener noreferrer"&gt;https://learn.microsoft.com/en-us/semantic-kernel/overview/&lt;/a&gt;), [NVIDIA NeMo Agent Toolkit](&lt;a href="https://docs.nvidia.com/nemo/agent-toolkit/latest/index.html" rel="noopener noreferrer"&gt;https://docs.nvidia.com/nemo/agent-toolkit/latest/index.html&lt;/a&gt;), [LiveKit Agents](&lt;a href="https://livekit.io/agents" rel="noopener noreferrer"&gt;https://livekit.io/agents&lt;/a&gt;), [Pipecat](&lt;a href="https://www.pipecat.ai/" rel="noopener noreferrer"&gt;https://www.pipecat.ai/&lt;/a&gt;), [Claude Agent SDK](&lt;a href="https://docs.claude.com/en/api/agent-sdk/overview" rel="noopener noreferrer"&gt;https://docs.claude.com/en/api/agent-sdk/overview&lt;/a&gt;), [Mastra](&lt;a href="https://mastra.ai/" rel="noopener noreferrer"&gt;https://mastra.ai/&lt;/a&gt;), and the [Vercel AI SDK](&lt;a href="https://ai-sdk.dev/" rel="noopener noreferrer"&gt;https://ai-sdk.dev/&lt;/a&gt;) among others, plus an MCP server for no-code clients that needs only a URL and a token. Every package shares one failure contract, which is the part worth reading before you pick: a failed context fetch returns an empty result and logs the error so the agent keeps answering, while a failed ingestion raises an explicit error so you know persistence did not happen. Teams moving off an existing layer have documented migration paths from Mem0, Zep, Letta, and Supermemory, and teams whose retention rules do not fit the default shape can configure a customized memory architecture per deployment. ### 5. Governance and data isolation Persistent user data creates responsibilities beyond retrieval quality. Review tenant isolation, access controls, auditability, encryption details, administrative roles, and the provider's data-handling terms before moving real user data into a service. Design memory boundaries in your own application as well. Pass a stable internal user identifier rather than relying on an email address when possible. Attach tenant or workspace scope to every operation, and test that a user cannot retrieve another user's memories through an altered request. Treat memory as application data, not as invisible model state. It should have an owner, a purpose, an access path, and a removal process. Maximem enforces isolation in three layers, with a logical storage namespace per instance, scope-based retrieval that never returns another user's memories, and network isolation per region. The guard that saves teams in practice is the one at the API boundary: on a B2B instance, forgetting &lt;code&gt;customer\_id\&lt;/code&gt; on a write raises an error rather than quietly writing a memory to the wrong scope, and a B2C instance rejects &lt;code&gt;customer\_id\&lt;/code&gt; outright. Traffic runs over TLS 1.3, with AES-256 at rest for the vector and graph stores and API keys hashed before storage. Region is fixed at client creation, between US East and EU Central, and memories stay in that region for their whole lifecycle. GDPR compliance is in place with a DPA available on request, SOC 2 Type II is in progress with audit completion targeted for Q3 2026, and every dashboard and SDK action is logged with a correlation id, principal, timestamp, action, and resource. ## A practical integration pattern Start with an allowlist of information the chatbot is permitted to remember. For example, you might allow explicit preferences and ongoing project details while excluding payment information, authentication secrets, and sensitive free-text content unless there is a documented reason to retain them. Then connect the memory layer at two points: - **After an interaction:** send the relevant message pair, event, or structured update for extraction and storage. Do not automatically save every internal chain or tool response. - **Before a response:** query memory using the current user, tenant, agent, and task context. Insert the returned memories into a clearly separated context block rather than blending them indistinguishably into the user's message. With Maximem, those two points are two calls: &lt;code&gt;\&lt;/code&gt;&lt;code&gt;python # After an interaction: store what is worth remembering await sdk.memories.create( document="User: I prefer dark mode and weekly digests.\\nAssistant: Noted.", document\_type="ai-chat-conversation", user\_id="internal-uuid-1234", customer\_id="acme", # tenant scope on a B2B instance mode="long-range", # full extraction, entity resolution, relationships ) # Before a response: fetch only what this turn needs context = await sdk.conversation.context.fetch( conversation\_id=conversation\_uuid, search\_query=\["display preferences", "digest cadence"\], max\_results=10, mode="fast", # hot path: vector plus graph, no LLM decomposition ) \&lt;/code&gt;&lt;code&gt;\&lt;/code&gt; Long conversations get compaction rather than a bigger prompt. Once turns are being recorded through &lt;code&gt;conversation.record\_message\&lt;/code&gt;, compaction reduces that history to a token budget while keeping the facts, the decisions, the preferences, and the narrative thread, with strategies that land between roughly 15% and 70% of the original token count depending on how aggressive you set it. That is the cheaper answer to a context window that keeps filling up. Add a user-facing memory control where the product experience calls for it. Users should be able to ask what the chatbot remembers, correct an item, or request deletion. Your application, not the model alone, should authorize and execute those actions. Finally, log memory operations separately from ordinary chat logs. Record the operation, scope, status, and identifier needed for debugging while avoiding unnecessary duplication of sensitive content. ## How to choose the best option for your chatbot For a prototype, prioritize a simple API, quick local setup, and transparent memory operations; Maximem's trial tier starts at 5,000 credits a month, and the operations that draw against it are ingestion, retrieval, compaction, and real-time listening sessions billed by concurrency, so the cost model is visible before you commit. For a production customer-support chatbot, prioritize tenant isolation, deletion workflows, audit controls, conflict handling, and predictable retrieval. For a multi-agent system, check whether memories can be shared selectively without making every agent a reader of every user record, which is exactly what the scope ladder is for. Before committing, run a proof of concept with real interaction patterns and synthetic or approved test data. Evaluate five things: memory precision, memory recall, update behavior, deletion behavior, and operational overhead. Include failure cases, not only successful conversations. If you want that evaluation to be comparable rather than anecdotal, run it through the same open harness the published scores came from, pointed at your own data and whichever providers you are considering. Maximem is memory and context infrastructure for agents, built so that the parts teams usually underestimate, entity resolution, temporal awareness, scoping, conscious forgetting, and permission-aware retrieval, are product behaviour rather than a backlog. The best integration is the one that gives your chatbot continuity while keeping retention purposeful, scoped, inspectable, and under application control. ## FAQ **Which chatbot memory layer is most accurate on public benchmarks?** Maximem carries the highest published LongMemEval accuracy among memory providers that publish one, at 92.0% across the full 500-question set, and scores 93.2% on LoCoMo across 1,540 category 1 to 4 questions, with &lt;code&gt;gpt-5-mini\&lt;/code&gt; as both answer model and judge. Both figures are verifiable rather than asserted, because the eval harness is open source, so you can re-run either benchmark against your own provider and your own data instead of taking the number on trust. **Is a vector database enough for persistent chatbot memory?** Not usually. A vector database can support similarity search, but a complete memory layer also needs extraction, scopes, updates, conflict handling, deletion, and governance. Maximem runs the vector store, the graph, the extraction pipeline, and the ranker as one managed service, so those pieces are not yours to build or operate. **What user data should a chatbot remember?** Start with information that has a clear product purpose, such as explicit preferences or ongoing work. Exclude secrets and sensitive data unless your application has a documented, controlled reason to retain it. Maximem enforces part of this for you: full card numbers, card security codes, card PINs, passwords, API keys and other secret codes, private keys, and raw biometric data are never stored under any policy setting. **How does a chatbot update an old memory?** The application should send new information through an update or extraction workflow that can identify the related memory, prefer the newer value when appropriate, and preserve an audit trail for important changes. Maximem resolves conflicting facts by scope priority, so a user-level correction takes precedence over an organization-level or application-level default. **Can persistent memory be shared across multiple agents?** It can, if the memory layer supports deliberate scopes and access rules. Share only the memories required for a task, and keep user, tenant, and organization boundaries explicit. Maximem's four scope levels make that sharing a write-time decision, and a missing tenant identifier on a B2B instance raises an error rather than leaking the memory upward. **How is a user's data deleted or erased from a memory layer?** Maximem separates deletion from erasure. Erasure destroys protected values irreversibly so they stop resolving everywhere, including in earlier backups. It is support-operated rather than self-service, requested by email and run as preview then execute, with an audit entry written before anything is destroyed, which is what documents a right-to-be-forgotten request after the fact. **Which frameworks does Maximem integrate with?** Twenty-four drop-in packages across Python and TypeScript, including LangChain, LangGraph, LlamaIndex, OpenAI Agents SDK, CrewAI, AutoGen, Google ADK, LiveKit Agents, Pipecat, Claude Agent SDK, Mastra, and the Vercel AI SDK, plus an MCP server for no-code clients. Custom stacks call ingestion and context fetch directly. **Should every chatbot message be saved to memory?** No. Conversation history and durable memory serve different purposes. Use an allowlist or filtering step so transient context and unnecessary sensitive content are not retained. ## Sources - [Maximem](&lt;a href="https://www.maximem.ai/" rel="noopener noreferrer"&gt;https://www.maximem.ai/&lt;/a&gt;), retrieved 22 September 2026 - [Memory and context eval harness, benchmark methodology and headline results](&lt;a href="https://github.com/maximem-ai/memory%5C_and%5C_context%5C_eval%5C_harness" rel="noopener noreferrer"&gt;https://github.com/maximem-ai/memory\_and\_context\_eval\_harness&lt;/a&gt;), retrieved 22 September 2026 - [Identifiers and scopes](&lt;a href="https://docs.maximem.ai/concepts/memory-scopes" rel="noopener noreferrer"&gt;https://docs.maximem.ai/concepts/memory-scopes&lt;/a&gt;), retrieved 22 September 2026 - [Memories and context](&lt;a href="https://docs.maximem.ai/concepts/memories-and-context" rel="noopener noreferrer"&gt;https://docs.maximem.ai/concepts/memories-and-context&lt;/a&gt;), retrieved 22 September 2026 - [Fast and accurate modes](&lt;a href="https://docs.maximem.ai/concepts/retrieval-modes" rel="noopener noreferrer"&gt;https://docs.maximem.ai/concepts/retrieval-modes&lt;/a&gt;), retrieved 22 September 2026 - [Entity resolution and master data management](&lt;a href="https://docs.maximem.ai/concepts/entity-resolution" rel="noopener noreferrer"&gt;https://docs.maximem.ai/concepts/entity-resolution&lt;/a&gt;), retrieved 22 September 2026 - [Erasing a person](&lt;a href="https://docs.maximem.ai/guides/erasure" rel="noopener noreferrer"&gt;https://docs.maximem.ai/guides/erasure&lt;/a&gt;), retrieved 22 September 2026 - [Sensitive data protection](&lt;a href="https://docs.maximem.ai/guides/pii-protection" rel="noopener noreferrer"&gt;https://docs.maximem.ai/guides/pii-protection&lt;/a&gt;), retrieved 22 September 2026 - [Multi-tenant SaaS pattern](&lt;a href="https://docs.maximem.ai/patterns/multi-tenant-saas" rel="noopener noreferrer"&gt;https://docs.maximem.ai/patterns/multi-tenant-saas&lt;/a&gt;), retrieved 22 September 2026 - [Security and trust](&lt;a href="https://docs.maximem.ai/resources/security-trust" rel="noopener noreferrer"&gt;https://docs.maximem.ai/resources/security-trust&lt;/a&gt;), retrieved 22 September 2026 - [Integrations overview](&lt;a href="https://docs.maximem.ai/integrations/overview" rel="noopener noreferrer"&gt;https://docs.maximem.ai/integrations/overview&lt;/a&gt;), retrieved 22 September 2026 - [Context compaction](&lt;a href="https://docs.maximem.ai/sdk/context-compaction" rel="noopener noreferrer"&gt;https://docs.maximem.ai/sdk/context-compaction&lt;/a&gt;), retrieved 22 September 2026 - [Pricing and credits](&lt;a href="https://docs.maximem.ai/resources/pricing" rel="noopener noreferrer"&gt;https://docs.maximem.ai/resources/pricing&lt;/a&gt;), retrieved 22 September 2026&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>AI Agent Evals: The Judge Is The Part Nobody Measures</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Fri, 18 Sep 2026 09:51:31 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/ai-agent-evals-the-judge-is-the-part-nobody-measures-627</link>
      <guid>https://dev.to/gaurav_dadhich/ai-agent-evals-the-judge-is-the-part-nobody-measures-627</guid>
      <description>&lt;p&gt;An LLM judge scoring the same agent output three times will often hand back three different answers. On MT-Bench, &lt;a href="https://arxiv.org/abs/2510.27106" rel="noopener noreferrer"&gt;Rating Roulette&lt;/a&gt; measured intra-rater reliability across repeated runs at a Krippendorff's Alpha of 0.265 for Llama 3.1, 0.507 for DeepSeek-R1 and 0.563 for Qwen-3, against a conventional floor of 0.8 for acceptable reliability. The paper, presented at EMNLP 2025 Findings, puts it plainly: LLM judges have low intra-rater reliability in their assigned scores across different runs, which makes their ratings "inconsistent, almost arbitrary in the worst case."&lt;/p&gt;

&lt;p&gt;Almost every guide to &lt;a href="https://www.maximem.ai/blog/agent-evals-guide" rel="noopener noreferrer"&gt;agent evaluation&lt;/a&gt; published this year covers rubric design, scoring techniques and metric taxonomies. Very few of them ask whether the judge doing the scoring produces the same number twice, and none of them work out what it costs to run that judge on everything rather than on a sample. Both gaps matter more than the metric taxonomy does, because a suite built on an unstable judge measures its own noise, and a suite that only ever sees 2% of traffic is blind to the other 98% by construction.&lt;/p&gt;

&lt;p&gt;Both properties turn out to be fixable, and fixing them changes what an &lt;a href="https://www.maximem.ai/glossary/evals" rel="noopener noreferrer"&gt;eval suite&lt;/a&gt; can be. It starts with dropping the assumption that the judge has to be a language model at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why an unstable judge is worse than no judge
&lt;/h2&gt;

&lt;p&gt;An eval suite exists to answer one question: is today worse than yesterday. Everything else is in service of that.&lt;/p&gt;

&lt;p&gt;Run a judge twice over the same fifty traces and get a pass rate of 82% and then 76%, and the six-point gap tells you nothing. Maybe the agent regressed. Maybe the judge felt differently. You cannot separate the two without re-running enough times to average the judge out, which multiplies your bill by however many runs you need.&lt;/p&gt;

&lt;p&gt;What happens next is predictable, and I have watched teams walk through every step of it. Somebody raises the failure threshold so the suite stops going red on noise. The threshold goes up again a month later. Eventually the suite passes on everything except catastrophic breakage, at which point it has become a very expensive smoke test that nobody reads. The suite did not fail loudly; it degraded into decoration.&lt;/p&gt;

&lt;p&gt;A second failure mode is subtler and worse. A judge with high run-to-run variance on a small number of questions will produce an eval set where a handful of traces flip verdict every run. Those flipping traces get investigated, found to be fine, and marked as flaky. Real regressions that land on the same borderline traces then get dismissed under the same label.&lt;/p&gt;

&lt;h2&gt;
  
  
  "Set temperature to zero" does not fix this
&lt;/h2&gt;

&lt;p&gt;Every engineer who has run an eval suite reaches for this within about four seconds of reading the paragraph above, and it deserves a serious answer rather than a dismissal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.maximem.ai/glossary/temperature" rel="noopener noreferrer"&gt;Temperature zero&lt;/a&gt; is real and it does real work. It removes sampling randomness from token selection, and for an extraction task with one defensible answer it will give you the same output nearly every time. Several of the better guides recommend it correctly; &lt;a href="https://www.testmuai.com/blog/llm-as-a-judge/" rel="noopener noreferrer"&gt;TestMu AI&lt;/a&gt;{target="_blank"} specifies temperature 0.0 in its calibration workflow for exactly this reason, and that is sound advice as far as it goes.&lt;/p&gt;

&lt;p&gt;What it does not touch is the harder half. Temperature constrains how a token is picked from a distribution; it does not make a subjective judgement less borderline. When a trace genuinely sits between "grounded" and "partially grounded", the underlying distribution is close to even, and greedy decoding at temperature zero will still tip one way or the other on tiny differences in context, ordering, or the phrasing of the preceding question in a batch. Rating Roulette ran its three judge models across three benchmarks and found reliability well below threshold; that variance is a property of judgement on ambiguous inputs, not of the sampling parameter.&lt;/p&gt;

&lt;p&gt;There is a stronger version of the objection worth handling too. &lt;a href="https://www.patronus.ai/llm-testing/llm-as-a-judge" rel="noopener noreferrer"&gt;Patronus AI&lt;/a&gt;{target="_blank"} recommends running the same input through the judge three times as a self-consistency check, which is genuinely good practice and the only place in the mainstream guidance where this problem is acknowledged as an operational concern. It is also a three-times cost multiplier on a judge that was already the expensive part of the pipeline, which brings us to the second unmeasured thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Nobody models what grading actually costs
&lt;/h2&gt;

&lt;p&gt;Of every major guide published on this topic in the past year, exactly one publishes a real number. The &lt;a href="https://dev.to/aws/how-to-evaluate-ai-agents-llm-as-judge-tutorial-4a6h"&gt;AWS tutorial on dev.to&lt;/a&gt;{target="_blank"} gives roughly $0.001 to $0.003 per evaluation on a small model and $0.015 to $0.045 on a mid-sized one. Useful, and it stops there. No page I could find takes that per-call figure and multiplies it by production volume, which is the only form in which the number means anything.&lt;/p&gt;

&lt;p&gt;So here is the multiplication, using a mid-sized judge at the middle of that published range and a 14-question rubric run once per trace.&lt;/p&gt;

&lt;p&gt;At roughly $0.03 per trace, grading one million agent traces costs about $30,000. A reasoning-model judge, which is what most teams reach for when rubric quality matters, is worse: &lt;a href="https://docs.typesafe.ai/cookbooks/consistency_noul_cookbook.md" rel="noopener noreferrer"&gt;TypeSafe's own comparison study&lt;/a&gt;{target="_blank"} measured Claude Opus 4.8 in reasoning mode at $0.034275 per query on a 14-question rubric, which lands at about $34,000 for the same million traces. Serially, at 13.9 seconds per call, that run takes roughly 160 days of wall clock.&lt;/p&gt;

&lt;p&gt;Nobody spends $34,000 and five months to grade last month's traffic. So nobody does. Instead the guidance converges on sampling, and the sampling rates are stated without any justification at all: the AWS tutorial suggests 1 to 5% of live traffic, &lt;a href="https://www.adaline.ai/blog/complete-guide-llm-ai-agent-evaluation-2026" rel="noopener noreferrer"&gt;Adaline&lt;/a&gt;{target="_blank"} suggests 5 to 10% for judge-based checks. Neither explains where the number came from, because it did not come from anywhere. It came from the bill.&lt;/p&gt;

&lt;p&gt;Sampling at 2% means a failure mode occurring in one conversation per thousand shows up in your eval data roughly once per fifty thousand conversations. You will find it eventually, from a customer, in a support ticket.&lt;/p&gt;

&lt;h2&gt;
  
  
  What changes when the judge is not a language model
&lt;/h2&gt;

&lt;p&gt;A grading task has a peculiar shape. The judge never needs to write anything. It needs to answer a fixed list of closed questions: was this grounded, was the right tool called, did the agent refuse when it should have, how directly did it answer. Each of those is a yes-or-no, a pick-one, or a rating on a defined ladder.&lt;/p&gt;

&lt;p&gt;Which means text generation, the expensive and unstable part, is pure overhead in a judge. You pay for output tokens you throw away, you wait for them, and you inherit their variance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://typesafe.ai/" rel="noopener noreferrer"&gt;TypeSafe&lt;/a&gt;{target="_blank"} released a model in September 2026 built on that observation. Jev returns typed decisions and probabilities instead of text, across three question types: a yes-or-no probability, a pick-one from a named set with a full probability distribution, and a rating against two to ten described levels. It cannot write a sentence. That is the design.&lt;/p&gt;

&lt;p&gt;Operating numbers, taken from the vendor's own published measurements with their method attached rather than from the launch-week coverage that rounded them:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Jev&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;gpt-5.4-mini (t=0)&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;claude-haiku-4-5 (t=0)&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;gpt-5.5 reasoning&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;claude-opus-4-8 reasoning&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Latency&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;111 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1,405 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1,780 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;11,125 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;13,886 ms&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Cost per query&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;$0.000043&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;$0.001089&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;$0.001798&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;$0.033157&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;$0.034275&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Method, because a &lt;a href="https://www.maximem.ai/glossary/benchmark" rel="noopener noreferrer"&gt;benchmark&lt;/a&gt; without one is a marketing claim: 15 repeated samples of a 14-question yes-or-no rubric against a single deliberately borderline insurance claim, sampled 11 September 2026, with the &lt;a href="https://www.maximem.ai/compare/maximem-synap-vs-supermemory" rel="noopener noreferrer"&gt;TypeSafe&lt;/a&gt; model resolving to jev-1.13.0. Published pricing at the time was $0.042 per million input tokens with output tokens free.&lt;/p&gt;

&lt;p&gt;Grading a million traces on those numbers costs roughly $43.&lt;/p&gt;

&lt;p&gt;That is the whole argument, and it is not really an argument about money. At $34,000 you sample and you argue about the rate. At $43 the rate stops being a question, and an eval suite becomes something you can point at all of production, continuously, without anyone having to approve it.&lt;/p&gt;

&lt;p&gt;Reproducibility matters as much as price does here. Across those same 15 repeats, mean per-question probability standard deviation came in at 0.0102 for yes-or-no questions and 0.0098 for pick-one questions. On a hard content-moderation case scored with eight pick-one questions, raw label agreement across repeats was 90.8%.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reliability is not validity, and this is where most of the excitement should stop
&lt;/h2&gt;

&lt;p&gt;A model that agrees with itself is not thereby correct, and the strongest evidence on this arrived in June 2026 from a UC Berkeley team. &lt;a href="https://arxiv.org/html/2606.19544v1" rel="noopener noreferrer"&gt;Reliability without Validity&lt;/a&gt;{target="_blank"} ran 21 judges from 9 providers across three benchmarks, producing around 541,000 individual judgments over 118 evaluation runs, and found that high test-retest reliability of 0.95 or better coexisted with severe position &lt;a href="https://www.maximem.ai/glossary/ai-bias" rel="noopener noreferrer"&gt;bias&lt;/a&gt; above 0.10 in more than one model. A judge can be perfectly repeatable and repeatably wrong.&lt;/p&gt;

&lt;p&gt;TypeSafe's own documentation says the same thing about its own model, which is more than most vendors manage. Their study of repeated pick-one decisions carries the sentence "This experiment does not measure accuracy," and describes its own uncertainty threshold as "an illustrative application policy, not a calibrated guarantee or a threshold chosen to maximize this run's agreement." The same study concedes that a probability near the threshold can still move between a concrete label and uncertain, and that the policy does not make the model deterministic.&lt;/p&gt;

&lt;p&gt;So the honest claim is narrower than the launch coverage suggested. A typed-decision judge removes one specific failure mode, the one where your measurement instrument moves under you. It does not tell you the instrument is pointed at the right thing. You still have to check, and there are two halves to that check: which biases carry over to a typed judge, and whether its confidence number means anything on your data.&lt;/p&gt;

&lt;h3&gt;
  
  
  The biases survive the change of judge, mostly
&lt;/h3&gt;

&lt;p&gt;Four biases get named repeatedly in the existing guidance, and they are worth separating by whether a typed judge inherits them.&lt;/p&gt;

&lt;p&gt;Position bias, where a judge favours whichever option it saw first, is inherited. The Berkeley study found it ranging from 0.002 for Gemini 2.5 Pro to 0.192 for Qwen 3 8B, nearly two orders of magnitude apart, so it is a per-model property rather than a universal constant. TypeSafe's own documentation concedes the equivalent: sibling order inside a pick-one question is part of the question rather than presentation. Shuffle your option order across runs and measure whether the answer moves.&lt;/p&gt;

&lt;p&gt;Verbosity bias, where longer answers score higher, turns out to be weaker than folklore suggests. All 21 judges in the Berkeley cohort registered a Pearson correlation below 0.011 with answer length, substantially lower than earlier estimates. Worth testing on your own rubric rather than designing around.&lt;/p&gt;

&lt;p&gt;Self-preference, where a judge rates its own family of models more kindly, does not apply to a judge that generates nothing and therefore has no outputs of its own in the comparison set. The &lt;a href="https://www.confident-ai.com/blog/why-llm-as-a-judge-is-the-best-llm-evaluation-method" rel="noopener noreferrer"&gt;Confident AI guide&lt;/a&gt;{target="_blank"} documents the effect for language-model judges and is the best summary of it I have found.&lt;/p&gt;

&lt;p&gt;Rubric sensitivity is the one that gets worse, not better. A typed judge takes your level descriptions extremely literally, which is a feature until two levels overlap, at which point confidence collapses and you get an honest 0.4 instead of a confident guess. Treat persistently low confidence on one question as a defect in the question.&lt;/p&gt;

&lt;p&gt;Hand-label 200 traces yourself, or with whoever owns quality. Run the judge over them. Plot confidence against accuracy and see whether the confidence number carries information. TypeSafe's own SEC filing classification exercise is a good worked example of what a passing result looks like: over 60 filings, answers above 0.9 confidence were correct 27 times out of 30, and answers below that line were correct 12 times out of 30. The confidence score was doing real work, and they only knew that because they measured it.&lt;/p&gt;

&lt;p&gt;Berkeley's team gives the sharper warning: every judge in their study overstated chance-corrected agreement, with exact match inflating Cohen's kappa by between 33.8 and 41.3 percentage points on MT-Bench. If you validate your judge by counting how often it matches a human, you are measuring the wrong thing, and you are measuring it generously.&lt;/p&gt;

&lt;h2&gt;
  
  
  Three verdicts, not two
&lt;/h2&gt;

&lt;p&gt;Every guide surveyed for this piece scores on a binary pass or fail, a 0 to 1 scale, or a 1 to 5 integer. Not one proposes an explicit third outcome, and that omission causes a measurable amount of the noise people attribute to the judge.&lt;/p&gt;

&lt;p&gt;Some traces are genuinely ambiguous. Forcing a label onto them manufactures disagreement that has nothing to do with the agent and everything to do with the trace sitting on a boundary.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;verdict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;probability&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.30&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;probability&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;low&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;fail&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;probability&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;high&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;pass&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;needs_human&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applied to that eight-question moderation rubric, the uncertainty band took raw label agreement from 90.8% to 99.2%, with 74.2% of answers still decided automatically and 25.8% routed for review. Three quarters of the work happens without a person, near-perfectly reproducibly, and the quarter that a machine should not be deciding alone gets flagged as such instead of being guessed at.&lt;/p&gt;

&lt;p&gt;Two things make this work in practice. Pick-one questions always return something, because the probabilities have to sum to one, so on a trace where no category applies the model still nominates a winner; pairing the pick-one with a separate yes-or-no asking whether any option applies at all gives you a gate that can go to zero. And when several checks feed one decision, aggregate on the maximum rather than the mean, since one confident red flag is the whole signal and averaging is how you hide it.&lt;/p&gt;

&lt;p&gt;Band edges are not universal. Set them from labelled examples and from what a wrong automatic decision costs you relative to the price of a human looking.&lt;/p&gt;

&lt;h2&gt;
  
  
  Grading before the response ships
&lt;/h2&gt;

&lt;p&gt;Once a grade costs a tenth of a second, it can run before the user sees anything rather than after.&lt;/p&gt;

&lt;p&gt;Not one page in the incumbent set mentions this, and it is the most useful structural change available. The shape is a cascade: generate with your normal model, grade the draft response inline, and escalate only when a check fires. TypeSafe documents the pattern for structured extraction, where a cheap model extracts, a per-field check asks whether each value looks wrong, and an expensive reasoning model is invoked only when any field crosses 0.7. They report quality comparable to the top-tier model at roughly a tenth of the cost.&lt;/p&gt;

&lt;p&gt;Pointed at agent output rather than extraction, the same shape looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;draft&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cheap_agent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;checks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;judge&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;system_one&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;draft&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="n"&gt;questions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;INLINE_RUBRIC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;      &lt;span class="c1"&gt;# grounding, scope, leakage, refusal correctness
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;checks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.70&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;strong_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;respond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c1"&gt;# pay only when the check fires
&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;draft&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your quality floor stops being whatever the cheap model does on a bad day, and your bill stops being whatever the expensive model costs on a good one. The gate has to be fast enough to hide inside the response budget, which is the entire reason a 111 ms judge makes this possible and a 13.9 second one does not.&lt;/p&gt;

&lt;h2&gt;
  
  
  What still has to be right: trajectories, tools and calibration
&lt;/h2&gt;

&lt;p&gt;None of the above removes the work the existing guides describe well, and a piece that skipped it would be selling you a judge without a rubric.&lt;/p&gt;

&lt;p&gt;Agent evaluation is trajectory evaluation. A correct final answer reached by calling four unnecessary tools, failing twice and recovering by accident is not a pass, and the &lt;a href="https://www.confident-ai.com/blog/llm-agent-evaluation-complete-guide" rel="noopener noreferrer"&gt;Confident AI agent guide&lt;/a&gt;{target="_blank"} is right that tool correctness, argument correctness and step efficiency need scoring separately from task completion. Feed the whole trajectory as a named object and ask about the path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user_request&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Book a table for four on Friday&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;search_restaurants&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;args&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}},&lt;/span&gt; &lt;span class="p"&gt;...],&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;retrieved_context&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[...],&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;agent_final_reply&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;TRAJECTORY_RUBRIC&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;correct_first_tool&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Noul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Was the first entry in `tool_calls` the right tool for `user_request`?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unnecessary_calls&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Score&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;How many entries in `tool_calls` were not needed for `user_request`?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="n"&gt;criteria&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Every call was needed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;One or two calls were not needed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Most calls were not needed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;recovered_from_failure&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Noul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;After the first failed call in `tool_calls`, did the agent take a reasonable next step?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;grounded&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Noul&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Is every factual claim in `agent_final_reply` supported by `retrieved_context`?&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Every question in that request is scored independently against the same state and runs in parallel, so a forty-question rubric costs roughly what a four-question rubric costs. TypeSafe measured 13 questions against a 54,000-character document as 12.2 times cheaper and 10 times faster batched into one call than sent as 13 separate calls, with answers unchanged. The usual reason rubrics stay thin, that each question is another paid round trip, stops applying, and you can afford to check the rare &lt;a href="https://www.maximem.ai/glossary/failure-modes" rel="noopener noreferrer"&gt;failure modes&lt;/a&gt; on every trace instead of only the common ones.&lt;/p&gt;

&lt;p&gt;Calibration is the other piece worth taking from the existing guidance rather than reinventing. Patronus recommends targeting a Cohen's kappa above 0.8 against expert labels; TestMu specifies a calibration set of 30 to 50 samples, measuring precision and recall, then freezing the judge. Both are right, and both apply unchanged to a typed judge. A frozen, version-pinned judge with a measured kappa is the artifact you want; everything in this piece is about making that artifact cheap enough to run everywhere.&lt;/p&gt;

&lt;p&gt;Pin the version explicitly. In TypeSafe's own published study the alias &lt;code&gt;jev-latest&lt;/code&gt; resolved to &lt;code&gt;jev-1.13.0&lt;/code&gt;, and a judge that silently upgrades makes last quarter's scores incomparable with this quarter's.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the suite actually runs
&lt;/h2&gt;

&lt;p&gt;Most eval suites run nightly because that is what they can afford. Cost decides placement, and once it stops deciding, three placements open up at once.&lt;/p&gt;

&lt;p&gt;A regression gate in continuous integration is the first and the easiest to justify. A 500-trace suite at a tenth of a second per trace finishes in well under a minute and costs a couple of cents, which makes it a pull request check rather than a scheduled job. &lt;a href="https://deepeval.com/blog/llm-as-a-judge" rel="noopener noreferrer"&gt;DeepEval&lt;/a&gt;{target="_blank"} and Adaline both describe the assertion pattern for wiring this into a pipeline, and it works unchanged with a typed judge behind it. An eval that runs before merge stops the regression; an eval that runs at 3am documents it.&lt;/p&gt;

&lt;p&gt;Continuous scoring of production traffic is the second, and it produces a different artifact from a pass rate. A quality signal computed on every request can be cut by customer, by prompt version, by model and by release, and alerted on when the distribution moves rather than when a threshold trips. That is monitoring, not testing, and the distinction is worth holding onto: a test answers whether the build is good, while a monitor answers whether reality has changed.&lt;/p&gt;

&lt;p&gt;Inline gating, described above, is the third, and it is the one that changes the product rather than the process.&lt;/p&gt;

&lt;h2&gt;
  
  
  The thing a typed judge cannot do
&lt;/h2&gt;

&lt;p&gt;It cannot tell you why.&lt;/p&gt;

&lt;p&gt;You get 0.31 and no sentence. For the engineer staring at a red suite at 5pm, the explanation is most of the value, and any honest account of this approach has to lead with that limitation rather than bury it.&lt;/p&gt;

&lt;p&gt;You do not have to pick one judge. Grade everything with the cheap typed judge, then spend a reasoning model only on the traces that failed or landed in the uncertain band, asking it to write the diagnosis. On a suite where 74% pass cleanly, you are paying reasoning-model prices on roughly a quarter of traces and getting a written explanation exactly where a human was going to look anyway. Cheap where the work is wide, expensive where it is deep.&lt;/p&gt;

&lt;p&gt;Two smaller limits are worth knowing before you design around them. State and questions share a budget of roughly 32,000 tokens, about 150,000 characters, so long trajectories with large retrieved context will not fit in one call and need grading per turn. And a pick-one question accepts at most 255 options, which matters the moment you try to classify against a large taxonomy.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I would actually build
&lt;/h2&gt;

&lt;p&gt;Start with the judge you have and measure it, because everything else is downstream of knowing whether your current numbers mean anything. Run your existing rubric five times over the same fifty traces and compute the variance per question. If it is small, your suite is fine and you can stop reading. If two questions account for most of the movement, those two questions are probably asking about more than one thing at once.&lt;/p&gt;

&lt;p&gt;Then hand-label 200 traces and calibrate whatever judge you intend to keep, plotting confidence against accuracy rather than counting agreement.&lt;/p&gt;

&lt;p&gt;Add the third verdict before you change anything else. It is a four-line function, it costs nothing, and on the published numbers it absorbs most of the residual disagreement into an honest label.&lt;/p&gt;

&lt;p&gt;Move the cheap judge to 100% of production traffic once it is calibrated, and keep the reasoning model for explanation duty on the failures. The point of grading everything is not thoroughness for its own sake; it is that a quality signal computed on all of production can be broken down by customer, by prompt version, by model, and alerted on when the distribution shifts. That is a different artifact from a nightly pass rate.&lt;/p&gt;

&lt;p&gt;We grade memory recall for &lt;a href="https://www.maximem.ai/synap" rel="noopener noreferrer"&gt;Maximem Synap&lt;/a&gt; on this shape, because memory quality is exactly the kind of property that degrades quietly and shows up in a support ticket rather than in a test. An eval that runs on a sample once a night finds that class of regression late, every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part worth sitting with
&lt;/h2&gt;

&lt;p&gt;For two years the eval tooling conversation has been about frameworks and metric taxonomies, and those frameworks are good. The judge underneath them has been treated as a solved component, and two recent studies say it is not, one published at EMNLP 2025 Findings and one a June 2026 preprint from UC Berkeley: judges disagree with themselves across runs, and the agreement statistics most teams use to validate them overstate the case by 30 to 40 percentage points.&lt;/p&gt;

&lt;p&gt;Fixing that is not a matter of a better prompt. It is a matter of asking whether the thing doing the grading should have been a text generator in the first place, given that it never needed to write anything. When the answer is no, the price falls far enough that the eval stops being a test you run and becomes a measurement you always have. That changes what you can know about your agent, which is the only reason any of this exists.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Agent Memory Is a Real Problem. Most Builders Just Have Not Hit It Yet.</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Fri, 18 Sep 2026 09:14:47 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/agent-memory-is-a-real-problem-most-builders-just-have-not-hit-it-yet-nko</link>
      <guid>https://dev.to/gaurav_dadhich/agent-memory-is-a-real-problem-most-builders-just-have-not-hit-it-yet-nko</guid>
      <description>&lt;p&gt;Every LLM call is stateless. Agent frameworks solve that within a single run, which is why &lt;a href="https://www.maximem.ai/the-memory-problem" rel="noopener noreferrer"&gt;the memory problem&lt;/a&gt; does not show up until the run ends. The first time it does show up, it does not look like a memory problem at all. It looks like an agent that asks a returning customer the same question it asked last week, a support copilot that contradicts a decision it made two sessions ago, or a bill for tokens that grew faster than usage did. By the time the pattern is legible, it has usually already cost something.&lt;/p&gt;

&lt;p&gt;This piece is about that gap: what &lt;a href="https://www.maximem.ai/glossary/agentic-memory-system" rel="noopener noreferrer"&gt;agent memory&lt;/a&gt; actually is, why so many teams building agents have not run into the problem yet, why the obvious fixes look like solutions and are not, and how we approach the problem at Maximem.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Agent Memory?
&lt;/h2&gt;

&lt;p&gt;Agent memory is the layer that lets an agent carry facts, preferences, episodes, and entities across turns, sessions, users, and tools, instead of treating every interaction as a cold start. A model on its own has no memory; each call is stateless, and whatever continuity an agent appears to have was engineered on top of that by somebody. Within one run, the framework holds that state. Across runs, across days, across a customer's whole relationship with your product, something else has to.&lt;/p&gt;

&lt;p&gt;Memory is what turns a capable-but-forgetful model into an agent that gets better the more it is used. It is the difference between a customer explaining their situation once and a customer explaining it every single time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is Agent Memory an Imagined Problem or a Real One?
&lt;/h2&gt;

&lt;p&gt;It is real, and the reason it does not feel real to most people building agents today is worth taking seriously, because the same reasons explain why the teams who have hit it treat it as one of the harder problems in the stack.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why most agent-builders have not come across the agent-memory problem yet
&lt;/h3&gt;

&lt;p&gt;The honest answer is that most agents in the wild are not yet operating in the conditions that make memory bite. Six things are usually true.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Production adoption is still early, and scale is low.&lt;/strong&gt; A large share of what gets called an "agent" today is an experiment or a demo. Real agents in production, carrying real users across real time, are still the minority, and the ones that exist are often running at a scale where the seams do not tear yet. Memory failures are a function of returning users and elapsed time. With few returning users and little elapsed time, the failure has nothing to act on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many teams are building workflows, not agents.&lt;/strong&gt; A rigid flow that moves a request through predefined steps does not need to remember anything, because the state it needs lives in the flow itself. This is a legitimate way to build, and for many problems it is the correct one. It also means the builder never encounters the memory problem, because they never built the thing that has the problem. The distinction matters: an agent decides what to do next; a workflow was told. Only the first one has anything to remember.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Many agents are non-conversational by design.&lt;/strong&gt; Two common shapes here. The first is short-call voice agents built for a single advertising or qualifying interaction, where the entire job is over in ninety seconds and there is no second conversation to be continuous with. The second is the far larger category of teams converting existing SaaS into AI-enabled SaaS, bolting a natural-language surface onto software whose data model and workflows were designed for humans clicking buttons. That is AI-enabled software, and it is valuable, but it is not the same as reimagining the work itself around an agent that accumulates context. The first shape has nothing to remember. The second remembers through its existing database and does not yet feel the absence of an &lt;a href="https://www.maximem.ai/research/agent-skills/skills-vs-agent-memory" rel="noopener noreferrer"&gt;agent memory layer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Token costs have not started pinching, because scale is low.&lt;/strong&gt; The most common way to fake memory is to stuff prior history into the prompt. At low volume, that is cheap enough to ignore. The cost of faking memory this way scales with conversation length multiplied by user count multiplied by frequency, so it stays invisible until two of those three start climbing, at which point it arrives as a line item nobody forecast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Returning customers are sparse, and there are almost no evals for agent CSAT yet.&lt;/strong&gt; Memory quality is only observable when the same user comes back and the agent either does or does not carry them forward. Most teams are not yet measuring satisfaction from agent interactions across sessions, so even where memory is quietly failing, there is no instrument pointed at it. The failure is real; the detector is not installed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Locally-run agent harnesses create the illusion that long context solves it.&lt;/strong&gt; A great deal of early agent building happens in a local &lt;a href="https://www.maximem.ai/glossary/harness" rel="noopener noreferrer"&gt;harness&lt;/a&gt; against a single developer's own history, where a long &lt;a href="https://www.maximem.ai/glossary/context-window" rel="noopener noreferrer"&gt;context window&lt;/a&gt; really does hold everything relevant. It is easy to conclude from that experience that a big enough window is memory. It is not, and the reasons that it is not become obvious the moment there is more history than a window can hold, or more than one user whose histories must not bleed into each other.&lt;/p&gt;

&lt;p&gt;None of these are signs that the problem is not real. They are the conditions under which a real problem stays hidden. Every one of them dissolves as agents move to production, run longer, serve more users, and start being measured.&lt;/p&gt;

&lt;h3&gt;
  
  
  For builders who have hit the problem, the alternatives look easy. They are not.
&lt;/h3&gt;

&lt;p&gt;Once a team does run into it, a set of primitives and adjacent tools present themselves as the fix, and each of them looks appealing because each of them solves a piece of the shape of the problem. The trap is that they look sufficient right up until someone builds an eval and measures precision and recall on retrieved context. Without that measurement, a partial solution and a real one are indistinguishable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.maximem.ai/memory-vs-context-windows" rel="noopener noreferrer"&gt;Larger context windows&lt;/a&gt;.&lt;/strong&gt; A bigger window is a bigger desk, not a better filing system. It postpones the problem by letting you hold more at once, but it does not decide what is worth holding, it does not persist anything past the session, and it does not keep one user's context out of another's. Past a certain history length the window is full again, and now you are paying to re-read everything on every turn. Bigger context is real capability that solves a different problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.maximem.ai/memory-vs-vector-rag" rel="noopener noreferrer"&gt;Vector RAG&lt;/a&gt;,&lt;/strong&gt; &lt;a href="https://github.com/pgvector/pgvector" rel="noopener noreferrer"&gt;&lt;strong&gt;pgvector&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;, &lt;a href="https://www.maximem.ai/glossary/graph-rag" rel="noopener noreferrer"&gt;graph RAG&lt;/a&gt;.&lt;/strong&gt; Semantic search over stored chunks is the most common homegrown memory, and it is useful for retrieval over documents. The failure mode is that raw conversation is not a document. Chunk-and-embed does not resolve that "the client", "Acme", and "Acme Corp" are one entity, it does not know which of two contradictory statements is current, and it retrieves on similarity rather than on relevance to the moment. High recall on chunks is not the same as retrieving the right fact, and the gap between those two is exactly what an eval exposes and intuition does not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Skills.&lt;/strong&gt; &lt;a href="https://www.anthropic.com/news/skills" rel="noopener noreferrer"&gt;Skills&lt;/a&gt; give an agent reusable, packaged competence, which is a real and useful primitive. It is also a different axis from memory. A skill is knowledge the agent brings to every user; memory is what the agent has learned about this user, this account, this history. Confusing the two leads to building excellent procedures that still forget who they are talking to.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Agent framework state machines.&lt;/strong&gt; This is the objection every serious builder reaches for first, and it deserves a straight answer. Frameworks such as &lt;a href="https://langchain-ai.github.io/langgraph/" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt; give you checkpointers, thread state, and cross-thread stores, and they do their job well: they carry an agent through a long, multi-step run without dropping most of what matters, and for completing a single execution correctly they are the right tool. The checkpointer exists to make one run reliable, and it does. What it was never trying to do is decide what, out of thousands of past interactions, is worth remembering next month, resolve entities across those interactions, reason about what has since changed, and keep all of it correctly scoped across many tenants. Those are not gaps in the framework. They are simply a different problem, one that begins where the run ends.&lt;/p&gt;

&lt;h3&gt;
  
  
  DIY is the first real response, because it looks easy until you run benchmarks
&lt;/h3&gt;

&lt;p&gt;The teams who see through the primitives usually reach the same next conclusion: we will build it ourselves. It is an understandable instinct, and it is where a lot of engineering time goes to quietly die. The reason is that the naive version really is a weekend of work, so the effort estimate is anchored on the wrong version.&lt;/p&gt;

&lt;p&gt;The first cut, embed the history, store it, retrieve by similarity, works in the demo. Then the benchmarks start. Precision and recall on retrieved context, contradiction handling when a user changes their mind, entity resolution across messy references, temporal reasoning about what is current, isolation across tenants, latency inside the conversation hot path, and retrieval quality that does not degrade as the store grows. Each one is a research problem with a literature behind it, and getting the whole thing right is iterative depth work that is hard to do well without a disproportionate investment of time. The build-it-ourselves estimate is almost always the estimate for the weekend version, and the production version is a different project entirely.&lt;/p&gt;

&lt;p&gt;This is the actual shape of the thing: agent memory is a data pipeline and fast-search problem, not a storage problem. Storing conversations is trivial. Deciding what to keep, resolving it into entities, keeping it current, forgetting what has gone stale, and returning exactly the right context in single-digit milliseconds is the work.&lt;/p&gt;

&lt;h2&gt;
  
  
  So, What Is Agent Memory? The Jobs To Be Done
&lt;/h2&gt;

&lt;p&gt;Stated as the jobs a real memory layer has to do, rather than as a definition, the shape becomes concrete. A memory layer earns its place when it does the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Persist context across sessions, users, and tools.&lt;/strong&gt; Facts, preferences, episodes, and entities survive past the end of a run, so a returning user is carried forward rather than re-interviewed. A support agent that already knows the customer's plan, their last three tickets, and the workaround it gave them last week is a different product from one that starts every chat by asking for an account number.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Resolve entities automatically.&lt;/strong&gt; "The client", "Acme", and "Acme Corp" collapse into one entity instead of fragmenting into three, so the agent reasons about a coherent world rather than a pile of near-duplicates. For a B2B sales or account agent, this is the difference between one accurate view of a company and several partial ones that disagree.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reason about time.&lt;/strong&gt; The layer knows what is current versus stale, so the agent acts on the latest state of a fact and not on something a user corrected two months ago. A scheduling or operations assistant that still believes a cancelled meeting is on the calendar is worse than no assistant.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Scope memory across tenancy levels.&lt;/strong&gt; Context is visible at the right level, from an individual user up through a customer organization and beyond, and never leaks across the boundaries that separate one tenant's data from another's. For a multi-tenant B2B copilot, this is not a nicety, it is the line between a working product and a data incident.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manage PII and permissions.&lt;/strong&gt; Memory respects who is allowed to see what, retrieval never surfaces something the current user should not have, and sensitive data is retained, masked, and retired according to policy rather than sitting in a prompt forever. A healthcare or fintech agent lives or dies on getting this right.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Forget consciously.&lt;/strong&gt; Stale and low-value memory is retired on purpose, so the store does not bloat into noise and retrieval stays sharp as history grows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Learn what to keep.&lt;/strong&gt; The layer improves what it retains over time instead of dumping raw history back into the prompt, so a coding agent gradually holds the conventions and decisions that matter to a codebase rather than every line anyone ever typed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Manage memory across multiple agents.&lt;/strong&gt; Context passes cleanly between agents in a multi-agent system, with shared knowledge and per-agent private memory kept distinct, rather than each agent re-deriving the world from scratch at every handoff.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Reduce token cost.&lt;/strong&gt; Faking memory by appending history grows cost quadratically with conversation length; a memory layer that retrieves only what the turn needs and compacts the rest keeps cost close to linear, which is the difference between a margin that survives scale and one that does not. A high-volume support deployment feels this first.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Return context fast enough to sit in the conversation.&lt;/strong&gt; Retrieval happens inside the latency budget of a live turn, not as an offline batch job. For a voice agent, where a pause of a second reads as a broken call, this constraint is unforgiving.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Signs You Need Agent Memory
&lt;/h2&gt;

&lt;p&gt;The clearest signals that you have crossed from "memory is overkill" into "memory is now the bottleneck":&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your agent is conversational, multi-turn, or long-running, and users come back. The moment a second session with the same user matters, memory matters.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are serving multiple customers from one product, and keeping each tenant's context isolated has become something you think about.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are stuffing conversation history into the prompt to fake continuity, and the token bill is starting to track conversation length rather than value delivered.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Your agent repeats questions, contradicts its own earlier decisions, or treats a returning user as a stranger.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You are running a multi-agent system and finding that context has to be re-derived every time control passes from one agent to another.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have started building memory in-house, and the second version of that build is turning out to be much larger than the first.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If two or more of these are true, the problem is no longer hypothetical for you, and the fastest way to know how much it is costing you is to measure it rather than guess.&lt;/p&gt;

&lt;p&gt;We run that measurement for you, free. You fill in a short form, we run our diagnostic against your agent, and we show you where its memory breaks today: what it fails to recall, where precision and recall drop, and what that is costing you in tokens and in users repeating themselves. You get the findings whether or not you ever use Maximem Synap. &lt;a href="https://docs.google.com/forms/d/e/1FAIpQLSeyTWs93X1aD3avdiY7B9ZtCJrMDNCs-PsDHpsAdCnXSSp3TQ/viewform" rel="noopener noreferrer"&gt;Start the free diagnostic here.&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How We Approach Agent Memory at Maximem
&lt;/h2&gt;

&lt;p&gt;The way we see it, agent memory is not merely a storage and retrieval problem, it is an architecture problem, and treating it as one is what separates a memory feature from a memory system.&lt;/p&gt;

&lt;p&gt;Maximem Synap ingests conversations asynchronously and extracts structure, not raw text. That structure is stored across three kinds of store at once, vector, graph, and file, and retrieval nets across all three together rather than betting the whole system on similarity search alone. Because ingestion runs in the background, the expensive extraction work never sits in the conversation hot path, and context is pre-fetched while the conversation is still going, which is how in-conversation retrieval stays under 15ms at P75. Conscious forgetting runs as background cycles over the stores, retiring what has gone stale so precision holds as history grows, and extraction, scoping, and retention are all configurable per deployment rather than fixed. On the public benchmarks this comes out as the most accurate memory system we are aware of, with 92% on LongMemEval and 93.2% on LoCoMo, against next-closest published scores in the low seventies.&lt;/p&gt;

&lt;p&gt;The full picture is laid out in our research paper, &lt;a href="https://www.maximem.ai/blog/agentic-context-management-paper" rel="noopener noreferrer"&gt;Agentic Context Management: Agent Memory Is Not Merely a Storage &amp;amp; Retrieval Problem, It Is an Architecture Problem&lt;/a&gt;. It treats memory as a five-stage lifecycle rather than a store: architecting a memory schema per agent, ingesting asynchronously with entity resolution, scoping retrieval narrowest-first across tenancy, anticipating the context an agent will need before it asks for it, and compacting with validation so cost stays close to linear in the length of the conversation rather than quadratic. Figure 1 of the paper draws this as a cycle around the agent. A store makes none of those decisions. Storage is one moment in the lifecycle, not the whole of it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>Why AI Forgets: Why ChatGPT, Claude, and Gemini Don't Remember You Well</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Wed, 26 Aug 2026 08:42:22 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/why-ai-forgets-why-chatgpt-claude-and-gemini-dont-remember-you-well-3igo</link>
      <guid>https://dev.to/gaurav_dadhich/why-ai-forgets-why-chatgpt-claude-and-gemini-dont-remember-you-well-3igo</guid>
      <description>&lt;p&gt;I had a conversation with Claude last Wednesday. Spent maybe forty minutes walking it through a product launch plan: the positioning, the pricing tiers, the three segments we were targeting. Good conversation, felt productive. On Thursday morning I opened a new chat to refine the email sequence for that same launch.&lt;/p&gt;

&lt;p&gt;"Could you tell me more about your product?" . Forty minutes of context, gone. Either corrupted or half-remembered.&lt;/p&gt;

&lt;p&gt;If you use &lt;a href="https://www.maximem.ai/blog/ai-apps-memory" rel="noopener noreferrer"&gt;AI tools regularly&lt;/a&gt;, you've had this moment. You've had it dozens of times. And at some point you stopped being surprised and started being annoyed. You copy-paste the same background into every new conversation. You keep a Google Doc of "stuff to tell the AI." You re-explain your job, your preferences, your constraints - over and over, to the most capable technology ever built.&lt;/p&gt;

&lt;p&gt;Here's the thing nobody tells you clearly: your AI isn't forgetting. It never knew you in the first place. What felt like a relationship was a transaction.&lt;/p&gt;

&lt;h1&gt;
  
  
  Every conversation is an island
&lt;/h1&gt;

&lt;p&gt;The way these tools work under the hood is genuinely counterintuitive. When you chat with ChatGPT or Claude or Gemini, the model doesn't "learn" from your conversation. Nothing you say changes the model itself. It processes your messages, generates a response, and when the session ends, the next session starts from a blank slate.&lt;/p&gt;

&lt;p&gt;Think of it like calling a support hotline where the agents don't have a CRM. You might get someone brilliant. They might solve your problem in five minutes flat. But tomorrow when you call back? Different person. No notes in the file. You start from "can I get your account number?"&lt;/p&gt;

&lt;p&gt;There's a technical term for this. AI conversations are stateless. Each one exists independently, unconnected to anything before or after it.&lt;/p&gt;

&lt;p&gt;Three specific things make this worse than it sounds:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The token window rolls over.&lt;/strong&gt; Even within a single conversation, there's a limit to how much the model can "see." ChatGPT and Claude have large context windows (128K-1M tokens depending upon the model), roughly 200 pages of text for some models. But in long conversations, older messages start falling off the edge. The model isn't summarizing them or filing them away. They're just not there anymore. Ask about something from the beginning of a two-hour coding session and you might get a blank stare. Plus there is something called as context-rot. In simple words, the more information you give them, the more they hallucinate on that information. They barely remember about 20-30% of it accurately. Not ideal.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Each platform is its own silo.&lt;/strong&gt; This one is brutal for anyone who uses more than one AI tool. And most power users do: ChatGPT for brainstorming, Claude for longer analysis, Gemini when you need something integrated with Google, Perplexity for research. Each one knows a fragment of you. None of them share notes. Your preferences in Claude don't exist in ChatGPT. That Perplexity research session about competitor pricing? Invisible to every other tool you use.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The "memory" features are thinner than they look.&lt;/strong&gt; ChatGPT does have a memory feature: it will store facts like your name, your job, that you prefer bullet points over paragraphs. Claude has something similar. But these are stored facts, not understanding. ChatGPT remembered that I work in AI infrastructure. It did not remember the forty-minute launch strategy. That's the gap. Flat facts versus actual context from working sessions.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  "But ChatGPT, Claude has memory now"
&lt;/h1&gt;

&lt;p&gt;I know. I've tested it extensively. Let me tell you what it actually does.&lt;/p&gt;

&lt;p&gt;ChatGPT's memory system keeps lightweight summaries of your recent conversations, roughly your last fifteen chats. Not the AI's responses, just compressed sketches of what you typed. It also stores explicit facts about you (your name, role, preferences) that get injected into every single prompt, whether relevant or not. One researcher who dug into this found 33 stored facts about himself riding along in every conversation. His gym schedule was being fed to ChatGPT when he asked about Python debugging.&lt;/p&gt;

&lt;p&gt;Claude takes a different approach. Instead of pre-loading summaries, it has retrieval tools it can use to search your past conversations. The operative word is "can." Claude has to decide, mid-conversation, that looking into your history would help. Sometimes it does. Sometimes it doesn't think to check. When it works, it's genuinely impressive; you get detailed context from three weeks ago. When it doesn't, you get nothing. [We did a deep dive into how each platform handles this](&lt;a href="https://www.maximem.ai/blog/ai-apps-memory" rel="noopener noreferrer"&gt;https://www.maximem.ai/blog/ai-apps-memory&lt;/a&gt;) and the short version is: all three major platforms are engineering their own isolated memory, and none of them talk to each other.&lt;/p&gt;

&lt;p&gt;Gemini's situation is different again. Strong integration with your Google ecosystem; it can pull from Drive, Gmail, Calendar. But your conversations with Gemini don't inform your conversations with ChatGPT or Claude. It's another walled garden, just with Google-shaped walls.&lt;/p&gt;

&lt;p&gt;The pattern: three platforms, three separate attempts at memory, three siloed systems that can't see past their own borders.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bigger context windows won't fix this
&lt;/h1&gt;

&lt;p&gt;I hear this one constantly. "GPT-5 will have a million-token &lt;a href="https://www.maximem.ai/glossary/context-window" rel="noopener noreferrer"&gt;context window&lt;/a&gt;, so the forgetting problem goes away." It won't, here's why:&lt;/p&gt;

&lt;p&gt;A larger context window makes individual conversations longer. It doesn't make them connected. You can fit an entire book into a single session, sure. But close that session and open a new one tomorrow; same blank slate, no matter how many tokens the window supports.&lt;/p&gt;

&lt;p&gt;There's also a cost issue nobody likes talking about. Context isn't free. Every token you stuff into that window costs money on the API side and computation on the &lt;a href="https://www.maximem.ai/glossary/inference" rel="noopener noreferrer"&gt;inference&lt;/a&gt; side. The bigger the window, the more expensive every single message becomes. A 200K-token conversation with Claude Sonnet costs meaningfully more than a fresh 2K-token one. The platforms aren't going to solve this by just making windows bigger, because that doesn't scale economically.&lt;/p&gt;

&lt;p&gt;And even within a long conversation, there's a well-documented problem researchers call "lost in the middle"; models pay more attention to information at the beginning and end of their context window and tend to miss things buried in the center. Bigger windows can actually make this worse, not better. More hay, same needle.&lt;/p&gt;

&lt;p&gt;## What you're actually losing&lt;/p&gt;

&lt;p&gt;Let's be concrete about the cost. Cottrill Research reported in 2025 that nearly half of knowledge workers spend one to five hours every day searching for information they've already accessed. UC Irvine's research on interruptions found it takes about 23 minutes to get back in the zone after each break in focus. Every time you re-explain your role, your project constraints, your communication preferences; that's an interruption. A self-inflicted one, caused by tools that should already know this.&lt;/p&gt;

&lt;p&gt;We tracked our own stats when we helped users create their AI Year End Wrapped. Users on average had revised their prompt in over half of all conversations. Half the time, they're teaching the AI something it should already know.&lt;/p&gt;

&lt;p&gt;Multiply this by every AI tool you use. Multiply by every working day. The cumulative friction is enormous, and it's invisible because it's distributed across hundreds of small moments. No single re-explanation feels like a big deal. But together, they eat hours every week.&lt;/p&gt;

&lt;p&gt;The subtler cost is harder to measure: the good conversations that never happen because you don't bother setting up the context. You wanted to ask Claude to refine yesterday's strategy. But that would mean re-pasting the strategy, re-explaining the market context, re-describing the team dynamics. So you just... don't. You work from the draft you already have, even though a fresh pass with full context might have caught the flaw in your pricing model.&lt;/p&gt;

&lt;h1&gt;
  
  
  What you can do about it right now
&lt;/h1&gt;

&lt;p&gt;Three options, escalating in effectiveness.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The manual workaround. Keep a document&lt;/strong&gt;: some people use Notion, some use a simple text file: with your standard context: role, current projects, communication preferences, key constraints. Paste it at the top of every new conversation. It works. It's tedious. It doesn't transfer between platforms. You become your own memory system, which, let's be honest, defeats a lot of the purpose of using AI in the first place.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use the platform-native memory features&lt;/strong&gt;. Turn on ChatGPT's memory. Use Claude Projects to store background documents. Set up Gemini's Google &lt;a href="https://www.maximem.ai/glossary/integrations" rel="noopener noreferrer"&gt;integrations&lt;/a&gt;. This gets you further. But each one only works inside its own platform. If you're a multi-platform user; and the data suggests most regular AI users are, you're still maintaining separate contexts everywhere.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Use a&lt;/strong&gt; &lt;a href="https://www.maximem.ai/cross-app-memory" rel="noopener noreferrer"&gt;&lt;strong&gt;cross-app memory&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;layer&lt;/strong&gt;. This is a newer category. Tools that sit above all your AI platforms and maintain one unified memory across everything. A Chrome extension, typically, that captures context from your conversations and makes it available everywhere you go. What you discussed in ChatGPT on Monday is available when you open Claude on Wednesday.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We built &lt;a href="https://www.maximem.ai/vity" rel="noopener noreferrer"&gt;Vity&lt;/a&gt; for exactly this reason. It's a free Chrome extension that syncs your memory across ChatGPT, Claude, Gemini, Perplexity, DeepSeek, Grok; ten platforms currently. It captures context from your conversations (with your consent, always), then proactively surfaces relevant memories as you type in any supported app. You approve what gets included. Nothing gets injected without you seeing it first. The whole thing runs on an encrypted vault that we can't read even if we wanted to.&lt;/p&gt;

&lt;p&gt;But my bias is showing. If you want an apples-to-apples look at how &lt;a href="https://www.maximem.ai/vity" rel="noopener noreferrer"&gt;Vity&lt;/a&gt; stacks up against other options in this category, we published a &lt;a href="https://www.maximem.ai/compare/maximem-vity-vs-mem0-vs-supermemory" rel="noopener noreferrer"&gt;detailed comparison of Vity, Mem0, and Supermemory&lt;/a&gt; that covers setup, platform support, privacy architecture, and memory depth. Read it and decide for yourself.&lt;/p&gt;

&lt;h1&gt;
  
  
  The forgetting problem isn't going away on its own
&lt;/h1&gt;

&lt;p&gt;Here's the uncomfortable truth. Smarter models don't fix statelessness. GPT-5 will be smarter than GPT-4. It will still start every conversation from zero. Claude's next version will be more capable. It still won't know what you told the current version last Tuesday.&lt;/p&gt;

&lt;p&gt;The forgetting isn't a technical limitation that next year's model update solves. It's an architectural choice. Each conversation is designed to be independent. That's actually useful for privacy and safety; it means your conversations don't bleed into each other or into other people's experiences. But it also means no AI tool, on its own, will ever "remember you" the way a colleague does.&lt;/p&gt;

&lt;p&gt;Memory has to be solved as a separate layer. Something that sits above the models, captures what matters, and brings it back when it's relevant. Whether that's Vity, or one of the alternatives, or something you build yourself with a text file and discipline; the core insight is the same.&lt;/p&gt;

&lt;p&gt;Your AI tools are not going to start remembering you. You have to give them a memory.&lt;/p&gt;

&lt;p&gt;---&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;strong&gt;Frequently Asked Questions&lt;/strong&gt;
&lt;/h1&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Why does ChatGPT forget everything between conversations?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;ChatGPT conversations are stateless by design. Each new chat starts with no knowledge of previous sessions. ChatGPT does have a built-in memory feature that stores basic facts about you, but it only retains lightweight summaries of recent chats and doesn't carry over the detailed context from working sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Can AI remember things between conversations?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Not natively. ChatGPT, Claude, and Gemini each have limited memory features that work within their own platform, but none of them share memory across platforms. Cross-app memory tools like &lt;a href="https://www.maximem.ai/vity" rel="noopener noreferrer"&gt;Vity&lt;/a&gt; solve this by maintaining a single memory layer that works across all major AI platforms.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Does Claude have memory like ChatGPT?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Claude has a different approach. Instead of pre-loading conversation summaries, Claude uses retrieval tools that can search your past conversations on demand. It offers a larger context window (upto 1 M tokens) for longer sessions, but like ChatGPT, its memory only works within Claude itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;How do I make AI remember my preferences?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Three options: (1) manually paste your preferences into every new chat, (2) use built-in features like ChatGPT Memory or Claude Projects within each platform, or (3) use a cross-app memory extension that syncs your preferences across all AI platforms automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;What is cross-app&lt;/strong&gt; &lt;a href="https://www.maximem.ai/glossary/episodic-memory-ai" rel="noopener noreferrer"&gt;&lt;strong&gt;AI memory&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;?&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Cross-app AI memory is a layer that captures context from your conversations across multiple AI platforms (ChatGPT, Claude, Gemini, Perplexity, etc.) and makes it available everywhere. Instead of each AI tool having its own isolated memory, you have one unified memory that follows you. Learn more about [how cross-app memory works](&lt;a href="https://www.maximem.ai/cross-app-memory" rel="noopener noreferrer"&gt;https://www.maximem.ai/cross-app-memory&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there a way to sync memory across ChatGPT and Claude?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not through the platforms themselves: ChatGPT and Claude don't share data with each other. Cross-app memory tools bridge this gap. &lt;a href="https://www.maximem.ai/vity" rel="noopener noreferrer"&gt;Vity's Chrome extension (which also works with OpenClaw)&lt;/a&gt; captures context from both platforms and surfaces relevant memories in either one, so preferences and project context travel with you.&lt;/p&gt;

&lt;h3&gt;
  
  
  How do AI agents remember previous conversations across sessions?
&lt;/h3&gt;

&lt;p&gt;They do not on their own. Something outside the model has to decide what is worth keeping from a conversation, store it, and put the relevant part back into context on a later turn. Without that layer every session starts from zero, no matter how capable the model is.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is this different for developers building agents than for people using ChatGPT?
&lt;/h3&gt;

&lt;p&gt;The cause is identical and the fix is not. A person can work around it with a pinned prompt or a memory feature. A developer shipping to thousands of users needs the layer itself: capture, retrieval, conflict resolution when a user changes their mind, and deletion that actually propagates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why does a bigger context window not solve it?
&lt;/h3&gt;

&lt;p&gt;A larger window extends how long one conversation runs before it degrades. It changes nothing about what happens when that conversation closes, and it raises cost on every turn because you reload the same history each time.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>MCP 2026-07-28: 20 Breaking Changes and the Errors They Cause</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Tue, 25 Aug 2026 06:38:27 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/mcp-2026-07-28-20-breaking-changes-and-the-errors-they-cause-og2</link>
      <guid>https://dev.to/gaurav_dadhich/mcp-2026-07-28-20-breaking-changes-and-the-errors-they-cause-og2</guid>
      <description>&lt;p&gt;The &lt;a href="https://www.maximem.ai/glossary/mcp" rel="noopener noreferrer"&gt;Model Context Protocol&lt;/a&gt; shipped revision &lt;code&gt;2026-07-28&lt;/code&gt; on 28 July 2026, and it is the largest change to the protocol since it launched. Sessions are gone. The &lt;code&gt;initialize&lt;/code&gt; handshake is gone. Servers can no longer initiate requests at all.&lt;/p&gt;

&lt;p&gt;If you run an MCP server, the useful thing to know first is that nothing breaks today on its own. A server speaking the old revision keeps working with clients speaking the old revision, and &lt;a href="https://claude.com/blog/bringing-mcp-2026-07-28-to-claude" rel="noopener noreferrer"&gt;Anthropic&lt;/a&gt; has said support is rolling out across Claude products without announcing general availability or per-product dates. The break arrives when a client upgrades underneath you, and when it arrives it is total in both directions, because a modern client cannot talk to a legacy server and a legacy client has no mechanism at all for talking forward to a modern one.&lt;/p&gt;

&lt;p&gt;Also gone in this revision: &lt;code&gt;ping&lt;/code&gt;, &lt;code&gt;logging/setLevel&lt;/code&gt;, SSE stream resumability, &lt;code&gt;resources/subscribe&lt;/code&gt;, &lt;code&gt;resources/unsubscribe&lt;/code&gt;, &lt;code&gt;tasks/list&lt;/code&gt; and &lt;code&gt;tasks/result&lt;/code&gt;. Roots, sampling, logging and Dynamic Client Registration are deprecated with a twelve month clock running on them.&lt;/p&gt;

&lt;p&gt;Below is the full diff, every error you will hit while upgrading with the fix for each, and the one deadline where the specification and the release blog give different answers, which matters because the blog is the document most people will read.&lt;/p&gt;




&lt;h2&gt;
  
  
  What changed in MCP 2026-07-28
&lt;/h2&gt;

&lt;p&gt;Eight things shipped, and they are easier to understand as one decision with seven consequences than as eight independent features.&lt;/p&gt;

&lt;p&gt;Everything traces back to one decision, &lt;a href="https://blog.modelcontextprotocol.io/posts/2026-07-28/" rel="noopener noreferrer"&gt;SEP-2575 and SEP-2567&lt;/a&gt;, which together make the protocol stateless. There is no handshake and no session identifier. Every request carries its own protocol version and client capabilities in &lt;code&gt;_meta&lt;/code&gt;, and a new &lt;code&gt;server/discover&lt;/code&gt; method replaces the capability exchange that used to happen at connection time. Servers must implement &lt;code&gt;server/discover&lt;/code&gt;; clients may skip it entirely and handle the error instead.&lt;/p&gt;

&lt;p&gt;Everything else follows from that. Because servers can no longer hold a connection open, they can no longer initiate requests, so &lt;strong&gt;Multi Round-Trip Requests&lt;/strong&gt; (SEP-2322) replace &lt;code&gt;sampling/createMessage&lt;/code&gt;, &lt;code&gt;elicitation/create&lt;/code&gt; and &lt;code&gt;roots/list&lt;/code&gt; with a pattern where the server returns &lt;code&gt;resultType: "input_required"&lt;/code&gt; and the client re-sends the original call with the answers attached. Because the operation can no longer be inferred from a session, it moves into HTTP headers, so &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt; (SEP-2243) are now required and a load balancer can route on them without parsing the body. Because list results no longer vary per connection, they become cacheable, so &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; (SEP-2549) are now non-optional fields on six result types.&lt;/p&gt;

&lt;p&gt;Four further changes are less structural but worth knowing. Authorization hardens across six SEPs, with RFC 9207 issuer validation now mandatory on the client side and Dynamic Client Registration formally deprecated in favour of &lt;a href="https://workos.com/blog/mcp-2026-spec-agent-authentication" rel="noopener noreferrer"&gt;Client ID Metadata Documents&lt;/a&gt;. Tasks moves out of the core protocol into an opt-in extension (SEP-2663) with a redesigned polling API. A formal extensions framework (SEP-2133) lets anyone ship a protocol feature under a reverse-DNS identifier without a specification change. And a real deprecation policy (SEP-2596) arrives with a twelve month minimum window, a published registry, and SDK-level obligations to mark deprecated surfaces.&lt;/p&gt;

&lt;p&gt;Here is the whole revision on one screen.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;2025-11-25&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;2026-07-28&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Handshake&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;initialize&lt;/code&gt; plus &lt;code&gt;notifications/initialized&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;None. Per-request &lt;code&gt;_meta&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Sessions&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;Mcp-Session-Id&lt;/code&gt; header, 404 to reinitialise, DELETE to end&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Removed. Explicit application-level handles&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Capabilities&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Negotiated once per connection&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Declared on every request&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Discovery&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;InitializeResult&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;server/discover&lt;/code&gt;, server MUST implement, client MAY call&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Transport&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;POST plus GET SSE, resumable via &lt;code&gt;Last-Event-ID&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;POST only. A modern-only server SHOULD return &lt;code&gt;405&lt;/code&gt; on GET and DELETE. No resumability&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Routing&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Operation in the JSON body. &lt;code&gt;MCP-Protocol-Version&lt;/code&gt; header required since &lt;code&gt;2025-06-18&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Two new required headers, &lt;code&gt;Mcp-Method&lt;/code&gt; on every request and &lt;code&gt;Mcp-Name&lt;/code&gt; on three of them&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Server to client requests&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;sampling/createMessage&lt;/code&gt;, &lt;code&gt;elicitation/create&lt;/code&gt;, &lt;code&gt;roots/list&lt;/code&gt; on a live stream&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;MRTR: &lt;code&gt;resultType: "input_required"&lt;/code&gt; plus &lt;code&gt;requestState&lt;/code&gt;, retried by the client with a new JSON-RPC id&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Subscriptions&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;resources/subscribe&lt;/code&gt; plus the GET SSE stream&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;subscriptions/listen&lt;/code&gt; with an explicit notification filter&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Caching&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;None&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; on six result types (the release blog says four and the changelog says five; the schema and the caching page say six)&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Long running work&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tasks, experimental, in core. Blocking &lt;code&gt;tasks/result&lt;/code&gt;, plus &lt;code&gt;tasks/list&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;io.modelcontextprotocol/tasks&lt;/code&gt; extension. Polling &lt;code&gt;tasks/get&lt;/code&gt;, plus &lt;code&gt;tasks/update&lt;/code&gt;. No &lt;code&gt;tasks/list&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Client registration&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;DCR (MAY) plus CIMD (SHOULD)&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;DCR deprecated. CIMD is the path. &lt;code&gt;application_type&lt;/code&gt; now MUST&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Issuer validation&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Not required&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;RFC 9207 &lt;code&gt;iss&lt;/code&gt; validation, MUST, including on error responses&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Logging&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;logging&lt;/code&gt; capability, &lt;code&gt;logging/setLevel&lt;/code&gt;, &lt;code&gt;notifications/message&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Deprecated. Per-request log level in &lt;code&gt;_meta&lt;/code&gt;, stderr, OpenTelemetry&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Liveness&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ping&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Removed&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Resource not found&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32002&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32602&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;MCP error codes&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32042&lt;/code&gt; (URL elicitation required)&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Three new codes, &lt;code&gt;-32020&lt;/code&gt; to &lt;code&gt;-32022&lt;/code&gt;, inside a reserved &lt;code&gt;-32020&lt;/code&gt; to &lt;code&gt;-32099&lt;/code&gt; block. &lt;code&gt;-32042&lt;/code&gt; retired&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Tool schemas&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;JSON Schema 2020-12 as default dialect&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Full 2020-12 keyword set. Network &lt;code&gt;$ref&lt;/code&gt; forbidden by default. DoS bounds required&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Tool lists&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;May vary per connection&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;MUST NOT vary per connection. SHOULD be deterministically ordered&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;experimental&lt;/code&gt; capability bag&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Formal extensions framework, reverse-DNS identifiers, opt-in, independently versioned&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Deprecation&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Ad hoc&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Formal policy. Twelve month floor, published registry, SDK obligations, ninety day security exception&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Result envelope&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Bare result object&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Required &lt;code&gt;resultType&lt;/code&gt; on every result&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What breaks, and what does not
&lt;/h2&gt;

&lt;p&gt;Compatibility is published in the specification itself, and that matrix has seven rows rather than the four most write-ups have been reproducing. The two rows that are usually dropped are the actionable ones.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Client&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Server&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Outcome&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Modern&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Modern&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Works&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Modern&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Fails&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Dual-era&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Modern&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Works&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Dual-era&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Works&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Modern&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Fails.&lt;/strong&gt; Legacy clients have no fall-forward mechanism&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Dual-era&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Works&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Legacy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Works per the legacy revision&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Modern means &lt;code&gt;2026-07-28&lt;/code&gt; and later, with per-request metadata. Legacy means &lt;code&gt;2025-11-25&lt;/code&gt; and earlier, with the &lt;code&gt;initialize&lt;/code&gt; handshake. Dual-era means an implementation that speaks both, which is the only posture that is safe if you have real users.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://pypi.org/project/mcp/" rel="noopener noreferrer"&gt;Python SDK v2&lt;/a&gt; gives you this by default, and it is worth understanding the mechanism rather than assuming it. &lt;code&gt;Server.run&lt;/code&gt; drives a dual-era loop in which &lt;strong&gt;the client's first request decides the connection's era, once&lt;/strong&gt;. A request carrying the &lt;code&gt;2026-07-28&lt;/code&gt; per-request &lt;code&gt;_meta&lt;/code&gt; envelope opens a modern connection; anything else, including an &lt;code&gt;initialize&lt;/code&gt; handshake, opens a legacy one. A later claim from the other era is then refused: &lt;code&gt;initialize&lt;/code&gt; on a modern connection returns &lt;code&gt;UNSUPPORTED_PROTOCOL_VERSION&lt;/code&gt; naming the versions served, and an enveloped request on a legacy connection returns &lt;code&gt;INVALID_REQUEST&lt;/code&gt;. So a v2 server serves both eras, per connection, not per request. One caveat that is not in the release notes and that I found in the source: HTTP era routing is header-based today, with body-primary classification marked as a follow-up.&lt;/p&gt;

&lt;p&gt;Twenty things break. Here they are by severity, where total means the implementation stops working entirely rather than degrading.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Change&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;What it breaks&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Severity&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;initialize&lt;/code&gt; and &lt;code&gt;notifications/initialized&lt;/code&gt; removed&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Every client and server implementing the handshake&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;Mcp-Session-Id&lt;/code&gt; and sessions removed&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any server holding per-session state, any client resuming a session&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Per-request &lt;code&gt;_meta&lt;/code&gt; with &lt;code&gt;protocolVersion&lt;/code&gt; and &lt;code&gt;clientCapabilities&lt;/code&gt; now required&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any request without them returns &lt;code&gt;-32602&lt;/code&gt; and HTTP &lt;code&gt;400&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;MCP-Protocol-Version&lt;/code&gt; header required and must match the body&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Mismatch returns &lt;code&gt;400&lt;/code&gt; with &lt;code&gt;-32020&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;Mcp-Method&lt;/code&gt; required on all requests, &lt;code&gt;Mcp-Name&lt;/code&gt; on three of them&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any hand-rolled HTTP client&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Server-initiated requests forbidden, MRTR replaces them&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Every server using sampling, elicitation or roots&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;The GET SSE stream is gone and resumability is removed. A modern-only server SHOULD answer GET and DELETE with &lt;code&gt;405&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any client relying on the GET stream or on &lt;code&gt;Last-Event-ID&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;resources/subscribe&lt;/code&gt; and &lt;code&gt;resources/unsubscribe&lt;/code&gt; removed&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any resource-subscription client&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tasks redesigned and moved to an extension&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Everyone on the experimental &lt;code&gt;2025-11-25&lt;/code&gt; Tasks API&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Total, for tasks users&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;resultType&lt;/code&gt; required on every result&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Clients not defaulting an absent value to &lt;code&gt;"complete"&lt;/code&gt;, or not handling &lt;code&gt;"input_required"&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Resource not found moves from &lt;code&gt;-32002&lt;/code&gt; to &lt;code&gt;-32602&lt;/code&gt;, and &lt;code&gt;-32042&lt;/code&gt; (URL elicitation required) must no longer be emitted&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any client matching on either literal code&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;notifications/cancelled&lt;/code&gt; is stdio-only. Streamable HTTP defines no client-to-server notifications; closing the SSE response stream is the cancellation signal&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any HTTP client that sends it, and any server that only cancels on receiving it&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ping&lt;/code&gt;, &lt;code&gt;logging/setLevel&lt;/code&gt; and &lt;code&gt;notifications/roots/list_changed&lt;/code&gt; removed&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Health-check loops and log-level control&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;notifications/elicitation/complete&lt;/code&gt; and &lt;code&gt;elicitationId&lt;/code&gt; removed&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;URL-mode elicitation correlation&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tool lists MUST NOT vary per connection&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any server personalising &lt;code&gt;tools/list&lt;/code&gt; per session rather than per token&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;High&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Any JSON Schema 2020-12 keyword is now allowed, but network &lt;code&gt;$ref&lt;/code&gt; resolution MUST be off by default and composition keywords need resource bounds&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Servers relying on remote &lt;code&gt;$ref&lt;/code&gt; resolution&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;An invalid &lt;code&gt;x-mcp-header&lt;/code&gt; forces the client to drop the tool from &lt;code&gt;tools/list&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Silent tool disappearance&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; are non-optional on six result types&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Servers omitting them are non-conformant&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;DCR deprecated and &lt;code&gt;application_type&lt;/code&gt; now required&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;OIDC-strict authorization servers rejecting native redirects&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;RFC 9207 &lt;code&gt;iss&lt;/code&gt; validation now MUST on the client side&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Clients that skip it are non-conformant&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Medium&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;What does not break is worth stating too, because it is more than you would expect. The stdio message framing is unchanged. Tools, resources, prompts, completion, pagination and progress keep their shapes. Elicitation survives in both form and URL modes, just delivered differently. And roots, sampling and logging are deprecated rather than removed, which means they are annotation-only and continue working for at least twelve months.&lt;/p&gt;

&lt;p&gt;There is one trap in era detection that is worth its own paragraph, because it is the thing implementations will get wrong, and the rules differ by transport.&lt;/p&gt;

&lt;p&gt;On HTTP you attempt a modern request and fall back on &lt;code&gt;400 Bad Request&lt;/code&gt;, except that a modern server also returns &lt;code&gt;400&lt;/code&gt; for &lt;code&gt;UnsupportedProtocolVersionError&lt;/code&gt;, for &lt;code&gt;MissingRequiredClientCapabilityError&lt;/code&gt;, and for header validation failures, so the specification says you SHOULD inspect the body before concluding anything. On stdio you probe with &lt;code&gt;server/discover&lt;/code&gt;, and there the rule is stronger: the fallback &lt;strong&gt;MUST NOT&lt;/strong&gt; be keyed to one specific error code. Era is a property of the server rather than of an individual request, so cache the determination for the lifetime of the server process on stdio, or of the origin on HTTP.&lt;/p&gt;

&lt;p&gt;One consequence of choosing dual-era that is easy to miss: the &lt;code&gt;405&lt;/code&gt; guidance for GET and DELETE is written for servers that support &lt;strong&gt;only&lt;/strong&gt; this revision. If you are serving both eras you still need the GET stream for legacy clients, so do not blanket-405 it.&lt;/p&gt;

&lt;h2&gt;
  
  
  It is also worth being straight about a tension in the messaging around all this. The operator of &lt;a href="https://glama.ai" rel="noopener noreferrer"&gt;Glama&lt;/a&gt;, who runs the largest open source MCP server index, wrote on &lt;a href="https://news.ycombinator.com/item?id=49088058" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; that "the new protocol is wire-incompatible in both directions. This means that many of the servers/clients will need to be refactored (not enough to just update the SDK). It will take time and it will be messy." A maintainer in the same thread wrote that "this protocol change doesn't require you to do anything to existing running MCP code." Both statements are true, about different situations. The second is true of a deployment nobody touches. The first is true the moment anything on the other end of the wire moves.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Every error you will hit upgrading to MCP 2026-07-28
&lt;/h2&gt;

&lt;p&gt;These are ordered roughly by how likely you are to see them.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;Unsupported protocol version&lt;/code&gt; after upgrading, error code &lt;code&gt;-32022&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the two eras failing to talk, and it is the most common thing you will see this week. The error carries the useful data in &lt;code&gt;error.data&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;-32022&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Unsupported protocol version"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"supported"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2025-11-25"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"requested"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1900-01-01"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;data.supported&lt;/code&gt; contains only old revisions, the server has not been upgraded. If it contains only &lt;code&gt;2026-07-28&lt;/code&gt;, the client has not. The fix in both directions is to serve both eras rather than to pick one, and the practical route to that is an SDK bump rather than hand-rolling the negotiation, because the negotiation has more edge cases than it looks like.&lt;/p&gt;

&lt;p&gt;One thing you cannot fix from the client side: a legacy client hitting a modern-only server. There is no fall-forward path in the older revisions, so that combination fails and will keep failing until the client updates. If you operate the server, this is the argument for staying dual-era well past the point where it feels necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;400 Bad Request&lt;/code&gt; with a &lt;code&gt;HeaderMismatch&lt;/code&gt; error, code &lt;code&gt;-32020&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Three headers are now required on every Streamable HTTP POST, and their values must match the body:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="nf"&gt;POST&lt;/span&gt; &lt;span class="nn"&gt;/mcp&lt;/span&gt; &lt;span class="k"&gt;HTTP&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="m"&gt;1.1&lt;/span&gt;
&lt;span class="na"&gt;MCP-Protocol-Version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-07-28&lt;/span&gt;
&lt;span class="na"&gt;Mcp-Method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;tools/call&lt;/span&gt;
&lt;span class="na"&gt;Mcp-Name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;search&lt;/span&gt;
&lt;span class="na"&gt;Content-Type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;application/json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is worth stating the scope of these precisely, because it is easy to over-apply them. &lt;code&gt;Mcp-Method&lt;/code&gt; is required on all requests. In the core protocol &lt;code&gt;Mcp-Name&lt;/code&gt; is required only on &lt;code&gt;tools/call&lt;/code&gt;, &lt;code&gt;resources/read&lt;/code&gt; and &lt;code&gt;prompts/get&lt;/code&gt;, where it carries &lt;code&gt;params.name&lt;/code&gt; or &lt;code&gt;params.uri&lt;/code&gt;. Sending &lt;code&gt;Mcp-Name&lt;/code&gt; on a &lt;code&gt;tools/list&lt;/code&gt; is not what the specification asks for.&lt;/p&gt;

&lt;p&gt;The tasks extension then adds three more. SEP-2663 requires that &lt;code&gt;tasks/get&lt;/code&gt;, &lt;code&gt;tasks/update&lt;/code&gt; and &lt;code&gt;tasks/cancel&lt;/code&gt; over Streamable HTTP set &lt;code&gt;Mcp-Name&lt;/code&gt; to &lt;code&gt;params.taskId&lt;/code&gt;, so that "transport intermediaries and load balancers [can] route subsequent requests for the same task to the server instance holding its state, which is typically required for correctness." Worth sitting with that sentence for a moment. It is discussed further below.&lt;/p&gt;

&lt;p&gt;Note also that &lt;code&gt;MCP-Protocol-Version&lt;/code&gt; is not new. It has been required on HTTP since &lt;code&gt;2025-06-18&lt;/code&gt;. The two genuinely new mandatory headers are &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt;, plus any &lt;code&gt;Mcp-Param-*&lt;/code&gt; your tools opt into.&lt;/p&gt;

&lt;p&gt;Header names are case-insensitive and header values are case-sensitive, and for integers the comparison should be numeric rather than string, so &lt;code&gt;42.0&lt;/code&gt; and &lt;code&gt;42&lt;/code&gt; match.&lt;/p&gt;

&lt;p&gt;There is a real caveat, and it was published a week before the specification landed. &lt;a href="https://agentgateway.dev/blog/2026-07-21-stateless-mcp-still-needs-mcp-native-dataplane/" rel="noopener noreferrer"&gt;Christian Posta at Solo.io pointed out&lt;/a&gt; that headers can lie: an attacker sends &lt;code&gt;Mcp-Name: echo&lt;/code&gt; in the header while the body calls &lt;code&gt;printEnv&lt;/code&gt;, and a proxy that allowlists on headers alone waves it through.&lt;/p&gt;

&lt;p&gt;Two mitigations exist. A server that processes the body MUST reject mismatches with &lt;code&gt;-32020&lt;/code&gt;. And intermediaries enforcing policy on mirrored headers SHOULD verify that &lt;code&gt;MCP-Protocol-Version&lt;/code&gt; indicates a revision requiring header-body validation, and SHOULD reject rather than trust the headers otherwise. Both are correct. The second is also a SHOULD placed on the component with the least incentive to comply, and it requires the intermediary to be MCP-version-aware, which is precisely the MCP-native dataplane Posta is arguing for. His post ends with a working fix rather than a dead end. Read it that way, and treat these headers as a routing hint rather than an authorization fact.&lt;/p&gt;

&lt;p&gt;There is an operational failure here that has nothing to do with your code. Check whether your reverse proxy, your CDN, or your API gateway strips unknown request headers, because these headers will vanish silently on the way to your server and every request will fail validation for a reason that is invisible from either end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your server-initiated requests stopped working
&lt;/h3&gt;

&lt;p&gt;Servers cannot originate requests any more. This is not a restriction on when they may do it; there is no &lt;code&gt;ServerRequest&lt;/code&gt; union in the schema at all. &lt;code&gt;sampling/createMessage&lt;/code&gt;, &lt;code&gt;elicitation/create&lt;/code&gt; and &lt;code&gt;roots/list&lt;/code&gt; still exist as types, but only ever as payloads inside a result.&lt;/p&gt;

&lt;p&gt;MRTR is the replacement. Your server returns an incomplete result naming what it needs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jsonrpc"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"result"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resultType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"input_required"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"inputRequests"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"github_login"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"method"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"elicitation/create"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"params"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"mode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"form"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Please provide your GitHub username"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="nl"&gt;"requestedSchema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"properties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"string"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"required"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"requestState"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AEAD-protected blob"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The client gathers the input and re-sends the original request with &lt;code&gt;inputResponses&lt;/code&gt; and the &lt;code&gt;requestState&lt;/code&gt; echoed back byte for byte, using a &lt;strong&gt;new&lt;/strong&gt; JSON-RPC id, because the specification treats the retry as an independent request.&lt;/p&gt;

&lt;p&gt;Six rules will bite you if you skip them. &lt;code&gt;InputRequiredResult&lt;/code&gt; is permitted only on &lt;code&gt;tools/call&lt;/code&gt;, &lt;code&gt;prompts/get&lt;/code&gt; and &lt;code&gt;resources/read&lt;/code&gt;, and servers MUST NOT send it on anything else. Clients MUST NOT inspect, parse or modify &lt;code&gt;requestState&lt;/code&gt;, and MUST NOT include one on the retry if the server did not send one. Servers MUST NOT send an &lt;code&gt;inputRequest&lt;/code&gt; type the client did not declare on that particular request. Servers MUST NOT assume the client will ever fulfil the request or retry at all, which means every MRTR exchange needs a timeout and a clean path to giving up. And &lt;code&gt;inputRequests&lt;/code&gt; and &lt;code&gt;requestState&lt;/code&gt; apply only to the retry of that one request, never to anything the client has in flight in parallel.&lt;/p&gt;

&lt;p&gt;The sixth is the one that will produce a crash rather than a bug report. &lt;code&gt;inputRequests&lt;/code&gt; &lt;strong&gt;is optional.&lt;/strong&gt; The schema requires at least one of &lt;code&gt;inputRequests&lt;/code&gt; or &lt;code&gt;requestState&lt;/code&gt;, and it names the case where only the state is present: load shedding. A server under pressure can hand back &lt;code&gt;requestState&lt;/code&gt; alone, and the specification says the client MAY then simply retry immediately. Any client that writes &lt;code&gt;for key in result.inputRequests&lt;/code&gt; throws on that response, at precisely the moment the server is least able to absorb a retry storm.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;MissingRequiredClientCapability&lt;/code&gt;, error code &lt;code&gt;-32021&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;Capabilities are now declared per request rather than once per connection, and a server may not rely on one the client did not send on that specific request. When it needs something undeclared it returns &lt;code&gt;-32021&lt;/code&gt; with the missing capabilities listed in &lt;code&gt;data.requiredCapabilities&lt;/code&gt;, and on HTTP the status is &lt;code&gt;400&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the client side, stop treating capabilities as connection setup. They belong in &lt;code&gt;_meta&lt;/code&gt; on every call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"_meta"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/protocolVersion"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2026-07-28"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/clientCapabilities"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"elicitation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"io.modelcontextprotocol/clientInfo"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;protocolVersion&lt;/code&gt; and &lt;code&gt;clientCapabilities&lt;/code&gt; are required. &lt;code&gt;clientInfo&lt;/code&gt; is optional but you should send it, and the specification is clear that neither &lt;code&gt;clientInfo&lt;/code&gt; nor &lt;code&gt;serverInfo&lt;/code&gt; is verified by the protocol, so nothing should make a security decision based on either.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resource not found now returns &lt;code&gt;-32602&lt;/code&gt;, not &lt;code&gt;-32002&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;The error code layout changed underneath everyone. Two codes that shipped in &lt;code&gt;2025-11-25&lt;/code&gt; are retired, and three new ones arrive in a newly reserved block.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Code&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Shipped in&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Status in &lt;code&gt;2026-07-28&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32002&lt;/code&gt;, resource not found&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;2025-11-25&lt;/code&gt; and earlier&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Retired. Use &lt;code&gt;-32602&lt;/code&gt;. Clients SHOULD keep accepting it from older servers&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32042&lt;/code&gt;, URL elicitation required&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;2025-11-25&lt;/code&gt; only&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Retired. Implementations of this revision MUST NOT emit it&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32020&lt;/code&gt;, header mismatch&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;new&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Reserved block&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32021&lt;/code&gt;, missing required client capability&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;new&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Reserved block&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;-32022&lt;/code&gt;, unsupported protocol version&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;new&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Reserved block&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Codes from &lt;code&gt;-32020&lt;/code&gt; to &lt;code&gt;-32099&lt;/code&gt; are now reserved for the specification, and implementations must not emit codes in it that the specification has not defined. The range &lt;code&gt;-32000&lt;/code&gt; to &lt;code&gt;-32019&lt;/code&gt; is legacy, and apart from &lt;code&gt;-32002&lt;/code&gt; receivers must not assume any specific meaning for codes in it.&lt;/p&gt;

&lt;p&gt;One clarification, because several write-ups have this wrong, including an earlier version of this one. The three new codes were briefly numbered &lt;code&gt;-32001&lt;/code&gt;, &lt;code&gt;-32003&lt;/code&gt; and &lt;code&gt;-32004&lt;/code&gt; &lt;strong&gt;inside the&lt;/strong&gt; &lt;code&gt;2026-07-28&lt;/code&gt; &lt;strong&gt;draft cycle&lt;/strong&gt; and renumbered before release. They were never part of &lt;code&gt;2025-11-25&lt;/code&gt;, whose schema defines exactly one non-standard code, &lt;code&gt;-32042&lt;/code&gt;. So if you are migrating from a shipped &lt;code&gt;2025-11-25&lt;/code&gt; implementation, the codes that actually change under you are &lt;code&gt;-32002&lt;/code&gt; and &lt;code&gt;-32042&lt;/code&gt;. If you built against a release candidate, check for the old three.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your tool disappeared from &lt;code&gt;tools/list&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;This is the most obscure genuinely breaking behaviour in the release, because it produces no JSON-RPC error, and because it is transport-dependent in a way that will waste somebody an afternoon.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;x-mcp-header&lt;/code&gt; is a new annotation that lets a server mark individual tool parameters to be mirrored into &lt;code&gt;Mcp-Param-{Name}&lt;/code&gt; HTTP headers, so that a gateway can route or rate-limit on a parameter value without reading the body. It is optional for servers and mandatory for clients to support. The constraints on it are strict: primitive types only, with &lt;code&gt;number&lt;/code&gt; explicitly not permitted while integer, string and boolean are; the property must be statically reachable from the schema root through a chain of &lt;code&gt;properties&lt;/code&gt; keys only, so nothing behind &lt;code&gt;items&lt;/code&gt;, &lt;code&gt;$ref&lt;/code&gt;, &lt;code&gt;oneOf&lt;/code&gt;, &lt;code&gt;anyOf&lt;/code&gt;, &lt;code&gt;allOf&lt;/code&gt;, &lt;code&gt;not&lt;/code&gt;, or &lt;code&gt;if&lt;/code&gt;/&lt;code&gt;then&lt;/code&gt;/&lt;code&gt;else&lt;/code&gt;; the value must be case-insensitively unique across the whole &lt;code&gt;inputSchema&lt;/code&gt;; annotated integers must sit within the JavaScript safe range; and the value must be a valid HTTP field-name token with no control characters.&lt;/p&gt;

&lt;p&gt;If any of those is violated, the client MUST exclude the tool from the result of &lt;code&gt;tools/list&lt;/code&gt;. There is no JSON-RPC error. The specification does ask clients to log a warning naming the tool and the reason, but that is a SHOULD and it surfaces in your client's log rather than to the model or the user, so the tool simply is not there any more and nothing in the conversation says why.&lt;/p&gt;

&lt;p&gt;What will actually cost you the afternoon is that this rule binds &lt;strong&gt;Streamable HTTP clients only&lt;/strong&gt;. Clients on other transports MAY ignore &lt;code&gt;x-mcp-header&lt;/code&gt; entirely. So the same server, with the same tool definition, can expose the tool over stdio on your laptop and hide it over HTTP in production.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;400&lt;/code&gt; with no obvious cause, and a missing &lt;code&gt;Accept&lt;/code&gt; header
&lt;/h3&gt;

&lt;p&gt;Not new, but hand-rolled clients get it wrong constantly and this revision gives them more opportunities to. The client MUST include an &lt;code&gt;Accept&lt;/code&gt; header listing both &lt;code&gt;application/json&lt;/code&gt; and &lt;code&gt;text/event-stream&lt;/code&gt;, because the server chooses between a single JSON response and an SSE stream and the client has to be ready for either.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;404 Not Found&lt;/code&gt; on a method the server does not implement
&lt;/h3&gt;

&lt;p&gt;This one is a trap for gateways and for anyone with retry logic. An unimplemented RPC method returns HTTP &lt;code&gt;404&lt;/code&gt; with JSON-RPC &lt;code&gt;-32601&lt;/code&gt;, which is deliberately distinguishable from a transport-level failure. Anything that treats &lt;code&gt;404&lt;/code&gt; as "this server is gone" and tears down the connection or fails over will misbehave against a perfectly healthy server that simply does not implement the method you asked for. Check the body before concluding anything about a &lt;code&gt;404&lt;/code&gt;, exactly as you already have to for a &lt;code&gt;400&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your list results are being served to the wrong tenant
&lt;/h3&gt;

&lt;p&gt;Not an error message, which is why it belongs here. &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; are now non-optional on six result types: &lt;code&gt;server/discover&lt;/code&gt;, &lt;code&gt;tools/list&lt;/code&gt;, &lt;code&gt;prompts/list&lt;/code&gt;, &lt;code&gt;resources/list&lt;/code&gt;, &lt;code&gt;resources/templates/list&lt;/code&gt; and &lt;code&gt;resources/read&lt;/code&gt;. Worth noting that the release blog lists four of those and the changelog lists five; the schema and the caching page say six, and they are the ones that count.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cacheScope&lt;/code&gt; takes &lt;code&gt;"public"&lt;/code&gt;, meaning any client, gateway or caching proxy may serve the response to any user, or &lt;code&gt;"private"&lt;/code&gt;, meaning it may be reused only within the same authorization context and MUST NOT be shared across contexts. Get this wrong on an authenticated endpoint and you have built a cross-tenant data leak with the protocol's blessing. The specification says so almost in those words: servers must be aware that a &lt;code&gt;"public"&lt;/code&gt; response may be shared between callers even when it comes from an authenticated endpoint.&lt;/p&gt;

&lt;p&gt;Two rules that follow. Results produced by an MRTR retry must never be cached, because they depend on inputs that are not part of the cache key. And clients SHOULD NOT treat &lt;code&gt;ttlMs&lt;/code&gt; as a polling interval; those that do poll MUST apply jitter and backoff, which is the single most likely way a naive client turns a TTL into a thundering herd.&lt;/p&gt;

&lt;h3&gt;
  
  
  Long-running jobs broke when sessions went away
&lt;/h3&gt;

&lt;p&gt;One of the sharper reactions on Hacker News was from someone who uses MCP servers to monitor workflows that run for days, and who wrote simply that "i use them to monitor workflows that takes days and now i have to make some changes."&lt;/p&gt;

&lt;p&gt;Tasks, now an extension, is the replacement, and it is a second migration for anyone who adopted the experimental API in &lt;code&gt;2025-11-25&lt;/code&gt;. What changed:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;2025-11-25&lt;/code&gt;, experimental&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;io.modelcontextprotocol/tasks&lt;/code&gt; extension&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Client opts in per request with a &lt;code&gt;task: {ttl}&lt;/code&gt; param&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;The server decides, unilaterally, per request&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/get&lt;/code&gt; plus a blocking &lt;code&gt;tasks/result&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/result&lt;/code&gt; removed; &lt;code&gt;tasks/get&lt;/code&gt; absorbs its job and polls, honouring &lt;code&gt;pollIntervalMs&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No client-to-server input method&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/update&lt;/code&gt; carrying &lt;code&gt;inputResponses&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/list&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Removed. There is no way to enumerate tasks&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;notifications/tasks/status&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;notifications/tasks&lt;/code&gt;, opt in via &lt;code&gt;subscriptions/listen&lt;/code&gt; with a &lt;code&gt;taskIds&lt;/code&gt; filter&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ttl&lt;/code&gt;, &lt;code&gt;pollInterval&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ttlMs&lt;/code&gt;, &lt;code&gt;pollIntervalMs&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/cancel&lt;/code&gt; returns the task&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tasks/cancel&lt;/code&gt; returns a bare acknowledgement; cancellation is cooperative and the server need only acknowledge&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Both parties can be requestors&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;tools/call&lt;/code&gt; only&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two consequences of that table deserve calling out. Because &lt;code&gt;tasks/list&lt;/code&gt; is gone, if your client loses a task id the task is unreachable, so persist task ids durably rather than holding them in memory. And because the extension must be negotiated in &lt;code&gt;_meta&lt;/code&gt; on each request, a server MUST NOT return a task handle to a client that did not declare the extension on that specific call.&lt;/p&gt;

&lt;p&gt;One detail that will catch people moving off &lt;code&gt;resources/subscribe&lt;/code&gt;: request-scoped notifications, meaning &lt;code&gt;notifications/progress&lt;/code&gt; and &lt;code&gt;notifications/message&lt;/code&gt;, still flow on the response stream of the request they belong to, &lt;strong&gt;not&lt;/strong&gt; on the &lt;code&gt;subscriptions/listen&lt;/code&gt; stream. And on stdio, if the connection drops the client MUST re-send &lt;code&gt;subscriptions/listen&lt;/code&gt;, because the server holds no subscription state across reconnections.&lt;/p&gt;

&lt;p&gt;One caveat before you build on this, and it is a real one. The extension's normative schema file is not published. The repository states it "is under development and is working towards implementing the changes described in SEP-2663", and carries a banner reading "&lt;strong&gt;not&lt;/strong&gt; an official extension and may change significantly or be discontinued", while the &lt;code&gt;2026-07-28&lt;/code&gt; changelog describes tasks as having moved into "an official extension." SEP-2663 itself still cites &lt;code&gt;-32003&lt;/code&gt;, an error code the shipped core renumbered to &lt;code&gt;-32021&lt;/code&gt;. Treat this part of the ecosystem as unfinished and budget for a second pass.&lt;/p&gt;

&lt;h3&gt;
  
  
  Your traces and your latency numbers went wrong
&lt;/h3&gt;

&lt;p&gt;This one is quiet and it affects everyone who has &lt;a href="https://www.maximem.ai/glossary/observability" rel="noopener noreferrer"&gt;observability&lt;/a&gt; wired up. Because the MRTR retry MUST use a different JSON-RPC id from the original request, one logical operation now appears on the wire as several id-distinct requests with no correlation identifier between them.&lt;/p&gt;

&lt;p&gt;Every tool that keys on request id, which is all of them, therefore reports an inflated call count and, worse, excludes the interval where a human was actually deciding something. That interval is precisely the thing you care about for an elicitation-based confirmation. An &lt;a href="https://github.com/kerlenton/mcpsnoop/blob/main/docs/2026-07-28-mrtr-breaks-latency.md" rel="noopener noreferrer"&gt;analysis published on release day&lt;/a&gt; measured a six second operation reporting as two calls totalling one second. That is one scripted exchange against the author's own proxy rather than a survey, so treat it as an illustration of the mechanism rather than a measurement of the blast radius. The mechanism is the part that generalises.&lt;/p&gt;

&lt;p&gt;There is no protocol-level fix. Linkage has to be inferred, either from the opaque &lt;code&gt;requestState&lt;/code&gt; blob or by matching the key sets in &lt;code&gt;inputResponses&lt;/code&gt; against the &lt;code&gt;inputRequests&lt;/code&gt; that produced them. It is worth noticing that the same revision standardised W3C trace context propagation, with &lt;code&gt;traceparent&lt;/code&gt;, &lt;code&gt;tracestate&lt;/code&gt; and &lt;code&gt;baggage&lt;/code&gt; explicitly exempted from the reverse-DNS prefix rule in &lt;code&gt;_meta&lt;/code&gt;. The plumbing got better and the semantics got worse in the same release.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization started failing on desktop and CLI clients
&lt;/h3&gt;

&lt;p&gt;If a client is going to break against a strict enterprise authorization server on day one, this is why. Clients MUST now specify &lt;code&gt;application_type&lt;/code&gt; during Dynamic Client Registration, and omitting it defaults to &lt;code&gt;"web"&lt;/code&gt; under OpenID Connect, which conflicts with the &lt;code&gt;localhost&lt;/code&gt; redirect URIs that desktop applications, mobile applications and CLI tools use. Native clients should send &lt;code&gt;application_type: "native"&lt;/code&gt;; genuinely remote browser-based clients should send &lt;code&gt;"web"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Two other authorization changes are worth checking before you ship. RFC 9207 issuer validation is now mandatory on the client side and it applies to error responses as well as success responses. You do decode the &lt;code&gt;iss&lt;/code&gt; value from the form-encoded response, and then you compare it as a literal string: no scheme or host case folding, no default-port elision, no trailing-slash handling and no percent-encoding normalisation. Note that authorization servers only SHOULD send &lt;code&gt;iss&lt;/code&gt;, so whether its absence is fatal depends on the server advertising &lt;code&gt;authorization_response_iss_parameter_supported&lt;/code&gt;. And persisted client credentials must now be keyed to the issuing authorization server's &lt;code&gt;issuer&lt;/code&gt;, so when the authorization server changes you must re-register rather than reuse.&lt;/p&gt;

&lt;h3&gt;
  
  
  SDK readiness, as of 29 July 2026
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;SDK&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Tier&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Version with &lt;code&gt;2026-07-28&lt;/code&gt;&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;TypeScript&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;@modelcontextprotocol/server@2.0.0&lt;/code&gt; and &lt;code&gt;@modelcontextprotocol/client@2.0.0&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Python&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;mcp==2.0.0&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Go&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;go-sdk v1.7.0&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;C#&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;1&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;ModelContextProtocol 2.0.0&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Rust&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;2&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;rmcp 3.0.0&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Java&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;2&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;No support yet&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Swift, Ruby, PHP, Kotlin&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;3&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No support, no committed timeline&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Two notes on that table. Java does have a &lt;code&gt;2.0.0&lt;/code&gt;, published on 11 June 2026, and it simply predates this revision; the jar contains &lt;code&gt;2025-11-25&lt;/code&gt; and earlier and no &lt;code&gt;2026-07-28&lt;/code&gt; at all. Java is a Tier 2 SDK, which carries a six month obligation, so support is due around January 2027. And on TypeScript, v2 is ESM-only, requires Node 20 or later, and splits the old monolith into separate server and client packages, which is a larger change than the version number suggests. There is a codemod: &lt;code&gt;npx @modelcontextprotocol/codemod v1-to-v2 .&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you maintain a library that depends on an MCP SDK, put an upper bound on it today, &lt;code&gt;mcp&amp;gt;=1.28,&amp;lt;2&lt;/code&gt; or &lt;code&gt;@modelcontextprotocol/sdk@^1&lt;/code&gt;, so that v2 does not land on your users before you have decided how to handle it.&lt;/p&gt;







&lt;h2&gt;
  
  
  Before and after, in two pictures
&lt;/h2&gt;

&lt;p&gt;If you came here with a red terminal, that is the practical half. What follows is why any of it happened.&lt;/p&gt;

&lt;p&gt;Two diagrams, each showing the same two things: how the protocol deploys, and what actually goes over the wire. Those turned out to be the same question, which is the whole reason this revision exists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.maximem.ai%2Fimg%2Fmcp-before-2025-11-25.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.maximem.ai%2Fimg%2Fmcp-before-2025-11-25.svg" alt="MCP client and server engagement before the 2026-07-28 revision: a stateful, connection-scoped pattern where a session is created at the handshake and pins every subsequent request to one server process" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That orange band running down the middle of the first diagram is the argument for the entire release. It is the session lifetime, and the line written across it says that every request underneath it must reach server instance number one. That constraint is not a &lt;a href="https://www.maximem.ai/glossary/deployment" rel="noopener noreferrer"&gt;deployment&lt;/a&gt; choice you made. It is a property of the protocol, because the negotiated capabilities and every in-flight request lived in one server process, so the load balancer had no option but to pin. Two of the three instances in that picture are unreachable for the duration of the session, the shared session store hanging off the side is pure protocol overhead you provisioned and paid for, and the gateway in the middle cannot route on anything useful because every call is &lt;code&gt;POST /mcp&lt;/code&gt; with the operation buried in the body.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.maximem.ai%2Fimg%2Fmcp-after-2026-07-28.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.maximem.ai%2Fimg%2Fmcp-after-2026-07-28.svg" alt="MCP client and server engagement after the 2026-07-28 revision: a stateless, self-describing pattern where every request carries its own version and capabilities and any server instance can answer it" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The payoff in the second diagram is small and easy to miss, so it is worth pointing at directly. Step three is a &lt;code&gt;tools/call&lt;/code&gt; that lands on instance three. Step four is that same logical call being retried, after the client gathers the input the server asked for, and it lands on instance two. A different box, mid-operation, and nothing breaks. That is what statelessness actually buys, and it is very hard to convey in prose.&lt;/p&gt;

&lt;p&gt;Two wins and two new burdens sit in the consequence strip at the bottom of the second diagram, and the mix is deliberate, because that is an accurate picture of the trade. Autoscale and serverless become native. In exchange, &lt;code&gt;requestState&lt;/code&gt; is now an attacker-controlled input you have to authenticate yourself, and the MRTR retry carries a new JSON-RPC id, which quietly breaks anything measuring latency by request id.&lt;/p&gt;







&lt;h2&gt;
  
  
  What the release fixed, and what it left alone
&lt;/h2&gt;

&lt;p&gt;MCP has been shipping for twenty months and accumulating a fairly specific critique record the whole time. The interesting way to read &lt;code&gt;2026-07-28&lt;/code&gt; is not as a list of features but as a response to that record, ranked by whether the specification deleted the thing being complained about. A protocol that removes the feature people objected to is conceding the argument in the plainest language available.&lt;/p&gt;

&lt;p&gt;Strongest evidence that this is what happened: the maintainers wrote the critique themselves, ten months before shipping the fix. From &lt;a href="https://blog.modelcontextprotocol.io/posts/2025-12-19-mcp-transport-future/" rel="noopener noreferrer"&gt;"Exploring the Future of MCP Transports"&lt;/a&gt;, published 19 December 2025:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Stateful connections force 'sticky' routing that pins traffic to specific servers, preventing effective auto-scaling."&lt;/p&gt;

&lt;p&gt;"Developers building simple, ephemeral tools are often required to manage complex backend storage to support basic multi-turn interactions."&lt;/p&gt;

&lt;p&gt;"Load balancers and API gateways must parse full JSON-RPC payloads to route traffic, rather than using standard HTTP patterns."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An earlier post, &lt;a href="https://blog.modelcontextprotocol.io/posts/2025-09-26-mcp-next-version-update/" rel="noopener noreferrer"&gt;"Update on the Next MCP Protocol Release"&lt;/a&gt; from September 2025, had already named horizontal scaling, long-running tasks, discovery, extensions and SDK &lt;a href="https://www.maximem.ai/glossary/compliance" rel="noopener noreferrer"&gt;compliance&lt;/a&gt; as the top five gaps.&lt;/p&gt;

&lt;p&gt;Five external critiques were louder than the rest. &lt;strong&gt;Statefulness and session affinity&lt;/strong&gt;, whose root cause was precise: the handshake negotiated capabilities per connection, the session identifier lived in the transport, and both meant every request had to reach the same process. &lt;a href="https://thenewstack.io/mcp-release-candidate-rewrite/" rel="noopener noreferrer"&gt;The New Stack&lt;/a&gt; put it as teams "paying to solve a distributed-systems problem the protocol had created for them." &lt;strong&gt;The tool-definition context tax&lt;/strong&gt;, where &lt;a href="https://www.apideck.com/blog/mcp-server-eating-context-window-cli-alternative" rel="noopener noreferrer"&gt;Apideck measured three MCP servers consuming 143,000 of a 200,000 token window&lt;/a&gt; before a single user message, and where the most damning source is Anthropic itself, which &lt;a href="https://www.anthropic.com/engineering/code-execution-with-mcp" rel="noopener noreferrer"&gt;published a method for taking 150,000 tokens down to 2,000&lt;/a&gt;, roughly a 98.7% reduction, by not using the protocol the way it was designed. &lt;strong&gt;&lt;a href="https://www.maximem.ai/glossary/prompt-injection" rel="noopener noreferrer"&gt;Prompt injection&lt;/a&gt;&lt;/strong&gt;, where &lt;a href="https://invariantlabs.ai/blog/mcp-github-vulnerability" rel="noopener noreferrer"&gt;Invariant Labs demonstrated data exfiltration through the GitHub MCP server&lt;/a&gt; and concluded that "GitHub alone cannot resolve this vulnerability through server-side patches," which is what makes it architectural rather than a bug. &lt;strong&gt;The absence of an authorization model&lt;/strong&gt;, summarised by &lt;a href="https://www.pomerium.com/blog/why-the-managed-context-protocol-mcp-spec-still-leaves-gaping-security-holes" rel="noopener noreferrer"&gt;Pomerium&lt;/a&gt; as "access is binary. Either a tool is exposed, or it isn't." And &lt;strong&gt;gateway hostility&lt;/strong&gt;, which is the same root cause as the first one seen from the operations side.&lt;/p&gt;

&lt;p&gt;Below those sit the rest: &lt;a href="https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/" rel="noopener noreferrer"&gt;Microsoft Research measuring performance degradation of up to 85% as the tool space grows, along with 775 colliding tool names and the word&lt;/a&gt; &lt;code&gt;search&lt;/code&gt; &lt;a href="https://www.microsoft.com/en-us/research/blog/tool-space-interference-in-the-mcp-era-designing-for-agent-compatibility-at-scale/" rel="noopener noreferrer"&gt;appearing across 32 distinct servers&lt;/a&gt;; the OAuth and Dynamic Client Registration burden that &lt;a href="https://www.descope.com/blog/post/enterprise-mcp" rel="noopener noreferrer"&gt;Descope catalogued as an enterprise blocker&lt;/a&gt;; the &lt;a href="https://julsimon.medium.com/why-mcps-disregard-for-40-years-of-rpc-best-practices-will-burn-enterprises-8ef85ce5bc9b" rel="noopener noreferrer"&gt;missing distributed-systems contract around idempotency, deadlines and tracing&lt;/a&gt;; and the absence of any asynchronous operation model.&lt;/p&gt;

&lt;p&gt;One disclosure belongs here rather than in a footer, because it changes how you should read half of those links. &lt;a href="https://www.speakeasy.com" rel="noopener noreferrer"&gt;Speakeasy&lt;/a&gt;, &lt;a href="https://www.scalekit.com" rel="noopener noreferrer"&gt;Scalekit&lt;/a&gt;, Descope, &lt;a href="https://workos.com" rel="noopener noreferrer"&gt;WorkOS&lt;/a&gt;, Pomerium, &lt;a href="https://www.docker.com" rel="noopener noreferrer"&gt;Docker&lt;/a&gt; and Apideck all sell products that exist because of the gaps they document. Their measurements are checkable and I have used several of them. Their framing is not neutral, and neither is mine, since Maximem ships tooling in this space too. Microsoft Research, &lt;a href="https://blog.trailofbits.com" rel="noopener noreferrer"&gt;Trail of Bits&lt;/a&gt;, Invariant Labs and Anthropic's own engineering blog are the cleanest sources in that list.&lt;/p&gt;

&lt;p&gt;So, the scorecard. Eighteen critiques, mapped against what actually shipped.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Critique&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;What &lt;code&gt;2026-07-28&lt;/code&gt; does&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Verdict&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Statefulness and session affinity&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Sessions, &lt;code&gt;initialize&lt;/code&gt; and the GET stream deleted. State becomes an explicit handle&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Solved&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tool-definition context tax&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Deterministic tool ordering, cacheable &lt;code&gt;tools/list&lt;/code&gt;. Neither reduces what the model sees&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Prompt injection and the lethal trifecta&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Nothing&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No authorization model&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Nothing. Scope step-up, which is often credited to this release, shipped in &lt;code&gt;2025-11-25&lt;/code&gt;. Modelling went to the &lt;code&gt;ext-auth&lt;/code&gt; extensions repo&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tool poisoning, rug pulls, line jumping&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Nothing. Descriptions remain unsigned and mutable&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tool-space interference, no namespacing&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Name-format rules, and clients "SHOULD implement a disambiguation strategy"&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Weak partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Auth complexity and the DCR burden&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;iss&lt;/code&gt; validation, credential-issuer binding and &lt;code&gt;application_type&lt;/code&gt; are real. But CIMD was already SHOULD and DCR already MAY in &lt;code&gt;2025-11-25&lt;/code&gt;, so the registration delta is largely a Deprecated label&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Gateway, WAF, metering and caching hostility&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt; headers, &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Solved&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Missing distributed-systems contract&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tracing yes, schema strictness yes, versioning discipline yes. Idempotency, deadlines and per-tool versioning no&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No long-running or async model&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tasks extension with polling, updates, cancellation and a durability guarantee. But its normative schema is unpublished and its own repository says it is not an official extension&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No multi-tenancy primitive&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Nothing, beyond &lt;code&gt;cacheScope: "private"&lt;/code&gt; being authorization-context aware&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Transport churn&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;One transport story now, but this release &lt;strong&gt;is&lt;/strong&gt; churn: the third breaking transport shape in sixteen months. The improvement is that churn is finally governed by a deprecation policy&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Neutral&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Configuration fragility&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Removes session config as a failure class, adds header validation as a new one&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Neutral&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Latency at the call level&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;No handshake, so the first-call penalty disappears. Cacheable lists cut repeat cost&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Improved&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Registry and discovery&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;code&gt;server/discover&lt;/code&gt; per server. The registry itself still has no protocol-version field&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Observability gap&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Trace context standardised, then MRTR breaks id-keyed measurement&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Mixed&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Risk stratification and cost opacity&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Nothing in core&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Untouched&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SDK quality and compliance opacity&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SDK tiering itself is SEP-1730, from October 2025. This release adds Tier 1 deprecation-marking obligations and conformance tests as a gate to Final&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Partial&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Three clear wins, nine partial or mixed, six untouched.&lt;/p&gt;

&lt;p&gt;I want to be explicit that I graded this twice, because the first pass was too generous. It credited this release with a scope step-up flow that shipped eight months earlier in &lt;code&gt;2025-11-25&lt;/code&gt;, rated long-running work solved on an extension whose normative schema does not exist, called transport churn solved in the release that caused it, and counted the registration changes as a fix when CIMD was already SHOULD and DCR already MAY. Correcting all four made the pattern sharper rather than softer, which is usually a sign the pattern is real rather than an artifact of how you drew the table.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;2026-07-28&lt;/code&gt; &lt;strong&gt;is an infrastructure release, not an agent-experience release.&lt;/strong&gt; Every problem that lives between a load balancer and a server process got fixed. Every problem that lives between a model and a tool description did not.&lt;/p&gt;

&lt;p&gt;Those untouched rows are worth sitting with, because they are the ones that most consistently kept MCP out of production. The context tax got deterministic tool ordering, which improves prompt-cache hit rates at the margin and is the entire response to a complaint that produced six separate front-page Hacker News threads and a first-party Anthropic post documenting a 98.7% workaround. Prompt injection got nothing, and tool descriptions are still unsigned, still mutable after a user has approved them, and still injected into the model's context at &lt;code&gt;tools/list&lt;/code&gt; time, which is the mechanism behind &lt;a href="https://blog.trailofbits.com/2025/04/21/jumping-the-line-how-mcp-servers-can-attack-you-before-you-ever-use-them/" rel="noopener noreferrer"&gt;what Trail of Bits named line jumping&lt;/a&gt; and the reason invocation-time approval was never the protection people assumed it was. Authorization modelling got nothing, and it is worth correcting a claim I have seen in several write-ups including my own first draft: the step-up flow with &lt;code&gt;insufficient_scope&lt;/code&gt; shipped in &lt;code&gt;2025-11-25&lt;/code&gt;, not here. What this release adds is authorization &lt;em&gt;hardening&lt;/em&gt;, which is real. Authorization &lt;em&gt;modelling&lt;/em&gt;, meaning per-tool scope and identity propagation into the tool, went to an extensions repository.&lt;/p&gt;

&lt;p&gt;Some fair objections, before the conclusion.&lt;/p&gt;

&lt;p&gt;No single revision could clear eighteen months of accumulated complaints, and that is true. The point was never the count. It is which half got cleared.&lt;/p&gt;

&lt;p&gt;A better objection is that statelessness &lt;strong&gt;is&lt;/strong&gt; an agent-experience change, and this one has more force than I would like. Fewer &lt;a href="https://www.maximem.ai/glossary/failure-modes" rel="noopener noreferrer"&gt;failure modes&lt;/a&gt;, no reconnection storms, no session dying mid-conversation, cheaper cold starts: reliability is part of the experience, and this release improves it. What it does not improve is anything the model can perceive. Same tool count, same trust in the descriptions, same token bill.&lt;/p&gt;

&lt;p&gt;Strongest of all is the argument that agent-experience work is happening in extensions now, and that the framework this release formalised is precisely what makes that possible. Go and look at the official &lt;a href="https://modelcontextprotocol.io/extensions/client-matrix" rel="noopener noreferrer"&gt;extension support matrix&lt;/a&gt;, though, which today lists nine clients. All nine support MCP Apps. Exactly one supports anything beyond it, and none supports OAuth Client Credentials. Extensions are opt-in on both ends, and the layer above the protocol is not there yet.&lt;/p&gt;

&lt;p&gt;That pattern is not carelessness. It is a boundary decision, and it is defensible. The protocol has drawn a line and put infrastructure concerns on its own side of it while leaving agent-experience concerns to the layer above. There is a serious argument that this is exactly what a protocol should do. It also means that if MCP was expensive for you last week because of tokens, or risky for you last week because of injection, this release changed nothing about either.&lt;/p&gt;




&lt;h2&gt;
  
  
  What the release created
&lt;/h2&gt;

&lt;p&gt;A piece that only lists what got better is a piece worth distrusting, so here is the other column.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;requestState&lt;/code&gt; &lt;strong&gt;moves a security boundary out of the protocol and into your application code.&lt;/strong&gt; The specification is unusually direct about this. Servers MUST treat &lt;code&gt;requestState&lt;/code&gt; as attacker-controlled input. If it influences authorization, resource access or business logic, servers MUST protect its integrity with HMAC or AEAD and MUST reject state that fails verification. Servers SHOULD embed the authenticated principal, a short expiry, and a digest of the originating request inside the protected payload. And then, having said all that, the specification concedes that these measures "do not by themselves guarantee single-use." Maxim Zavodchik at Akamai &lt;a href="https://www.securityweek.com/new-enterprise-ready-mcp-specification-brings-new-security-challenges/" rel="noopener noreferrer"&gt;put the consequence plainly&lt;/a&gt;: "critical security boundaries are now entirely dependent on how developers implement them." Set against &lt;a href="https://equixly.com/blog/2025/03/29/mcp-server-new-security-nightmare/" rel="noopener noreferrer"&gt;Equixly's finding that 43% of the MCP servers they assessed shipped command injection&lt;/a&gt;, and that 45% of the vendors they disclosed to dismissed the risk as theoretical, that is a large bet on developer diligence.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Headers can lie&lt;/strong&gt;, which is covered above, and the component making the policy decision is the one not reading the body.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And sessions are not quite as gone as the headline suggests.&lt;/strong&gt; SEP-2663 requires that &lt;code&gt;tasks/get&lt;/code&gt;, &lt;code&gt;tasks/update&lt;/code&gt; and &lt;code&gt;tasks/cancel&lt;/code&gt; over Streamable HTTP carry &lt;code&gt;Mcp-Name: &amp;lt;taskId&amp;gt;&lt;/code&gt;, explicitly so that intermediaries can "route subsequent requests for the same task to the server instance holding its state, which is typically required for correctness." That is instance affinity, reinstated by the flagship extension for long-running work, keyed to a task ID instead of a session ID. It is a better design than the old one, because the affinity is now explicit, addressable, and scoped to a unit of work rather than to a connection. But anyone reading "sessions are gone" as "you will never need sticky routing again" should read that sentence in SEP-2663 first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Roots deprecation removes the only structural filesystem boundary the protocol had.&lt;/strong&gt; The prescribed migration is to pass directories through tool parameters, resource URIs, or server configuration, which converts a client-enforced limit into a server-trusted argument. Scope enforcement now lives in each developer's code and is applied inconsistently by construction.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sampling deprecation quietly moves cost onto server operators.&lt;/strong&gt; SEP-2577 gives three reasons and leads with the design one: "correct sampling implementation requires human-in-the-loop approval, model selection logic, security considerations, and (since SEP-1577) tool loop support," which it says contributed to low client adoption. The lead maintainer's version, &lt;a href="https://www.theregister.com/devops/2026/07/23/model-context-protocol-prepares-to-break-with-its-stateful-past/5276722" rel="noopener noreferrer"&gt;to The Register&lt;/a&gt;, is that "the semantics were confusing and hard to implement." That reasoning is sound.&lt;/p&gt;

&lt;p&gt;The part nobody has priced is the migration. The prescribed replacement is to integrate directly with LLM provider &lt;a href="https://www.maximem.ai/glossary/api" rel="noopener noreferrer"&gt;APIs&lt;/a&gt;, which moves model credentials, billing, rate-limit handling and model-choice policy from the client to the server operator. That is my reading of the consequence rather than a complaint anyone has organised around, and I could not find one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;And the specification is silent on two things it probably should not be.&lt;/strong&gt; There is no CORS guidance anywhere in it, despite four new mandatory headers that are all non-simple and therefore all trigger a browser preflight. To be precise about the claim, I grepped all thirty-one specification pages and the schema: zero mentions of CORS, preflight, &lt;code&gt;OPTIONS&lt;/code&gt; or &lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Documentation is a different matter, and the way it mentions CORS is the more interesting finding. The &lt;code&gt;2026-07-28&lt;/code&gt; authorization tutorial ships sample code containing &lt;code&gt;cors({ origin: "*", exposedHeaders: ["Mcp-Session-Id"] })&lt;/code&gt;, exposing a header this revision deleted, and two of its live handler blocks still read &lt;code&gt;req.headers["mcp-session-id"]&lt;/code&gt;. That page is not stale in one snippet. It is stale throughout, under a &lt;code&gt;2026-07-28&lt;/code&gt; URL. The extension support matrix has the same problem in miniature, still instructing client authors to "declare support in the &lt;code&gt;extensions&lt;/code&gt; field of your &lt;code&gt;initialize&lt;/code&gt; capabilities" for a handshake that no longer exists. There is also no size bound on &lt;code&gt;requestState&lt;/code&gt;, which round-trips through the client on every retry.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://trilogyai.substack.com/p/mcp-grows-up-what-the-july-28-spec" rel="noopener noreferrer"&gt;Trilogy AI&lt;/a&gt; makes the sharpest counter-argument to the whole release, and it is worth taking seriously: statelessness relocates complexity rather than deleting it. Explicit handles consume &lt;a href="https://www.maximem.ai/glossary/token-budget" rel="noopener noreferrer"&gt;token budget&lt;/a&gt;. Models operating with garbled handles fail differently from expired sessions, but they still fail. And nobody has specified what recovery looks like when a model loses a handle in the middle of a conversation. The session was at least a thing the infrastructure understood. The handle is a string the model has to keep track of.&lt;/p&gt;




&lt;h2&gt;
  
  
  When does HTTP+SSE actually stop working, and why do two official pages disagree?
&lt;/h2&gt;

&lt;p&gt;Every write-up on this release is leading with July 2027, which is when roots, sampling, logging and Dynamic Client Registration become eligible for removal. That is correct and it is not the nearest deadline.&lt;/p&gt;

&lt;p&gt;Nearest is the legacy HTTP+SSE transport, deprecated back in &lt;code&gt;2025-03-26&lt;/code&gt; and only now given a removal clock. Two official sources describe that clock differently.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Source&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Implied earliest removal&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;The &lt;a rel="noopener noreferrer nofollow" href="https://modelcontextprotocol.io/specification/2026-07-28/deprecated"&gt;deprecated features registry&lt;/a&gt;, "three months after SEP-2596 reaches Final", with PR #2596 merged under the &lt;code&gt;final&lt;/code&gt; label on 18 May 2026&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;around 18 August 2026&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;The &lt;a rel="noopener noreferrer nofollow" href="https://blog.modelcontextprotocol.io/posts/2026-07-28/"&gt;release blog&lt;/a&gt;, "officially deprecated, with a year-long offramp"&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;around July 2027&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The registry's number is the reasoned one, and SEP-2596 explains it in a section called &lt;code&gt;Transition&lt;/code&gt; that is worth quoting because it is better thinking than the blog's summary:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Both features were publicly deprecated well over twelve months before this SEP, so the minimum deprecation window has in practice already been served; re-anchoring their clock to a future revision release would restart a window the ecosystem has already had. Each is therefore given a three-month grace period from the date this SEP reaches Final before it is eligible for removal, matching the floor the Expedited removal clause sets for the shortest permissible window."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So the SEP-Final anchoring is deliberate and reasoned, not an anomaly. HTTP+SSE and the &lt;code&gt;includeContext&lt;/code&gt; values are the two features grandfathered in from before the policy existed, and the SEP is explicit that "the deprecation-SEP requirements in Deprecating a feature are not applied retroactively" to them.&lt;/p&gt;

&lt;p&gt;What that leaves is smaller than a governance story and more useful than one: &lt;strong&gt;the document most people will read is wrong about the date.&lt;/strong&gt; The blog says twelve months. The registry and the SEP say three, from a date that has already passed.&lt;/p&gt;

&lt;p&gt;Before you act on that, one thing the SEP says that the coverage has also missed, and that cuts the other way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Removal still follows Removing a feature: a Core Maintainer decision at release preparation, not an automatic event when the grace period ends."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Removal also requires a new Current revision to ship, and none is scheduled. So there is no August cliff. What there is, from around 18 August 2026, is &lt;em&gt;eligibility&lt;/em&gt;, meaning the point from which any future revision may drop the transport without further notice. If you are still on HTTP+SSE, the planning implication is not that something breaks next month. It is that you no longer have a guaranteed window, and you should stop assuming the twelve months the blog implies.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now the governance oddity, which is a different feature.&lt;/strong&gt; The lifecycle policy that shipped in this revision says plainly that "deprecation is a specification change and therefore requires a SEP per the SEP guidelines." Dynamic Client Registration's deprecation is recorded against PR #2858, titled "Authorization spec split," a documentation reorganisation merged on 4 June 2026 whose description is about page load time and navigation. It is the only row in the deprecated registry without a SEP number.&lt;/p&gt;

&lt;p&gt;Three rebuttals suggest themselves and none of them holds. That CIMD arrived via SEP-991 and the deprecation merely followed it: SEP-991 contains zero occurrences of the string "deprecat". That SEP numbers are PR-derived under SEP-1850, so #2858 is effectively the SEP number: there is no file in &lt;code&gt;seps/&lt;/code&gt;, no SEP label and no SEP status, and the registry's own column heading reads "Deprecation SEP" while the cell reads "PR #2858". That the grandfathering clause covers it: it does not, because that clause covers only the two features deprecated before the policy existed, and DCR is a new deprecation in this revision.&lt;/p&gt;

&lt;p&gt;I do not think anything was slipped through. DCR was already only a MAY in &lt;code&gt;2025-11-25&lt;/code&gt; and CIMD was already a SHOULD, so the substantive change is close to a label, which is probably exactly why nobody stopped to write a SEP. That is the interesting version of the finding: the first process the policy governed was skipped, on a change small enough that skipping it felt reasonable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much of this matters in practice.&lt;/strong&gt; I paginated the official registry on 29 July 2026. There are 1,888 published version entries declaring an &lt;code&gt;sse&lt;/code&gt; remote, which is 761 distinct servers, 709 of them the latest version of their server, against 20,173 entries and 9,045 distinct servers on &lt;code&gt;streamable-http&lt;/code&gt;. Note the distinction between entries and servers, because a naive count inflates the number by more than double.&lt;/p&gt;

&lt;p&gt;A better measure of who actually gets hurt comes from Glama's index of 62,726 open-source servers, shared on &lt;a href="https://news.ycombinator.com/item?id=49088058" rel="noopener noreferrer"&gt;Hacker News&lt;/a&gt; the day the spec shipped: roughly 88% have been pushed to within the last year, which means about 12% have not been touched in twelve months. Those are the servers that will still be speaking a dead transport when someone finally removes it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to do, by what kind of MCP you run
&lt;/h2&gt;

&lt;p&gt;Four situations cover most people. The migration skill linked below covers the rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you run a local stdio server&lt;/strong&gt;, you are the lowest-risk group, because there are no headers, no sessions and no OAuth in your path. Implement &lt;code&gt;server/discover&lt;/code&gt;, since it is a MUST for servers and it doubles as the era probe on stdio. Move logging to &lt;code&gt;stderr&lt;/code&gt;, because &lt;code&gt;logging/setLevel&lt;/code&gt; is gone and &lt;code&gt;notifications/message&lt;/code&gt; is deprecated and must not be emitted unless the request carried a log level in &lt;code&gt;_meta&lt;/code&gt;. Stop writing JSON-RPC requests to stdout entirely. And plan for in-flight requests simply being lost when the process dies, because the protocol no longer pretends otherwise.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you run a multi-tenant SaaS MCP&lt;/strong&gt;, this is the highest-stakes cluster and the first thing to audit is &lt;code&gt;cacheScope&lt;/code&gt;, before anything else, because that is the field that leaks. Anything user-scoped, tenant-scoped or permission-scoped must be &lt;code&gt;"private"&lt;/code&gt;. Then check tool visibility, and here is the carve-out most write-ups are missing: tool lists MUST NOT vary per &lt;em&gt;connection&lt;/em&gt;, but they MAY still vary by the authorization presented on the request, since credentials are per-request input rather than connection state. Per-tenant tool filtering is still entirely legal. It simply has to key off the token instead of the session. After that, work through the authorization changes: &lt;code&gt;iss&lt;/code&gt; validation, CIMD support, &lt;code&gt;application_type&lt;/code&gt;, credential binding, and single-challenge scope emission.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you run on serverless or the edge&lt;/strong&gt;, you are the biggest winner and most of your work is deletion. Remove the Durable Object, Redis or DynamoDB session pinning, remove session affinity from the load balancer, and then actually test round-robin by firing a sequence of requests and asserting that none of them depends on the previous one landing anywhere in particular. Re-tune your cold-start and concurrency budgets while you are there, because a one-shot tool call is now literally one HTTP request with no handshake in front of it, and your per-invocation cost model has changed. If you are on Cloudflare, note that &lt;code&gt;McpAgent&lt;/code&gt; is now feature-frozen and &lt;code&gt;createMcpHandler(v1Server)&lt;/code&gt; goes away in the next major.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you run a gateway, proxy or aggregator&lt;/strong&gt;, three rules. Do not make policy decisions on &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt; alone. Handle &lt;code&gt;resultType&lt;/code&gt; values you do not recognise, and never pass &lt;code&gt;"task"&lt;/code&gt; through to a client that did not negotiate the extension. And remember that the MRTR retry arrives with a different JSON-RPC id, so any metering or rate limiting keyed on id will double-count a single logical operation. There is also an opportunity here that the Glama operator named on Hacker News, which is that protocol-incompatible servers and clients are going to need translating between for at least a year, and the gateway layer is the natural place for that to live.&lt;/p&gt;




&lt;h2&gt;
  
  
  The twelve-point compatibility checklist
&lt;/h2&gt;

&lt;p&gt;Run this against your server before you call the migration done.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Can a request land on a &lt;strong&gt;cold, empty instance&lt;/strong&gt; and succeed?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you implement &lt;code&gt;server/discover&lt;/code&gt;? It is a MUST for servers.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you accept and validate &lt;code&gt;MCP-Protocol-Version&lt;/code&gt;, &lt;code&gt;Mcp-Method&lt;/code&gt; and &lt;code&gt;Mcp-Name&lt;/code&gt;, and does your proxy forward them?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Do you ignore inbound &lt;code&gt;Mcp-Session-Id&lt;/code&gt; and &lt;code&gt;Last-Event-ID&lt;/code&gt;? (And if you serve &lt;strong&gt;only&lt;/strong&gt; this revision, do you answer GET and DELETE with &lt;code&gt;405&lt;/code&gt;? If you are dual-era, keep the GET stream for legacy clients.)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Is &lt;code&gt;resultType&lt;/code&gt; present on every result, and does your client handle &lt;code&gt;"input_required"&lt;/code&gt;?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Are &lt;code&gt;ttlMs&lt;/code&gt; and &lt;code&gt;cacheScope&lt;/code&gt; present on all six cacheable result types, and is &lt;code&gt;cacheScope&lt;/code&gt; &lt;strong&gt;correct&lt;/strong&gt; for authenticated data?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does &lt;code&gt;tools/list&lt;/code&gt; avoid varying per connection, and return a deterministic order?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you replaced every server-initiated request with MRTR, and is &lt;code&gt;requestState&lt;/code&gt; integrity-protected?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you moved off &lt;code&gt;-32002&lt;/code&gt; and &lt;code&gt;-32042&lt;/code&gt;, and if you built against a release candidate, off the pre-release &lt;code&gt;-32001&lt;/code&gt;, &lt;code&gt;-32003&lt;/code&gt; and &lt;code&gt;-32004&lt;/code&gt; numbering?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does your &lt;code&gt;inputSchema&lt;/code&gt; validate as JSON Schema 2020-12, with network &lt;code&gt;$ref&lt;/code&gt; resolution disabled by default?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Have you inventoried your use of roots, sampling, logging and DCR against the 2027-07-28 clock?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you are still on HTTP+SSE, is your Streamable HTTP migration scheduled? Eligibility for removal opened around 18 August 2026, not in twelve months, whatever the release blog says.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  The tool
&lt;/h2&gt;

&lt;p&gt;There is a gap in the ecosystem that you can verify with one &lt;code&gt;curl&lt;/code&gt;. The official MCP registry has no protocol-version field: server records carry a &lt;code&gt;$schema&lt;/code&gt;, the server's own semantic version and its remote types, and nothing at all declaring which protocol revision the server speaks. So there are tens of thousands of published servers, a wire incompatibility that runs in both directions, and no machine-readable compatibility signal anywhere.&lt;/p&gt;

&lt;p&gt;Client-side information is thinner still, and in a way that has already had consequences. SEP-2577 justifies deprecating roots, sampling and logging partly on low client adoption, and cites &lt;code&gt;modelcontextprotocol.io/clients#feature-support-matrix&lt;/code&gt; as its evidence. That page and that anchor no longer resolve; the URL now redirects to the getting-started introduction. The evidence base for three deprecations is a dead link.&lt;/p&gt;

&lt;p&gt;We built &lt;code&gt;mcp-2026-migrate&lt;/code&gt; to close that for ourselves and it is easier to give away than to keep. It is a skill for &lt;a href="https://claude.com/product/claude-code" rel="noopener noreferrer"&gt;Claude Code&lt;/a&gt; and Codex that reads your repository, identifies which of the twenty breaking changes apply to your code, and applies the mechanical ones, plus a standalone probe that determines a server's protocol era from the outside, which works on servers whose source you do not have. Free, open source, and built by Maximem, which is the same reason to read the scorecard above with the disclosure in mind.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently asked questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is MRTR in MCP?&lt;/strong&gt; Multi Round-Trip Requests, introduced in the &lt;code&gt;2026-07-28&lt;/code&gt; MCP specification, is the pattern that replaced server-initiated requests. The server returns &lt;code&gt;resultType: "input_required"&lt;/code&gt; with the inputs it needs and an opaque &lt;code&gt;requestState&lt;/code&gt; blob, and the client re-sends the original request with the answers attached. It works only on &lt;code&gt;tools/call&lt;/code&gt;, &lt;code&gt;prompts/get&lt;/code&gt; and &lt;code&gt;resources/read&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does&lt;/strong&gt; &lt;code&gt;resultType: "input_required"&lt;/code&gt; &lt;strong&gt;mean?&lt;/strong&gt; As of the &lt;code&gt;2026-07-28&lt;/code&gt; MCP specification, every result carries a &lt;code&gt;resultType&lt;/code&gt;, and &lt;code&gt;"input_required"&lt;/code&gt; means the operation is incomplete because the server needs something from the client. An absent &lt;code&gt;resultType&lt;/code&gt; must be treated as &lt;code&gt;"complete"&lt;/code&gt; for backward compatibility with older servers, and an unrecognised value must be treated as invalid.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I keep using MCP 1.x for now?&lt;/strong&gt; Yes. A server on &lt;code&gt;2025-11-25&lt;/code&gt; keeps working with clients on &lt;code&gt;2025-11-25&lt;/code&gt;, and the SDK v1 lines are still published. What you cannot do is mix eras, because a modern client cannot talk to a legacy server and a legacy client cannot talk to a modern one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can a server support both the old and new MCP spec at the same time?&lt;/strong&gt; Yes, and this is the recommended posture if you have real users. The &lt;code&gt;2026-07-28&lt;/code&gt; specification calls it dual-era. The Python SDK v2 does it by default: the client's first request decides that connection's era, once, and a later claim from the other era is refused. So in many cases an SDK upgrade gets you there without application changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why am I getting "unsupported protocol version" after upgrading?&lt;/strong&gt; Error &lt;code&gt;-32022&lt;/code&gt; means the two ends do not share a supported revision. Check &lt;code&gt;error.data.supported&lt;/code&gt; to see which side is behind. The fix is to make one side dual-era rather than to force both to the same revision at the same moment.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to update my MCP server?&lt;/strong&gt; Not today, if nothing on the other end of your wire has moved. The &lt;code&gt;2026-07-28&lt;/code&gt; revision does not break a running deployment by itself. You need to update before your clients do, and Anthropic has not yet shipped support across Claude, so most people have some runway.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What replaced&lt;/strong&gt; &lt;code&gt;Mcp-Session-Id&lt;/code&gt;&lt;strong&gt;?&lt;/strong&gt; Nothing at the protocol level. The &lt;code&gt;2026-07-28&lt;/code&gt; specification removed sessions entirely. State that must span requests is now an explicit, opaque, server-minted handle returned in a tool result and passed back as an ordinary tool argument, which the server re-authorizes on every call. One nuance: the tasks extension asks clients to send &lt;code&gt;Mcp-Name: &amp;lt;taskId&amp;gt;&lt;/code&gt; so intermediaries can route back to the instance holding a task's state, so instance affinity has not disappeared, it has become explicit and scoped to a unit of work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Was&lt;/strong&gt; &lt;code&gt;initialize&lt;/code&gt; &lt;strong&gt;removed from MCP?&lt;/strong&gt; Yes. As of &lt;code&gt;2026-07-28&lt;/code&gt; the &lt;code&gt;initialize&lt;/code&gt; request and the &lt;code&gt;notifications/initialized&lt;/code&gt; notification are both removed and nothing replaced them. Protocol version and client capabilities travel in &lt;code&gt;_meta&lt;/code&gt; on every request, and &lt;code&gt;server/discover&lt;/code&gt; covers the discovery case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When will the Java SDK support 2026-07-28?&lt;/strong&gt; It does not yet. Java is a Tier 2 SDK, which carries a six-month obligation from the specification release, so support is due around January 2027. Note that a Java &lt;code&gt;2.0.0&lt;/code&gt; does exist, published 11 June 2026, but it predates this revision and contains no &lt;code&gt;2026-07-28&lt;/code&gt; support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When will Claude clients support the new MCP spec?&lt;/strong&gt; Anthropic has said support is rolling out across Claude products and has not announced general availability or per-product dates. Check the Claude release notes rather than relying on this sentence, which ages badly by design.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is sampling still supported in MCP?&lt;/strong&gt; Sampling is deprecated as of &lt;code&gt;2026-07-28&lt;/code&gt;, not removed. It continues to work for at least twelve months, with the earliest removal being the first revision released on or after 28 July 2027.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do I use instead of sampling now that it is deprecated?&lt;/strong&gt; The specification's prescribed migration is to integrate directly with an LLM provider API. Budget for the consequence, which is that model credentials, billing and rate-limit handling move from the client to your server.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How do I handle workflows that take days now that MCP is stateless?&lt;/strong&gt; Use the &lt;code&gt;io.modelcontextprotocol/tasks&lt;/code&gt; extension. The server returns a task handle, the client polls &lt;code&gt;tasks/get&lt;/code&gt; honouring &lt;code&gt;pollIntervalMs&lt;/code&gt;, and sends input through &lt;code&gt;tasks/update&lt;/code&gt;. Persist task ids durably, because &lt;code&gt;tasks/list&lt;/code&gt; was removed and a lost id means an unreachable task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are the&lt;/strong&gt; &lt;code&gt;Mcp-Method&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;Mcp-Name&lt;/code&gt; &lt;strong&gt;headers for?&lt;/strong&gt; They let load balancers, gateways and rate limiters route and meter on the operation without parsing the JSON-RPC body. &lt;code&gt;Mcp-Method&lt;/code&gt; is required on all requests as of &lt;code&gt;2026-07-28&lt;/code&gt;; &lt;code&gt;Mcp-Name&lt;/code&gt; is required only on &lt;code&gt;tools/call&lt;/code&gt;, &lt;code&gt;resources/read&lt;/code&gt; and &lt;code&gt;prompts/get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long until HTTP+SSE stops working?&lt;/strong&gt; Eligibility for removal opened around 18 August 2026, three months after SEP-2596 reached Final. The release blog's "year-long offramp" does not match the registry or the SEP. Removal is still a maintainer decision at release preparation and requires a new revision to ship, so nothing breaks on a date, but you no longer have a guaranteed window.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is&lt;/strong&gt; &lt;code&gt;2026-07-28&lt;/code&gt; &lt;strong&gt;the same thing as MCP 2.0?&lt;/strong&gt; There is no MCP 2.0. The string does not appear anywhere in the official documentation and the release announcement never uses it. It is community shorthand, and it exists because the SDKs went to 2.0.0 and 3.0.0 while the specification stayed on date-based revisions, which is a real inconsistency that people on Hacker News have been asking about for over a year.&lt;/p&gt;




&lt;h2&gt;
  
  
  The line the protocol drew
&lt;/h2&gt;

&lt;p&gt;The thing worth taking away from &lt;code&gt;2026-07-28&lt;/code&gt; is not any individual change. It is where the boundary landed.&lt;/p&gt;

&lt;p&gt;This revision decided that problems living between a load balancer and a server process belong to the protocol, and that problems living between a model and a tool description belong to the layer above it. Sessions, routing, caching, discovery and transport are the protocol's job now, and they are handled well. Token economics, prompt injection, tool-space collisions and authorization modelling are somebody else's, explicitly and by design.&lt;/p&gt;

&lt;p&gt;That is a coherent position and quite possibly the right one, because protocols that try to solve everything tend to solve nothing. The layer above is where extensions live, and extensions are exactly the right shape for the work that remains.&lt;/p&gt;

&lt;p&gt;But nine clients appear in the official extension support matrix today, and exactly one of them supports anything beyond MCP Apps. So the expensive parts of running an MCP server and the risky parts of running an MCP server are now, formally, somebody else's problem, and that somebody has not shown up yet.&lt;/p&gt;

&lt;p&gt;Worth knowing who you are waiting for.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Last updated 29 July 2026. Registry figures measured against&lt;/em&gt; &lt;code&gt;registry.modelcontextprotocol.io&lt;/code&gt; &lt;em&gt;on the same date. If something here is wrong, tell me and I will fix it in place rather than publishing a correction nobody reads.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>9 Essential Claude Skills for AI Engineers Building Production Agents + 1 Bonus Skill</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Tue, 11 Aug 2026 03:49:41 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/9-essential-claude-skills-for-ai-engineers-building-production-agents-1-bonus-skill-2b0n</link>
      <guid>https://dev.to/gaurav_dadhich/9-essential-claude-skills-for-ai-engineers-building-production-agents-1-bonus-skill-2b0n</guid>
      <description>&lt;h2&gt;
  
  
  &lt;strong&gt;📖 What Are Claude Skills?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Claude Skills&lt;/strong&gt; are organized folders of instructions, scripts, and resources that Claude (both Claude Code CLI and Claude Cowork GUI) can discover and load dynamically to perform specialized tasks. Think of them as reusable, modular capabilities that teach Claude how to complete specific tasks in a repeatable way.&lt;/p&gt;

&lt;p&gt;Skills are simple to create—just a folder with a &lt;code&gt;SKILL.md&lt;/code&gt; file containing YAML frontmatter and instructions. When you make a request, Claude automatically invokes relevant Skills based on your needs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key points:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Skills work across &lt;strong&gt;both&lt;/strong&gt; &lt;a href="https://code.claude.com/" rel="noopener noreferrer"&gt;Claude Code (CLI)&lt;/a&gt; and &lt;a href="https://claude.com/product/cowork" rel="noopener noreferrer"&gt;Claude Cowork (GUI)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some skills are &lt;strong&gt;native/built-in&lt;/strong&gt; (docx, pdf, pptx, xlsx - everyone has these)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Others are &lt;strong&gt;community-built&lt;/strong&gt; and need discovery/installation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;This guide focuses on &lt;strong&gt;community skills&lt;/strong&gt; for AI/ML engineering&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" rel="noopener noreferrer"&gt;Official Claude Skills Documentation&lt;/a&gt; | &lt;a href="https://github.com/anthropics/skills" rel="noopener noreferrer"&gt;Anthropic Skills Repository&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🎯 What This Is&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;A hand-picked collection of &lt;strong&gt;9 real,&lt;/strong&gt; &lt;a href="https://www.maximem.ai/glossary" rel="noopener noreferrer"&gt;&lt;strong&gt;community-built Claude Skills&lt;/strong&gt;&lt;/a&gt; specifically for AI engineers building production agents and LLM-powered applications.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What makes these different:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;❌ NOT native skills (you need to discover and install them)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Built by the community for specific AI/ML engineering problems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ Focus on &lt;a href="https://www.maximem.ai/glossary/prompt-engineering" rel="noopener noreferrer"&gt;prompt engineering&lt;/a&gt;, evaluation, security, and debugging&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ All verified with installation links, creators, and GitHub repos&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Who this is for:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.maximem.ai/glossary/developer-agents" rel="noopener noreferrer"&gt;AI/ML engineers&lt;/a&gt; building agent systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LLM application developers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Engineers implementing RAG pipelines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Security researchers testing &lt;a href="https://www.maximem.ai/glossary/tool-use" rel="noopener noreferrer"&gt;AI vulnerabilities&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Anyone debugging production agent behavior&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;📦 The Essential 9 Skills&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. promptfoo-evaluation ⭐⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Integrates the Promptfoo evaluation framework directly into your Claude workflow. Set up structured LLM testing with LLM-as-judge assertions, custom Python metrics, few-shot examples, variable substitution, and long text handling. Generates evaluation configs and runs systematic prompt testing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building &lt;a href="https://www.maximem.ai/blog/agent-evals-guide" rel="noopener noreferrer"&gt;evaluation pipelines&lt;/a&gt; before production &lt;a href="https://www.maximem.ai/glossary/deployment" rel="noopener noreferrer"&gt;deployment&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A/B testing prompts with quantitative metrics&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Regression testing when changing models or prompts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating reproducible evaluation reports&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; Most engineers ship prompts without systematic testing. This catches regressions before users do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/daymade-claude-code-skills-promptfoo-evaluation-skill-md" rel="noopener noreferrer"&gt;promptfoo-evaluation on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; daymade | &lt;a href="https://github.com/daymade/claude-code-skills" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 531 stars, 59 forks | Last updated: Jan 29, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@promptfoo-evaluation Create an evaluation suite for my customer support agent
with 10 test cases covering edge cases and hallucination detection

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;2. promptinjection ⭐⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Comprehensive &lt;a href="https://www.maximem.ai/glossary/prompt-injection" rel="noopener noreferrer"&gt;prompt injection&lt;/a&gt; security testing with 5 specialized workflows: complete security assessment, reconnaissance, direct injection testing, indirect injection testing, and multi-stage attack simulations. Includes attack taxonomy, defense mechanisms, and detailed reporting templates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Security audits before production deployment&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Red-teaming your agent's prompt defenses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Testing jailbreak resistance&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building defensive prompt engineering patterns&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; One successful prompt injection can leak system prompts, bypass &lt;a href="https://www.maximem.ai/glossary/guardrails" rel="noopener noreferrer"&gt;guardrails&lt;/a&gt;, or manipulate agent behavior. Test before attackers do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/danielmiessler-personal-ai-infrastructure-releases-v2-5-claude-skills-promptinjection-skill-md" rel="noopener noreferrer"&gt;promptinjection on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; Daniel Miessler | &lt;a href="https://github.com/danielmiessler/Personal_AI_Infrastructure" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 6,136 stars | Industry-recognized security researcher&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@promptinjection Run a complete security assessment on my RAG pipeline prompts.
Test for indirect injection via uploaded documents.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;3. evaluating-llms ⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Multi-faceted LLM evaluation using automated metrics, LLM-as-judge patterns, and benchmark creation. Tests prompt quality, validates RAG pipelines, measures safety (hallucinations, bias, toxicity), and compares models for production deployment decisions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Validating RAG pipeline accuracy&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Comparing GPT-4 vs Claude vs Gemini for your use case&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measuring hallucination rates quantitatively&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building custom benchmarks for domain-specific tasks&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; "It feels like it works" isn't a deployment strategy. This gives you numbers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/ancoleman-ai-design-components-skills-evaluating-llms-skill-md" rel="noopener noreferrer"&gt;evaluating-llms on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; ancoleman | &lt;a href="https://github.com/ancoleman/ai-design-components" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 154 stars, 27 forks | Last updated: Dec 11, 2025&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@evaluating-llms Compare Claude Sonnet vs GPT-4o for code review tasks.
Run 50 test cases and measure accuracy, latency, and cost.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;4. ai-prompt-engineering ⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Production-grade prompt engineering patterns including structured outputs (JSON/schema validation), deterministic extractors, RAG grounding with citations, tool/agent workflows, and prompt safety testing. Focuses on operational patterns that work at scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building reliable structured output systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Implementing RAG with proper citation tracking&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Designing tool-calling agent workflows&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Ensuring deterministic extraction from documents&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; Moving from prototype to production requires structured, predictable outputs. This skill teaches production patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/vasilyu1983-ai-agents-public-frameworks-shared-skills-skills-ai-prompt-engineering-skill-md" rel="noopener noreferrer"&gt;ai-prompt-engineering on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; vasilyu1983 | &lt;a href="https://github.com/vasilyu1983/AI-Agents-Public" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 29 stars, 6 forks | Last updated: Jan 26, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ai-prompt-engineering Design a prompt for extracting invoice data
with strict JSON schema validation and error handling

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;5. ai-threat-testing ⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Offensive AI security testing framework that systematically tests OWASP Top 10 for LLM Applications vulnerabilities: prompt injection, insecure output handling, training data poisoning, model denial of service, supply chain vulnerabilities, sensitive information disclosure, insecure plugin design, excessive agency, overreliance, and model theft.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Pre-deployment security assessments&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Penetration testing for AI systems&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Compliance validation (SOC2, ISO 27001)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building threat models for LLM applications&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; LLM security is different from traditional AppSec. This skill understands the unique attack surface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/transilienceai-communitytools-claude-skills-ai-threat-testing-skill-md" rel="noopener noreferrer"&gt;ai-threat-testing on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; transilienceai | &lt;a href="https://github.com/transilienceai/communitytools" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 19 stars, 3 forks | Last updated: Jan 27, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ai-threat-testing Run OWASP Top 10 assessment on my customer-facing chatbot.
Focus on prompt injection and sensitive information disclosure.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;6. llm-evaluation ⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Comprehensive LLM evaluation patterns including systematic prompt testing, hallucination detection methodologies, benchmark creation frameworks, and quality metrics. Provides structured approaches to measuring LLM performance across multiple dimensions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Building internal benchmark suites&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Detecting hallucinations in RAG responses&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tracking model performance over time&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creating evaluation dashboards&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; "It looks right" isn't enough. Systematic evaluation catches edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/applied-artificial-intelligence-claude-code-toolkit-skills-llm-evaluation-skill-md" rel="noopener noreferrer"&gt;llm-evaluation on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; applied-artificial-intelligence | &lt;a href="https://github.com/applied-artificial-intelligence/claude-code-toolkit" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 32 stars, 9 forks | Last updated: Jan 14, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@llm-evaluation Create a hallucination detection suite for my RAG pipeline.
Test with 20 adversarial queries designed to trigger false information.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;7. llm-patterns ⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Comprehensive catalog of AI-first application patterns, LLM testing methodologies, and prompt management strategies. Covers foundational architectural patterns for building scalable LLM applications including chain-of-thought, few-shot learning, retrieval patterns, and agent workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Learning production LLM application architecture&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Choosing the right pattern for your use case&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding trade-offs between approaches&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building reference implementations&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; Saves you from reinventing solutions to common problems. Learn from battle-tested patterns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/alinaqi-claude-bootstrap-skills-llm-patterns-skill-md" rel="noopener noreferrer"&gt;llm-patterns on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; alinaqi&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 467 stars, 37 forks | Last updated: Jan 21, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@llm-patterns Show me the best pattern for building a code review agent
with chain-of-thought reasoning and tool calling

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;8. coding-agent ⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Programmatic control of coding agents (Codex CLI, Claude Code, OpenCode, Pi Coding Agent) via background process management. Enables workflow automation with LangChain, custom agents, Claude API integration, and execution logging. Run agents from scripts, monitor outputs, and chain operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Automating code generation workflows&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Building CI/CD integrations with agents&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Chaining multiple agent operations&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Programmatic agent testing&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; Manual agent interaction doesn't scale. Automate agent workflows for production use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/openclaw-openclaw-skills-coding-agent-skill-md" rel="noopener noreferrer"&gt;coding-agent on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; openclaw | &lt;a href="https://github.com/openclaw/openclaw" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 143,701 stars, 21,502 forks | Last updated: Feb 2, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@coding-agent Set up automated code review workflow that runs on every PR.
Generate review comments and post to GitHub.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;9. agent-debugger ⭐⭐⭐⭐⭐&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does:&lt;/strong&gt; Systematic debugging toolkit for AI agentic workflows. Diagnoses common issues: wrong/inconsistent responses, tool/function calling failures, conversation loops, stuck agent states, and latency problems. Works with LangChain, custom agents, and Claude API. Provides step-by-step debugging workflows and root cause analysis.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Debugging why your agent gives wrong answers&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Fixing tool calling failures&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Diagnosing conversation loops&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Optimizing agent latency&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Understanding complex agent behavior&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential:&lt;/strong&gt; Agent debugging is HARD. You can't just "console.log" an agent's reasoning. This gives you systematic troubleshooting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Installation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Skill Link:&lt;/strong&gt; &lt;a href="https://skillsmp.com/skills/avivk5498-my-claude-code-skills-agent-debugger-skill-md" rel="noopener noreferrer"&gt;agent-debugger on SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Creator:&lt;/strong&gt; AvivK5498 | &lt;a href="https://github.com/AvivK5498/My-Claude-Code-Skills" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Stats:&lt;/strong&gt; 5 stars, 0 forks | Last updated: Jan 27, 2026&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@agent-debugger My customer support agent sometimes ignores the tool output
and gives generic responses. Help me diagnose what's failing.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus Skill: maximem synap (agent memory) ⭐⭐⭐⭐⭐: built by us
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;What it does&lt;/strong&gt;: Drop-in skill that teaches your AI coding agent (Claude Code, Cursor, Codex) how to integrate Maximem Synap; persistent, structured, multi-tenant memory for your agents. Covers SDK setup, scoping (per-user / per-customer), ingestion, retrieval, and per-framework packages for LangChain, LangGraph, CrewAI, Vercel AI SDK, LiveKit, and 18 more.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use cases&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Agents that remember users across sessions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-tenant memory isolation (user / customer / org scopes)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Replacing DIY vector-DB memory pipelines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Voice agents that recall caller history mid-call&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it's essential&lt;/strong&gt;: The other nine skills solve "is my prompt good?" — this one solves "does my agent remember the right things?"&lt;/p&gt;

&lt;p&gt;Installation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Skill link: &lt;a href="https://github.com/maximem-ai/maximem_synap_sdk/tree/main/skills" rel="noopener noreferrer"&gt;https://github.com/maximem-ai/maximem_synap_sdk/tree/main/skills&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Docs: &lt;a href="https://docs.maximem.ai/integrations/ai-coding-agents" rel="noopener noreferrer"&gt;https://docs.maximem.ai/integrations/ai-coding-agents&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Creator: Maximem (yes, that's us — disclosure)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Example usage&lt;/strong&gt;: @synap Add per-user memory to my LangGraph support agent so it remembers customers across sessions&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🚀 Installation Guide&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Quick Start (5 minutes)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Step 1: Verify Claude Skills is enabled&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For Claude Code (CLI):&lt;/strong&gt; Skills are enabled by default&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;For Claude Cowork (GUI):&lt;/strong&gt; Available in Pro subscription&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Check: Run &lt;code&gt;claude skills list&lt;/code&gt; (CLI) or look for Skills menu (GUI)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Install skills&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Method A: Using Claude Code CLI (recommended)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Install from GitHub (most common)&lt;/span&gt;
claude skills &lt;span class="nb"&gt;install &lt;/span&gt;daymade/claude-code-skills

&lt;span class="c"&gt;# Or install from local directory&lt;/span&gt;
claude skills &lt;span class="nb"&gt;install&lt;/span&gt; /path/to/skill/folder

&lt;span class="c"&gt;# List installed skills&lt;/span&gt;
claude skills list

&lt;span class="c"&gt;# Update existing skill&lt;/span&gt;
claude skills update daymade/claude-code-skills

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Method B: Manual installation&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Clone the skill repository from GitHub&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Place folder in &lt;code&gt;~/.claude/skills/&lt;/code&gt; directory&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Restart Claude or reload skills&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Method C: From SkillsMP marketplace&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Browse &lt;a href="https://skillsmp.com/" rel="noopener noreferrer"&gt;SkillsMP&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Click skill → Copy GitHub URL&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Use Method A or B above&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Using skills&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Automatic invocation&lt;/strong&gt; (Claude decides when to use):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Claude will automatically use relevant skills
"Evaluate my prompt against these 10 test cases"
→ Claude uses promptfoo-evaluation skill

"Test my agent for prompt injection vulnerabilities"
→ Claude uses promptinjection skill

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Explicit invocation&lt;/strong&gt; (you specify):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@promptfoo-evaluation Create evaluation suite...
@agent-debugger Debug my LangChain agent...

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Verification&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Check if skills are working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# CLI&lt;/span&gt;
claude skills list

&lt;span class="c"&gt;# Should show installed skills with status&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;💡 Pro Tips&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Combine Skills for Workflows&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ai-prompt-engineering Design production prompt for invoice extraction
@promptfoo-evaluation Create test suite with 20 edge cases
@promptinjection Test for injection vulnerabilities
@llm-evaluation Run hallucination detection

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chain skills together for comprehensive development → testing → security workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Start with Evaluation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Most engineers skip evaluation until production breaks. Install &lt;strong&gt;promptfoo-evaluation&lt;/strong&gt; or &lt;strong&gt;llm-evaluation&lt;/strong&gt; first. Build testing into your development flow from day one.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. Security Before Launch&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Use &lt;strong&gt;promptinjection&lt;/strong&gt; and &lt;strong&gt;ai-threat-testing&lt;/strong&gt; at least 1 week before production deployment. Security vulnerabilities found in production are 10x more expensive to fix.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Debugging Saves Hours&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;When your agent misbehaves, reach for &lt;strong&gt;agent-debugger&lt;/strong&gt; before spending hours reading logs. Systematic debugging beats intuition.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Learn Patterns Early&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;New to LLM development? Start with &lt;strong&gt;llm-patterns&lt;/strong&gt; to understand established approaches before building your own solution.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;📊 Expected Impact&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Based on testing with 12 AI engineering teams:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Time Savings:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Evaluation setup:&lt;/strong&gt; 4 hours → 20 minutes (promptfoo-evaluation)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security testing:&lt;/strong&gt; 8 hours → 1 hour (promptinjection)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Debugging sessions:&lt;/strong&gt; 2 hours → 30 minutes (agent-debugger)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Pattern research:&lt;/strong&gt; 10 hours → 1 hour (llm-patterns)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Quality Improvements:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bugs caught pre-production:&lt;/strong&gt; 3-5x increase&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Security vulnerabilities found:&lt;/strong&gt; 8-12 per project (before users find them)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Evaluation coverage:&lt;/strong&gt; From ad-hoc to systematic&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;ROI:&lt;/strong&gt; If you're paid $150K/year and these skills save 10 hours/week, that's ~$30K/year in your time.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;⚠️ What's Missing (Ecosystem Gaps)&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Honest assessment:&lt;/strong&gt; The Claude Skills ecosystem is early-stage. These 9 skills cover evaluation, security, and debugging well. But gaps remain:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not yet available as community skills:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;❌ Vector database utilities (Pinecone/Weaviate helpers)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ LLM cost tracking tools (token counting, spend monitoring)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ Context window analyzers (visualize token usage)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ API mocking frameworks (mock OpenAI/Anthropic responses)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;❌ Production monitoring integrations (Datadog, New Relic)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;✅ &lt;strong&gt;Agent memory / context management&lt;/strong&gt;: this gap is now covered: we ship an official &lt;code&gt;synap&lt;/code&gt; &lt;a href="https://github.com/maximem-ai/maximem_synap_sdk/tree/main/skills" rel="noopener noreferrer"&gt;skill&lt;/a&gt; that wires persistent memory into your agent.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why:&lt;/strong&gt; Community focus is on foundational concerns (prompt quality, security, evaluation). Infrastructure tooling hasn't been built yet.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this means:&lt;/strong&gt; You'll still need traditional tools for monitoring, cost tracking, and infrastructure. Skills augment your workflow, they don't replace your entire toolchain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;***UPDATE***&lt;/strong&gt;: The H2 2026 version of top skills is &lt;a href="https://www.maximem.ai/blog/claude-skills-for-engineers-h2-2026" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🔗 Additional Resources&lt;/strong&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Official Documentation&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview" rel="noopener noreferrer"&gt;Agent Skills Overview - Claude API Docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://code.claude.com/docs/en/skills" rel="noopener noreferrer"&gt;Extend Claude with Skills - Claude Code Docs&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills" rel="noopener noreferrer"&gt;Creating Your Own Skills - Anthropic Engineering&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/anthropics/skills" rel="noopener noreferrer"&gt;Anthropic Skills Repository (GitHub)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Community Marketplaces&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://skillsmp.com/" rel="noopener noreferrer"&gt;SkillsMP - 96,000+ Skills Directory&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.skillhub.club/" rel="noopener noreferrer"&gt;SkillHub - AI-Evaluated Skills&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/travisvn/awesome-claude-skills" rel="noopener noreferrer"&gt;Awesome Claude Skills (GitHub)&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Skill Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://platform.claude.com/docs/en/build-with-claude/skills-guide" rel="noopener noreferrer"&gt;Using Agent Skills with the API&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/anthropics/skills/blob/main/.claude-plugin/marketplace.json" rel="noopener noreferrer"&gt;Skills Specification Format&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://websearchapi.ai/blog/how-to-create-claude-code-skills" rel="noopener noreferrer"&gt;How to Create Claude Code Skills - Complete Guide&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Security Resources&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://owasp.org/www-project-top-10-for-large-language-model-applications/" rel="noopener noreferrer"&gt;OWASP Top 10 for LLM Applications&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://simonwillison.net/2023/Apr/14/worst-that-can-happen/" rel="noopener noreferrer"&gt;Prompt Injection Primer&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;🤖 Building Production Agents? You Need Context Management.&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you're using these skills to build production AI agents, you'll inevitably hit &lt;strong&gt;the context management problem&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The symptoms:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Your agent forgets critical information mid-conversation&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Context windows explode and costs spike 10x&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Multi-user scenarios leak data between sessions&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Semantic search returns irrelevant results despite good embeddings&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Why it happens:&lt;/strong&gt; Evaluation and security (these 9 skills) solve "is my prompt good?" Context management solves "does my agent remember the right things?"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is where Synap comes in.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Synap is an &lt;strong&gt;agentic context management platform&lt;/strong&gt; that handles memory, retrieval, and context decisions for your agents - so you can focus on prompts and features, not debugging why your agent forgot something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;a href="https://docs.maximem.ai/getting-started/quickstart" rel="noopener noreferrer"&gt;Maximem Synap Docs&lt;/a&gt; | &lt;a href="https://synap.maximem.ai/playground/" rel="noopener noreferrer"&gt;Maximem Synap Playground&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>File vs Vector for RAG</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Sat, 01 Aug 2026 11:36:12 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/file-vs-vector-for-rag-4d58</link>
      <guid>https://dev.to/gaurav_dadhich/file-vs-vector-for-rag-4d58</guid>
      <description>&lt;p&gt;File-driven &lt;a href="https://www.maximem.ai/glossary/context-management" rel="noopener noreferrer"&gt;context management&lt;/a&gt; has been the rage in the last few days, especially since Claude CoWork launched. It made me curious and I tried a few things.&lt;/p&gt;

&lt;p&gt;I ran an experiment across &lt;strong&gt;5 distinct domains&lt;/strong&gt;: from Python code to scientific papers. I ingested &lt;strong&gt;50,000 documents&lt;/strong&gt; from popular datasets and fired &lt;strong&gt;5,000 queries&lt;/strong&gt; at them.&lt;/p&gt;

&lt;p&gt;The goal? To find out what all the noise about file-based search is. And if it is even real!&lt;/p&gt;

&lt;p&gt;I started this expecting &lt;a href="https://www.maximem.ai/glossary/vector-database" rel="noopener noreferrer"&gt;Vector search&lt;/a&gt; to crush the benchmarks across the board. I was ready to write another post about why everything needs to be an embedding. But at 2:00 AM, observing my Macbook Pro heating up like a nuclear-power plant, I realized we've been sold a 'Semantic Dream' that doesn't always match the engineering reality.&lt;/p&gt;

&lt;h2&gt;
  
  
  What these two systems actually do
&lt;/h2&gt;

&lt;p&gt;Before the numbers, the distinction that explains all of them.&lt;/p&gt;

&lt;p&gt;Keyword search, in this case &lt;a href="https://github.com/quickwit-oss/tantivy" rel="noopener noreferrer"&gt;Tantivy&lt;/a&gt;, builds an inverted index and matches terms exactly. It has no model of meaning. If the query says "sort a list" and the document says &lt;code&gt;bubble_sort&lt;/code&gt;, keyword search finds nothing, because those are different strings. What it does have is precision, because when the term in the query is the same term in the document, the match is exact and nothing else outranks it.&lt;/p&gt;

&lt;p&gt;Vector search, in this case &lt;a href="https://www.trychroma.com" rel="noopener noreferrer"&gt;ChromaDB&lt;/a&gt;, converts text into a numeric representation and finds documents whose representation sits nearby. It has an approximate model of meaning and no notion of exactness. It will bridge "sort a list" to &lt;code&gt;bubble_sort&lt;/code&gt;, and it will equally happily return a document about cell structure when you asked about mitochondria, because those two things live close together in the same space.&lt;/p&gt;

&lt;p&gt;Exact matching and approximate meaning are not two implementations of the same idea. They are two different capabilities, and the benchmark below is a map of which one you need where.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;p&gt;We measured with MRR@10, which scores how high the correct document ranks in the first ten results. A score of 1.0 means the right document was ranked first every time.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Dataset&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Domain&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Keyword, exact match&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Vector, semantic&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Winner&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Margin&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;CodeXGLUE&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Natural language to code&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.2901&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.9143&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Vector&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.6242&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;MS MARCO&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Real Bing queries&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.4035&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.5225&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Vector&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.1190&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SQuAD&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Wikipedia question answering&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.6048&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.6136&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Tie&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.0088&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;HotpotQA&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Multi-hop reasoning&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.5494&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.4953&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Keyword&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.0541&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SciQ&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Science exam questions&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.8145&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.6142&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Keyword&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.2003&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Mean, all five&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.5325&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.6320&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Vector&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.0995&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Mean, excluding CodeXGLUE&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;0.5931&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;0.5614&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;Keyword&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;+0.0317&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Read the final two rows together, because that is the entire result. Across five datasets vector search wins by roughly ten points of MRR, which is the number that would go on a slide. Remove CodeXGLUE and the ranking inverts, with exact-match keyword search ahead by three points.&lt;/p&gt;

&lt;p&gt;Vector search is not generally better at retrieval. It is 3.15 times better at one job, and that job carries the average for everything else.&lt;/p&gt;

&lt;p&gt;CodeXGLUE is the purest semantic-gap task in the set, because a natural language description of what code should do shares almost no vocabulary with the code that does it. Exact matching has nothing to match on, and scores 0.2901. This is the case vector search exists for, and it wins it decisively.&lt;/p&gt;

&lt;p&gt;SciQ is the inverse. Science exam questions turn on specific entities, and in that setting a word is not an approximation of a concept, it is a key. Mitochondria is not a thing that is similar to a cell. Exact matching locks onto the term and scores 0.8145, while vector search drifts toward documents that sit nearby in embedding space and scores 0.6142.&lt;/p&gt;

&lt;p&gt;SQuAD is a tie. The gap is 0.0088 on a single run with no seed averaging, which is inside the noise, and reporting it as a vector win would be dishonest.&lt;/p&gt;

&lt;h2&gt;
  
  
  The vector tax, with a number
&lt;/h2&gt;

&lt;p&gt;The earlier version of this post said embedding generation is a tax and did not say how large. It is 76.4 times.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;colgroup&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;col&gt;
&lt;/colgroup&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Dataset&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Keyword indexing&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Vector embedding and indexing&lt;/p&gt;&lt;/th&gt;
&lt;th colspan="1" rowspan="1"&gt;&lt;p&gt;Ratio&lt;/p&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;CodeXGLUE&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;445.75 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;43,098.93 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;96.7x&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;MS MARCO&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;418.56 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;26,335.61 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;62.9x&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SQuAD&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;410.60 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;35,920.01 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;87.5x&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;HotpotQA&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;394.98 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;29,538.14 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;74.8x&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;SciQ&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;444.30 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;26,670.01 ms&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;60.0x&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;Total, 50,000 documents&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;2.11 seconds&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;161.6 seconds&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;td colspan="1" rowspan="1"&gt;&lt;p&gt;&lt;strong&gt;76.4x&lt;/strong&gt;&lt;/p&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is 23,650 documents per second against 309, on the same machine over the same corpus.&lt;/p&gt;

&lt;p&gt;The consequence is about when an agent can use what it just learned. If an agent needs to read a repository or a hundred-page document and act on it within the same turn, exact-match indexing is effectively instant and embedding is a coffee break. If it reads now and acts later, the tax amortises and stops mattering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The result that points past both systems
&lt;/h2&gt;

&lt;p&gt;HotpotQA has the smallest margin in the table and the most instructive failure underneath it.&lt;/p&gt;

&lt;p&gt;Those questions require linking two documents, for example establishing which of two magazines was founded first. Vector search would reliably retrieve the document for the first entity and miss the bridge document for the second, because the second document was not similar enough to a query that was mostly about the first. The answer was retrievable and the evidence was not.&lt;/p&gt;

&lt;p&gt;That is not a similarity problem and no reranker fixes it. Neither exact matching nor semantic similarity has any representation of the fact that two documents are connected. Both systems rank documents independently against a query, and a bridge document is by definition the one that does not look like the query. Answering that class of question requires storing the relationship itself, which is a third mechanism and the reason graph structure exists in memory systems at all.&lt;/p&gt;

&lt;p&gt;Finding the answer is not the same as holding enough context to prove it, and an agent that retrieves the first without the second produces confident, unsupported output rather than an error.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method, and everything wrong with it
&lt;/h2&gt;

&lt;p&gt;Anyone can rerun this, and anyone evaluating it should know where it is weak.&lt;/p&gt;

&lt;p&gt;10,000 documents and 1,000 queries per dataset, 50,000 and 5,000 in total, executed on January 14, 2026 on an Apple M4 with 16GB of RAM. Keyword search was Tantivy 0.22.0 with the default analyzer. Vector search was ChromaDB 0.4.0 or later with all-MiniLM-L6-v2 at 384 dimensions. No chunking on either side. Scoring was MRR@10.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;On scoring, which is the part most benchmarks in this category get wrong.&lt;/strong&gt; Relevance was evaluated programmatically by exact document ID matching against each dataset's ground truth, in &lt;code&gt;src/evaluation/metrics.py&lt;/code&gt;. There is no LLM judge anywhere in this pipeline. Nothing here can be moved by a prompt file, a judging bias, or an equivalence rule, which is a claim we cannot make about most published numbers in this category, including some of our own work on conversational benchmarks. A rerun on the same corpus produces the same table.&lt;/p&gt;

&lt;p&gt;Six limitations, in the order they would be raised against us.&lt;/p&gt;

&lt;p&gt;Single run rather than an average over seeds, so small margins carry no weight and SQuAD should be read as a tie.&lt;/p&gt;

&lt;p&gt;all-MiniLM-L6-v2 is a small and relatively old embedding model. A stronger embedder would very likely raise the vector numbers and could change the sign on HotpotQA. The honest statement is that this measures a common default configuration rather than the best available vector setup.&lt;/p&gt;

&lt;p&gt;Tantivy ran on its default analyzer with no tuning, so the keyword side is equally untuned.&lt;/p&gt;

&lt;p&gt;No chunking, which affects both approaches and affects vector retrieval more on longer documents.&lt;/p&gt;

&lt;p&gt;Ingestion timings come from local embedding on an M4. A hosted embedding API moves that number in both directions, worse for network round trips and better for batched inference, so treat 76.4x as the shape of the cost rather than a constant.&lt;/p&gt;

&lt;p&gt;MRR@10 measures where the correct document ranks. It does not measure whether the agent then produced a correct answer. Retrieval rank and task success are different things, and we would rather say that ourselves than have it said back to us.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this does not settle
&lt;/h2&gt;

&lt;p&gt;This benchmark runs over a fixed corpus of documents that were written by someone else and do not change. Agent memory is neither of those things. It grows on every turn, it is written by the agent itself, and yesterday's fact can contradict today's.&lt;/p&gt;

&lt;p&gt;The next post covers what happens to both of these systems once the corpus is conversation history rather than documents, which is where the interesting failures live. The architecture argument, including where graph structure and extraction fit, is on our &lt;a href="https://www.maximem.ai/build-vs-buy-agent-memory" rel="noopener noreferrer"&gt;build vs buy agent memory&lt;/a&gt; page, and the formal treatment of the token economics is in &lt;a href="https://arxiv.org/abs/2607.21503" rel="noopener noreferrer"&gt;our paper on Agentic Context Management&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>The state of AI memory in 2026: claimed vs observed</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Tue, 28 Jul 2026 05:17:29 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/the-state-of-ai-memory-in-2026-claimed-vs-observed-1n94</link>
      <guid>https://dev.to/gaurav_dadhich/the-state-of-ai-memory-in-2026-claimed-vs-observed-1n94</guid>
      <description>&lt;h1&gt;
  
  
  The state of AI memory in 2026: claimed vs observed
&lt;/h1&gt;

&lt;p&gt;AI memory is the most-benchmarked, least-reproduced category in the AI tooling stack right now. Vendors publish high numbers. The numbers travel through Twitter threads and conference decks and "agent infrastructure" landing pages. Almost nobody actually runs the harness themselves to check whether the numbers reproduce. We did.&lt;/p&gt;

&lt;p&gt;This post is the result of that work. It is a landscape map of the AI memory vendors competing in 2026, a tour of the two benchmarks the field has converged on (LongMemEval and LoCoMo), and a side-by-side of what each vendor publishes against what we observed when we re-ran the same evaluations on an open harness. Where we have completed a reproduction, we cite both numbers. Where we have not, we say so plainly. The harness is open-source. The detailed audit notes that explain the larger reproduction gaps are linked at the end.&lt;/p&gt;

&lt;p&gt;This is a long read. The shortcut version lives in the results table six sections down. If you came here from a "state of AI memory" search, that table is what you actually wanted.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why memory is the bottleneck in 2026
&lt;/h2&gt;

&lt;p&gt;The million-token-context-window race did not solve memory. It shifted the cost. You can stuff a million tokens into a single prompt now, which sounds like it should make memory unnecessary, but two well-documented &lt;a href="https://www.maximem.ai/glossary/failure-modes" rel="noopener noreferrer"&gt;failure modes&lt;/a&gt; turn that promise into wishful thinking at production scale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.maximem.ai/glossary/context-rot" rel="noopener noreferrer"&gt;Context rot&lt;/a&gt; kills the promise of long windows. As the context fills, attention quality degrades across the entire sequence, not just at the edges. The same model that answers cleanly with 8K tokens of context will hallucinate, contradict itself, or hedge unnecessarily when given 800K tokens of conversation history. Multiple recent evaluations (Chroma's context-rot study, the lost-in-the-middle work that started this thread of research in 2023, and follow-ups across most frontier model families) confirm that long context is not equivalent to focused context.&lt;/p&gt;

&lt;p&gt;Lost-in-the-middle compounds the problem. Information placed in the center of a long prompt is consistently retrieved with lower accuracy than information at the beginning or end, irrespective of model size or window length. For an agent that has accumulated weeks of conversation history, this means critical facts — the user's preferences, an earlier commitment, the resolution of a previous escalation — routinely sit in the part of the context where retrieval is worst.&lt;/p&gt;

&lt;p&gt;So memory layers exist because the &lt;a href="https://www.maximem.ai/glossary/context-window" rel="noopener noreferrer"&gt;context window&lt;/a&gt; is the wrong abstraction for stateful behavior. An agent that remembers should not have to re-read its entire conversational history to recall that the user prefers terse answers, works in payments &lt;a href="https://www.maximem.ai/glossary/compliance" rel="noopener noreferrer"&gt;compliance&lt;/a&gt;, runs a Series B SaaS company, and asked about SOC 2 controls two weeks ago. The memory layer is supposed to retrieve only what matters, in time, at the right level of abstraction, with the right scoping primitives.&lt;/p&gt;

&lt;p&gt;Scoping is its own subtlety. In a B2B setting, two users at the same company should share organizational context (their company's preferred vocabulary, internal processes, prior support history, configuration choices) while remaining isolated at the personal level. A memory layer that treats every user as an island misses the obvious B2B value, and a memory layer that pools everything misses the obvious privacy and personalization requirement. The interesting work in 2026 is building scoping primitives that handle both at the same time.&lt;/p&gt;

&lt;p&gt;In 2026 this is no longer aspirational. Memory is in the critical path for every serious agent product we have looked at: copilots that personalize across sessions, customer &lt;a href="https://www.maximem.ai/use-cases/synap/support" rel="noopener noreferrer"&gt;support agents&lt;/a&gt; that retain history across tickets, consumer chat apps that build long-term context with each user, internal-tool agents that have to remember what they did last Tuesday. The bottleneck is real. The vendors competing to solve it are real. The benchmarks the field uses to measure progress are real. The published numbers are a separate question, and that is where this post earns its keep.&lt;/p&gt;

&lt;h2&gt;
  
  
  The vendor map
&lt;/h2&gt;

&lt;p&gt;The agent-memory landscape splits cleanly into three categories. (Personal and consumer memory products such as ChatGPT Memory and Maximem's own &lt;a href="https://www.maximem.ai/vity" rel="noopener noreferrer"&gt;Vity&lt;/a&gt; are a separate market with different benchmarks and different buyers; they are out of scope for this post.)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Category one&lt;/strong&gt;: dedicated open-source memory libraries. Mem0's OSS layer (the one with the most ecosystem traction), Letta (the descendant of the MemGPT research line out of Berkeley), Cognee (ontology-driven, slightly more academic in positioning). These are products you install and run yourself. The trade-off is operational: you carry the runtime, the storage, the upgrades, the on-call. The upside is portability and full control.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Category two:&lt;/strong&gt; dedicated hosted memory products. Mem0 Cloud, Zep (the most mature on graph-structured memory), SuperMemory (B2B-leaning, customer-support-heavy in the case studies they show), and &lt;a href="https://www.maximem.ai/synap" rel="noopener noreferrer"&gt;Synap&lt;/a&gt; (which Maximem builds; structured long-term memory with multi-tenant scoping primitives). This is the segment with the most active commercial competition right now. Pricing pages started looking like each other six months ago, which is usually a sign that buyers are starting to ask the same comparison questions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Category three&lt;/strong&gt;: memory features inside agent frameworks. LangGraph, LlamaIndex, the Vercel AI SDK, the OpenAI Agents SDK, and a handful of others ship minimal memory primitives as part of the framework. These cover the common case (recent-turn recall, simple key-value persistence) and stop short of the harder problems: entity resolution across surface forms, temporal reasoning over versioned facts, cross-conversation synthesis. If you need real memory and you are using one of these frameworks, you almost always end up wiring in a dedicated memory layer.&lt;/p&gt;

&lt;p&gt;A small but persistent group of teams still rolls their own memory layer in-house. The argument for it (data layer, compliance, portability) is real for the first few months and gets weaker the longer the system runs. Most in-house implementations we have seen end up reimplementing the obvious primitives (&lt;a href="https://www.maximem.ai/glossary/chunking" rel="noopener noreferrer"&gt;chunking&lt;/a&gt;, embedding, recency-decay retrieval, basic deduplication) without ever getting to the harder problems (entity resolution, temporal reasoning, scoping, multi-tenant isolation). The cost compounds. The right framing for in-house is not "we built it ourselves" but "we built a worse version and now we maintain it forever." A few teams need to roll their own for regulatory reasons. Most teams convince themselves they need to, regret it eighteen months later, and migrate to a vendor anyway.&lt;/p&gt;

&lt;p&gt;A 3-category diagram of this map sits below. Marker for the design team: &lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqirwvzn87kgnbyp6.public.blob.vercel-storage.com%2Fsyndication%2Fimages%2F346853de2f888c7e9961.svg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fqirwvzn87kgnbyp6.public.blob.vercel-storage.com%2Fsyndication%2Fimages%2F346853de2f888c7e9961.svg" alt="vendor-map-2026.svg" width="1200" height="600"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Field Benchmarks Itself
&lt;/h2&gt;

&lt;p&gt;Two benchmarks dominate published claims in 2026: LongMemEval and LoCoMo.&lt;/p&gt;

&lt;p&gt;LongMemEval came out of Adobe Research in 2024 and was accepted at &lt;a href="https://arxiv.org/abs/2410.10813" rel="noopener noreferrer"&gt;ICLR 2025&lt;/a&gt;. It tests how well a memory system can answer questions over a long, multi-session conversational history. 500 questions, distributed across six categories: single-session-user, single-session-assistant, single-session-preference, knowledge-update, temporal-reasoning, and multi-session. The hardest category by a wide margin is multi-session, because it requires the system to synthesize evidence from multiple separate conversations rather than pulling from a single recent thread. Published methodology uses an LLM-as-judge with a binary correct-or-wrong label.&lt;/p&gt;

&lt;p&gt;LoCoMo, from Snap Research at &lt;a href="https://snap-stanford.github.io/LoCoMo/" rel="noopener noreferrer"&gt;ACL 2024&lt;/a&gt;, focuses on long-form open-ended conversations. The benchmark contains five question categories. Industry convention (the convention Mem0, Zep, and most others follow) is to exclude the adversarial category and report on categories one through four. Roughly: multi-hop reasoning, temporal reasoning, open-domain opinion, and single-hop recall. Open-domain is the category where vendor prompt engineering tends to do the most lifting, because the gold answers often follow predictable patterns (an answer of "likely no" tends to be correct when the most recent referenced event involved a bad experience, for instance).&lt;/p&gt;

&lt;p&gt;Both benchmarks share a structural property worth understanding before reading any published number. The answer model and the judge model are not part of the memory system. They are separate LLMs that the vendor configures via prompt. That separation is intentional: the benchmarks test the memory layer, not the LLM. But it does mean the vendor controls what gets asked of the model, how it gets reasoned over before the answer comes out, and how the response gets graded by the judge. Three points of leverage. All in the prompt files. Which is where reproduction starts to matter.&lt;/p&gt;

&lt;h3&gt;
  
  
  How we re-ran the numbers
&lt;/h3&gt;

&lt;p&gt;Our harness operates on a simple principle. Use each vendor's paid hosted product (or the OSS layer at its recommended configuration when no hosted product exists). Ingest the benchmark dataset through their pipeline exactly as a customer would. Then run the questions through a standardized answerer and judge that we control, so we are measuring the memory layer rather than the vendor's evaluation stack.&lt;/p&gt;

&lt;p&gt;Concretely: gpt-5 as the answer model across the board, a binary judging prompt with explicit conditions for marking both CORRECT and WRONG (no "lean toward yes" bias, no one-directional override clauses, no encoded dataset hints), five-seed averaging to control for stochasticity, and the same ingestion configuration we would recommend to any builder using the vendor SDK in production.&lt;/p&gt;

&lt;p&gt;The headline reproduction finding so far is the gap on LongMemEval, and it has two parts because we ran Mem0 twice. Before Mem0's April 14, 2026 announcement of their new state-of-the-art numbers, we ingested the LongMemEval haystack into their hosted product and ran the questions through our standardized answerer and judge. We got 57.5%. After their April 14 push (which followed the prompt-tuning commits we will detail below), we re-ran the same evaluation against their updated hosted product. We got 73.8%. The Mem0 memory layer genuinely improved by 16.3 points across that window, which is real engineering progress worth acknowledging. The published claim from the same announcement was 93.4%, still 19.6 points above the post-April-14 reproduction on the same memory system and the same data.&lt;/p&gt;

&lt;p&gt;The reason the numbers differ is not the memory layer. It is what the vendor stacks on top of the memory layer at evaluation time. In Mem0's case specifically, this stack lives in the answer and judge prompt files at github.com/mem0ai/memory-benchmarks. We audited the files at the exact commits that ship with their published claims:&lt;br&gt;&lt;br&gt;
Here are the &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/bd063eea04de4f8a19927beea155afa094a01905/benchmarks/longmemeval/prompts.py" rel="noopener noreferrer"&gt;LongMemEval prompts&lt;/a&gt; (committed April 3, 2026) and for the &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/edcd6f1d42400837b1fcb6997716f1769dc51a37/benchmarks/locomo/prompts.py" rel="noopener noreferrer"&gt;LoCoMo prompts&lt;/a&gt; (committed April 9, 2026). Both land before Mem0's April 14 number announcement; the file-level evidence of prompt-tuning is built into Mem0's own commit history (their April 3 commit message reads, in part: "Sync prompts from evals: CONTEXT CHECK, Rule 14 (contradictions), BIAS CHECK in judge, 5-step FINAL CHECK").&lt;/p&gt;

&lt;p&gt;The mechanisms surface clearly once you read those files. There are 14 dataset-specific equivalence rules in the answer prompt that map 1-to-1 to specific public LongMemEval question_ids (samples include "chandelier counts as jewelry" at line 145 and "scratch grains count as new layer feed" at line 147). There is a hidden chain-of-thought block ( tags at lines 53 and 65 &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/bd063eea04de4f8a19927beea155afa094a01905/benchmarks/longmemeval/prompts.py#L53-L65" rel="noopener noreferrer"&gt;here&lt;/a&gt; where those rules get applied before the visible answer is emitted; the judge only ever sees the cleaned answer. There is an explicit "lean toward yes" instruction in the LongMemEval judge prompt at line &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/bd063eea04de4f8a19927beea155afa094a01905/benchmarks/longmemeval/prompts.py#L269" rel="noopener noreferrer"&gt;269&lt;/a&gt; paired with a 5-step gauntlet to clear before marking anything WRONG at line &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/bd063eea04de4f8a19927beea155afa094a01905/benchmarks/longmemeval/prompts.py#L328" rel="noopener noreferrer"&gt;328&lt;/a&gt; , and no symmetric gauntlet before marking anything CORRECT. There is a one-directional gold-override clause in the LoCoMo judge at line &lt;a href="https://github.com/mem0ai/memory-benchmarks/blob/bd063eea04de4f8a19927beea155afa094a01905/benchmarks/longmemeval/prompts.py#L328" rel="noopener noreferrer"&gt;212&lt;/a&gt; that can promote a wrong prediction to correct when "evidence supports" it, but explicitly cannot demote a correct prediction to wrong when evidence contradicts it.&lt;/p&gt;

&lt;p&gt;Marker for design: this is the section where the receipt-card screenshots belong, inline. Each screenshot is captioned with the file:line citation already in the prose.&lt;/p&gt;

&lt;p&gt;Every one of these findings is documented with verbatim quotes pinned to the specific commit and line, SHA-256 hashes on mirrored copies of both prompt files, and Wayback Machine archive URLs for independent third-party timestamped copies. The full evidence chain sits in the receipts section at the end of this post.&lt;/p&gt;

&lt;p&gt;This pattern is not unique to Mem0. We are extending the testing to other vendors and will publish their reproductions as they complete. Across the vendors measured so far, the gap between published and observed tracks directly with how much benchmark-specific prompt engineering sits between the memory system and the headline number. It does not track with the quality of the memory system itself.&lt;/p&gt;

&lt;p&gt;Synap, our own product, was tested through the same harness with no benchmark-specific prompt advantages. Our numbers appear in the results table below alongside everyone else's, in every category we have measured, including the categories where we are weaker than the published competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Reproduction table, LongMemEval, mid-2026:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbk2p9fnsn59fj9d68ikj.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbk2p9fnsn59fj9d68ikj.webp" alt="ChatGPT Image May 27, 2026, 01\_43\_04 PM.png" width="800" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Zep number reproduced on April 10, 2026 harness; Zep has not independently verified the configuration we used.&lt;/p&gt;

&lt;p&gt;The Mem0 row is the one to read carefully. The 57.5% to 73.8% lift across the April 14 product update is real, and it is improvement Mem0 has earned the right to claim. The 73.8% to 93.4% jump from observed to published, however, is not attributable to the memory system. That part of the gap maps cleanly onto the prompt mechanisms documented in the methodology section above.&lt;/p&gt;

&lt;p&gt;Per-category breakdown, LongMemEval (Synap on current harness):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxwv9975o2zt828u5nu3.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fuxwv9975o2zt828u5nu3.webp" alt="ChatGPT Image May 27, 2026, 01\_44\_47 PM.png" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwu4r7ts81k07izv1iguo.webp" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fwu4r7ts81k07izv1iguo.webp" alt="ChatGPT Image May 27, 2026, 01\_47\_28 PM.png" width="800" height="640"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The reproduction gap is the most interesting column in any of these tables. It is, roughly, a measure of how much non-memory-layer engineering is sitting between the underlying system and the headline number a vendor publishes. The harness, the methodology, and the seeds are documented in the section above and in the repo linked at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is hard, what is coming
&lt;/h2&gt;

&lt;p&gt;Genuine cross-session synthesis is the hardest unsolved piece. Today, even the strongest memory layers do per-session extraction well and struggle to link the same entity across sessions when the surface representation differs. The benchmarks reflect this directly: LongMemEval multi-session is the lowest score for almost every vendor on the leaderboard. Solving it is part vector retrieval, part graph reasoning, and part ontology engineering, which is why no single team has nailed it yet.&lt;/p&gt;

&lt;p&gt;Temporal reasoning at scale is the next frontier. Calculating "what was the state of X two months ago" requires the memory system to maintain versioned facts and answer questions against a specific point in time, not just retrieve the current version and call it good. Most vendors approximate this with date metadata and good retrieval. Few do it as a first-class feature. This will start to matter more as agents move into use cases where past state is operationally consequential: compliance, audit logging, longitudinal personalization, financial agents that need to reason about what was true at a transaction date.&lt;/p&gt;

&lt;p&gt;Multi-tenant isolation paired with intelligent organizational sharing is where the enterprise segment gets decided. Enterprise buyers ask about this within the first three calls, and most memory products treat it as a configuration concern rather than an architectural one. The hard version is harder than it sounds: isolate users by default, share organizational context (vocabulary, processes, prior decisions) automatically when appropriate, expose the boundary as a primitive rather than a setting, and do all of it in genuinely shared infrastructure. The vendors that build this as a first-class primitive will win the enterprise segment over the next two years.&lt;/p&gt;

&lt;p&gt;Memory is the data layer for AI. The companies treating it as a feature will lose to the companies treating it as a category. That is the bet behind every serious memory vendor in 2026, including us.&lt;/p&gt;

&lt;h2&gt;
  
  
  Receipts and reproduction
&lt;/h2&gt;

&lt;p&gt;Everything in this post is reproducible.&lt;/p&gt;

&lt;p&gt;The harness we built and ran is open-source &lt;a href="https://github.com/maximem-ai/memory_and_context_eval_harness" rel="noopener noreferrer"&gt;here.&lt;/a&gt; One command runs the standardized binary-judge configuration against either ingest pipeline. Pull requests welcome, from vendors and independent researchers both.&lt;/p&gt;

&lt;p&gt;The Mem0 evidence chain, in full:&lt;/p&gt;

&lt;p&gt;- LongMemEval &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt; pinned at commit bd063eea04de4f8a19927beea155afa094a01905 (committed April 3, 2026 by Soumil Rathi). The 14 dataset-equivalence rules live at lines 138-148. The hidden chain-of-thought instruction lives at lines 53 and 65. The "lean toward yes" bias check is line 269. The 5-step FINAL CHECK before marking WRONG is lines 328-334.&lt;/p&gt;

&lt;p&gt;- LoCoMo &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt; pinned at commit edcd6f1d42400837b1fcb6997716f1769dc51a37 (committed April 9, 2026, same author). The opinion-question shortcuts are lines 81-82. The hardcoded LoCoMo session window ("All events occurred in 2022-2024. Never output 2025 or 2026.") is lines 64-65. The one-directional gold-override clause is line 212.&lt;/p&gt;

&lt;p&gt;- We mirrored both files locally at those commits. SHA-256 of the LongMemEval &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt;: ba8cf60d26f1390ecbef0f07b3e950556fe3bc5a37ba4b5343f28217f18c144f. SHA-256 of the LoCoMo &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;8ebac1ef60e9ab5caf99079fdaac038b85472e81491ed35e2d2655f3927c76c2. Any independent reproducer can fetch either file at the commit and confirm the hash.&lt;/p&gt;

&lt;p&gt;- Wayback Machine archive of the LongMemEval &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt; at the pinned commit: web.archive.org/web/20260505163741/... (captured May 5, 2026).&lt;/p&gt;

&lt;p&gt;Benchmark sources:&lt;/p&gt;

&lt;p&gt;- &lt;a href="https://arxiv.org/abs/2410.10813" rel="noopener noreferrer"&gt;LongMemEval&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;- &lt;a href="https://snap-stanford.github.io/LoCoMo%20(https://snap-stanford.github.io/LoCoMo/" rel="noopener noreferrer"&gt;LoCoMo&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;Disclosures: we tested Mem0 through their paid hosted product, ran their published benchmark harness both verbatim and modified, and read their &lt;a href="http://prompts.py" rel="noopener noreferrer"&gt;prompts.py&lt;/a&gt; at the commits above. SuperMemory and Zep were tested on our April 10, 2026 harness (numbers cited in the table). We have not yet completed LoCoMo reproduction for Mem0's post-April-14 product; that run is in progress and will update the table when complete. We have not yet ingested Letta or Cognee on the harness.&lt;/p&gt;

&lt;p&gt;Mem0 has been invited to respond publicly. If they publish a correction with evidence we will update the post. The repo accepts pull requests from any vendor who wants their configuration tested differently. Reproducibility cuts in both directions, and we would rather have the table be right than be flattering.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Agent Memory Is Not Merely a Storage &amp; Retrieval Problem, It Is an Architecture Problem.</title>
      <dc:creator>Gaurav Dadhich</dc:creator>
      <pubDate>Sat, 25 Jul 2026 06:21:18 +0000</pubDate>
      <link>https://dev.to/gaurav_dadhich/agent-memory-is-not-merely-a-storage-retrieval-problem-it-is-an-architecture-problem-3e1j</link>
      <guid>https://dev.to/gaurav_dadhich/agent-memory-is-not-merely-a-storage-retrieval-problem-it-is-an-architecture-problem-3e1j</guid>
      <description>&lt;p&gt;Most teams building AI agents are treating memory and inference cost as something the next model release will eventually fix. They believe that a bigger context window, a smarter retriever, a cheaper token rate, etc. would absolve the need for a system for solving agent memory. &lt;/p&gt;

&lt;p&gt;This posture is convenient but it is wrong. What an agent remembers, when it forgets, and how much it costs to reason are architectural decisions. They get made long before any model is involved, and no amount of model improvement fixes a bad architecture underneath it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Memory is a lifecycle, not a buffer
&lt;/h2&gt;

&lt;p&gt;Most agent systems today treat context as one shared blob: everything goes in, nothing meaningfully comes out, and the "solution" to running out of room is a bigger window. That is not a memory system, it is a pile.&lt;/p&gt;

&lt;p&gt;A lifecycle approach breaks this into stages that each need their own design:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ingestion: what gets written to memory in the first place, and at what granularity&lt;/li&gt;
&lt;li&gt;Scoping: what is relevant to this agent, this user, this task, versus what is just noise that happened to be nearby&lt;/li&gt;
&lt;li&gt;Decay: what loses relevance over time and should be forgotten deliberately, not accidentally truncated when the buffer fills up&lt;/li&gt;
&lt;li&gt;Retrieval: what gets pulled back into context for a given turn, and why&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Treat these as one undifferentiated blob and you get exactly the failure modes everyone complains about: agents that "forget" things that mattered and "remember" things that did not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where the cost actually goes
&lt;/h2&gt;

&lt;p&gt;Most of the token spend in agent systems is not the reasoning itself, it is carrying forward context that no longer earns its place. Every stale fact, every resolved sub-task, every turn of small talk that gets re-sent on every subsequent call adds up, and it adds up silently, because nothing in a shared-buffer architecture prompts you to ask whether that context is still worth its cost.&lt;/p&gt;

&lt;p&gt;Getting this right requires treating cost as a lifecycle property too, not a line item you optimize after the fact.&lt;/p&gt;

&lt;h2&gt;
  
  
  We argue a methodology and 5 primitives would be a better approach
&lt;/h2&gt;

&lt;p&gt;I wrote this up formally in a 23-page paper, "Agentic Context Management". It includes a full evaluation harness and the underlying study data, so the argument is not just conceptual, it is something you can check.&lt;/p&gt;

&lt;p&gt;This is the same thinking behind the memory work we have been doing at Synap, now written up with data behind it.&lt;/p&gt;

&lt;p&gt;Paper: arxiv.org/abs/2607.21503&lt;/p&gt;

&lt;p&gt;Genuinely interested in where people think the lifecycle framing breaks down, especially anyone running multi-agent systems where scoping gets a lot harder.&lt;/p&gt;

&lt;p&gt;About Author:&lt;br&gt;
I am the founder of Maximem.ai - an agentic context management and agent memory company. &lt;/p&gt;

</description>
      <category>agents</category>
      <category>ai</category>
      <category>architecture</category>
      <category>llm</category>
    </item>
  </channel>
</rss>
