<?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: Jonathan Trippett</title>
    <description>The latest articles on DEV Community by Jonathan Trippett (@jrtrippett).</description>
    <link>https://dev.to/jrtrippett</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%2F4055380%2Fa4c96718-8519-4334-8e57-2493a15d160d.png</url>
      <title>DEV Community: Jonathan Trippett</title>
      <link>https://dev.to/jrtrippett</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jrtrippett"/>
    <language>en</language>
    <item>
      <title>MCP dropped sessions. Here's the pattern that replaces them.</title>
      <dc:creator>Jonathan Trippett</dc:creator>
      <pubDate>Thu, 30 Jul 2026 15:53:57 +0000</pubDate>
      <link>https://dev.to/jrtrippett/title-mcp-dropped-sessions-heres-the-pattern-that-replaces-them-4c9m</link>
      <guid>https://dev.to/jrtrippett/title-mcp-dropped-sessions-heres-the-pattern-that-replaces-them-4c9m</guid>
      <description>&lt;p&gt;The Model Context Protocol's 2026-07-28 revision removed protocol-level&lt;br&gt;
sessions entirely. No &lt;code&gt;initialize&lt;/code&gt; handshake, no &lt;code&gt;Mcp-Session-Id&lt;/code&gt; header,&lt;br&gt;
no held-open bidirectional stream. Every request is now self-describing&lt;br&gt;
and can land on any server instance behind a plain load balancer.&lt;/p&gt;

&lt;p&gt;That's a real win for scaling. It's also a real problem if your server&lt;br&gt;
needs to remember anything between calls, which most useful ones do.&lt;/p&gt;

&lt;h2&gt;
  
  
  The pattern: explicit state handles
&lt;/h2&gt;

&lt;p&gt;Instead of a hidden session living in the transport layer, a tool mints&lt;br&gt;
a handle and hands it back to the model:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;create_cart()  →  "cart_7f3a9c2e5b1d"
add_item(cart="cart_7f3a9c2e5b1d", sku="MUG-01", quantity=2)
view_cart(cart="cart_7f3a9c2e5b1d")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Four HTTP requests. Four separate server instances, potentially. The&lt;br&gt;
only thread connecting them is a twelve-character string the model can&lt;br&gt;
see, hold onto, and pass around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why a visible handle actually beats a hidden session
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The model can hold more than one at once. Two carts isn't a protocol
problem anymore, it's just two strings.&lt;/li&gt;
&lt;li&gt;It shows up in the transcript. When something breaks, you can read
the handle and go look at exactly the state that caused it.&lt;/li&gt;
&lt;li&gt;Scope is explicit. A tool that wasn't handed a handle can't touch
that cart. There's no ambient "current cart" to reach for by accident.&lt;/li&gt;
&lt;li&gt;Any instance can serve any request. No sticky routing, no shared
session table, no session affinity to configure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The cost: handles are now part of your tool's contract, so getting their&lt;br&gt;
error cases right matters. Expired, malformed, and unknown all need to&lt;br&gt;
be distinct, readable messages, not one generic 500.&lt;/p&gt;

&lt;h2&gt;
  
  
  I wrote a generator for this pattern
&lt;/h2&gt;

&lt;p&gt;I kept rebuilding the same scaffolding, a pluggable state store, handle&lt;br&gt;
minting and validation, a working multi-turn example, so I turned it&lt;br&gt;
into a CLI:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm create stateforge@latest my-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It generates a TypeScript + Express server with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A swappable &lt;code&gt;StateStore&lt;/code&gt; (in-memory for dev, Redis for production/serverless)&lt;/li&gt;
&lt;li&gt;A working shopping-cart example built entirely on explicit handles&lt;/li&gt;
&lt;li&gt;A visual inspector, live tool list, call forms, editable state browser&lt;/li&gt;
&lt;li&gt;Deploy configs for Vercel and Docker&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MIT licensed, zero runtime dependencies in the CLI itself.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/JRTrippett/mcp-stateforge" rel="noopener noreferrer"&gt;https://github.com/JRTrippett/mcp-stateforge&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would genuinely like to hear if anyone's solving this differently, the&lt;br&gt;
2026-07-28 spec is new enough that I don't think there's a "standard"&lt;br&gt;
answer yet.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>mcp</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
