Remote MCP Server: 5 Fixes for a Painful Migration

I migrated my own remote MCP server to the 2026-07-28 stateless spec on AWS Lambda, deleted the session store and the ALB stickiness, and measured what changed.
Remote MCP server on AWS goes stateless: Mcp-Session-Id, ALB stickiness and session store removed

A remote MCP server used to be an awkward thing to run on serverless. I had one on AWS Lambda behind an Application Load Balancer, and for months it carried two pieces of plumbing I resented: ALB target-group stickiness so a client’s requests always hit the same task, and a DynamoDB table holding session state because the protocol demanded a session at all. On 28 July 2026 the Model Context Protocol shipped its largest revision since launch and made the core stateless, and I got to delete both. This is what actually changed when I migrated my own remote MCP server, what I measured, and where the sharp edges still are.

Table of contents

What “stateless” actually removed

The 2026-07-28 spec did three concrete things. It removed the initialize/initialized handshake, so a client’s very first message can be the actual tool call. It retired the Mcp-Session-Id header that clients previously had to echo on every subsequent request. And it dropped the standalone GET stream and Last-Event-ID resumption that the session model needed. The maintainers themselves called it the most substantial change since authorization was added, which is not marketing, it changes the shape of every MCP server deployment.

The practical consequence is the one line worth memorizing: app state persists, protocol state does not. Your tools can still read and write a database; a stateless remote MCP server keeps its app state, just not its protocol state. What’s gone is the protocol’s own insistence that a conversation lives on one server instance. Every request now carries its own protocol version and client context, so any instance can answer any request.

The AWS plumbing I deleted from my remote MCP server

The old session-based protocol fought horizontal scaling, and the AWS Architecture Blog’s Well-Architected review of the new spec names the exact anti-patterns I had built. A session lived on whichever instance issued it, so running more than one instance meant one of two things: pin clients with sticky routing, or externalize session state to a shared store. I had done both, belt and braces.

Under the stateless core, neither is required. The migration table from the AWS Builder Center post maps it cleanly: where you previously enabled ALB target-group stickiness, you now delete the stickiness configuration and run plain round-robin; where you externalized session state to DynamoDB or ElastiCache, you delete the session store and, if a tool genuinely needs cross-call state, you pass it as an explicit handle in the tool arguments. That last clause is the important discipline, and I’ll come back to it.

For a Lambda-hosted server specifically, this is the difference between a workaround and a first-class pattern. Lambda has no sticky routing and no persistent connections; request in, response out is exactly what it does natively. A session-based server meant paying for a mandatory handshake on a platform whose entire model is stateless invocation. Now the protocol matches the runtime, and a remote MCP server on Lambda is finally a natural fit.

AWS plumbing Session-based protocol (2025) Stateless core (2026-07-28)
Load balancer ALB target-group stickiness required Plain round-robin; delete stickiness
Session state Externalize to DynamoDB / ElastiCache Delete the store; pass state as tool args
First request initialize handshake, then the call First message can be the tool call
Session header Mcp-Session-Id echoed every request Header retired entirely
Lambda fit Handshake paid on stateless compute Request in, response out, native fit
Remote MCP server stateless migration: four pieces of AWS plumbing deleted
The four pieces of AWS plumbing the old session protocol forced on me.

The migration, step by step, on my own deployment

My server runs on the FastMCP class behind the Lambda Web Adapter. The actual code change was two constructor flags: stateless_http=True and json_response=True. Together they turn off the Mcp-Session-Id negotiation and prefer plain JSON responses over held-open SSE streams, which is what you want when the compute is ephemeral and recreated every invocation.

Then the infrastructure teardown, in order, because order matters if you don’t want a window where clients break:

First I deployed the stateless server build alongside the old one and pointed a fraction of traffic at it. Second, once I confirmed clients could call it with no handshake, I removed the ALB stickiness configuration and let requests round-robin. Third, I stopped writing to the DynamoDB session table, watched for a few days to be sure nothing read from it, and only then deleted the table. Deleting the store first would have been the mistake; the AWS guidance is explicit that for an existing server you work through the steps in sequence rather than flipping everything at once.

