Sessions
Opt-in Mcp-Session-Id lifecycle, legacy only.
Note
Protocol-level sessions were removed in 2026-07-28. Modern servers are stateless; carry cross-call state in explicit handles passed as ordinary tool arguments.
Sessions are off by default. Enable them and initialize starts issuing session ids that clients must return on every subsequent request:
defineMcpHandler({
name: "my-server",
version: "1.0.0",
// Simple — uses crypto.randomUUID()
session: true,
// Or configured
session: {
generateId: (event) => `session-${Date.now()}`,
maxSessions: 1000,
},
tools: [/* ... */],
});#Lifecycle
initialize creates a session and returns it in the mcp-session-id response header.POST, GET, and DELETE must carry that header.DELETE removes it from the store.| Situation | Response |
|---|---|
Missing mcp-session-id | 400 |
| Unknown session id | 404 |
maxSessions exceeded | 503 |
Session ids are format-checked before they are looked up or stored — bounded length, alphanumerics plus - and _. A custom generateId must stay inside that alphabet.
#The Store Is In-Memory
The built-in store is a bounded Map in the handler's closure. That has consequences worth being explicit about:
- It does not survive a restart. Clients get
404and must re-initialize. - It is per-process. Behind a load balancer without sticky sessions, requests will land on a process that has never seen the id.
maxSessionsis unset by default. The store is a client-growable, server-lifetime collection: without a cap, anything that can reachinitializecan grow it. SetmaxSessionson any endpoint that is not fully trusted — exceeding it returns503rather than consuming more memory.
For anything multi-process, prefer keeping real state in your own store keyed by the session id, so losing the id costs a handshake rather than data.
#Reading the Session
defineMcpTool({
name: "remember",
handler: (event) => {
const sessionId = event.context.mcp?.sessionId;
return { content: [{ type: "text", text: `session: ${sessionId ?? "none"}` }] };
},
});Important
A session id is a bearer credential: whoever holds it continues that session. It is not an authentication mechanism — pair sessions with transport auth rather than treating the id as proof of identity.