Remote MCP server migration order to avoid downtime
The migration order that avoids downtime: delete the session store last.
For a brand-new server the advice is simpler: target 2026-07-28 directly, stateless from the start, explicit identifiers, and no dependence on Roots, Sampling, or MCP Logging.

What I measured before and after

I care about numbers more than architecture diagrams, so here is what my own migration moved. These are from my single low-traffic remote MCP server, not a benchmark suite, and your mileage will differ, but the direction is the point.

Cold-start behaviour improved because there was no handshake round-trip before the first useful call. Cost dropped because I deleted a provisioned DynamoDB table that existed only to satisfy the protocol. And the operational surface shrank: one fewer stateful dependency to monitor, back up, and reason about during an incident.

Where stateless still bites

This is the part most write-ups skip, so I’ll be direct about it. Stateless is a subset of what a stateful server could do, and a real Reddit thread among MCP implementers makes the honest case that some capabilities, server-initiated notifications, for instance, simply cannot work the same way when every request is an independent connection. If you depended on the server pushing something to the client mid-call, that pattern is gone and you redesign around it.

Elicitation is the concrete example. Before, if a tool needed something from the user mid-call, a confirmation, a missing parameter, the server pushed an elicitation/create request back over a held-open stream, which was exactly the thing that made stateless deployment hard. The new spec reworks server-to-client requests around stateless multi-round-trip patterns, but if your tools leaned on interactive mid-call prompts, that is real redesign work, not a flag flip.

The other trap is assuming “stateless protocol” means “stateless application.” It does not. If a tool call needs the result of a previous one, that state has to live somewhere you control and travel as an explicit argument. The protocol won’t carry it for you anymore, and pretending otherwise is how you ship a server that works in testing and corrupts data under concurrency.

What’s worth doing if you run one

If you run one of these servers today, target the 2026-07-28 revision for your remote MCP server. New builds start stateless with explicit identifiers. Existing servers migrate in the sequence above, deploy stateless, remove stickiness, then remove the session store last, rather than all at once.

Delete the plumbing the old protocol forced on you: ALB stickiness and any session store that existed only for the handshake. Keep application state in DynamoDB, S3, or a memory service, and pass anything a tool needs across calls as an explicit handle in the arguments.

If you use held-open streams for elicitation or server notifications, inventory those first, they are the migration’s real cost, not the constructor flags. And treat every remote MCP server as potentially untrusted regardless of protocol version: allowlist tools, validate identities, and fail closed. The stateless change is about scaling and cost, not a security upgrade.

If you want the wider agent-plumbing context, I wrote about what an LLM gateway actually does for a coding agent and about the AI agent security risks I found auditing my own machine, both of which touch the same tool-serving surface.

FAQ

What is a remote MCP server? A remote MCP server is a Model Context Protocol server exposed over HTTP so AI agents and clients can call its tools across a network, rather than running it locally over stdio. On AWS it typically runs on Lambda or a container behind API Gateway or an ALB.

Do I still need session management for a remote MCP server? No. As of the 2026-07-28 spec the protocol core is stateless: no initialize handshake and no Mcp-Session-Id. Any server instance can answer any request. Application state, if a tool needs it, must be stored by you and passed as an explicit argument.

Is a stateless remote MCP server spec-compliant? Yes, the current spec specifies the stateless shape. The nuance implementers raise is that stateless servers can’t support certain stateful features like server-initiated notifications, so a stateless server is effectively a subset of a full stateful one. For most tool-serving workloads that subset is exactly what you want.

Should I migrate my existing server? If your remote MCP server runs on serverless or scales horizontally, yes, you can delete sticky routing and the session store. Migrate in sequence (deploy stateless, drop stickiness, remove the session store last) and inventory any held-open-stream features first.

Related reading: Cloud cost optimization: 7 proven fixes for a painful AWS bill.


Sources: MCP 2026-07-28 specification announcement; AWS Architecture Blog, MCP went stateless: is your AWS deployment well-architected?; AWS Builder Center migration checklist; MCP Server on AWS Lambda complete guide. Deployment steps and observations are from migrating my own low-traffic remote MCP server on AWS Lambda in 2026; figures are illustrative of that single deployment, not a benchmark.

Shares:
Post a Comment

Leave a Reply

Your email address will not be published. Required fields are marked *