Live Webinar
The Festive Growth Sessions: How Top Brands Drive More Leads· 23 Sept, 3:30 PM ISTSave Your Seat
Wati

How Long Does an MCP Session Stay Alive?

Rohan Chaturvedi
7 mins read
Fact-checked by: Namitha Sudhakar
|According to: Editorial Policies
How Long Does an MCP Session Stay Alive?
CategoriesAI Agent

Too Long? Read This First

  • MCP specifies no session TTL. A session lasts until the server ends it, the client ends it, or the deployment discards its state.
  • If a server has ended a session, requests carrying the old id must receive HTTP 404. The client's required response is to discard the id and send a fresh initialize.
  • A dropped connection is not a terminated session and is not a cancelled request. Those are three separate failure modes with three different recoveries.
  • ping checks whether the peer is responsive. It does not renew an idle session or stop the server expiring it.
  • OAuth token expiry and session expiry are unrelated. An expired token gives you 401 and needs a refresh; an expired session gives you 404 and needs a re-initialize.
  • The 2026-07-28 revision removes protocol-level sessions entirely, so this lifecycle applies to servers on 2025-11-25 and earlier.

There is no fixed answer, and that is the specification's deliberate choice rather than an omission. Model Context Protocol defines no idle timeout, no absolute lifetime and no keep-alive that extends a session, so the server owns that policy entirely and may end a session at any moment.

The practical consequence for anyone building a client: you must be ready for a session to expire immediately after a request that just succeeded. Code that assumes continuity will work in testing and fail in production the first time a server restarts.

What Creates a Session in the First Place

Under the initialization-based lifecycle, four things happen in order.

The client sends initialize carrying its supported protocol version, capabilities and implementation details. The server replies with the negotiated version, its own capabilities and server information. The client then sends notifications/initialized, and only after that do normal operations begin.

A Streamable HTTP server may return an MCP-Session-Id header alongside that initialization result. Two words there matter: may return. Assignment is optional, and plenty of servers are stateless and never issue one. If an id is assigned, the client must send it on every subsequent request.

Worth being precise about what that id is. It is a correlation and state handle. It carries no lease, no expiry timestamp and no promise about how long it stays valid. Nothing in the lifecycle specification obliges a server to keep it alive for any period at all.

The Three Failure Modes People Conflate

Most session bugs come from treating these as one problem. They are not.

Symptom

What it means

Correct recovery

HTTP 401

The OAuth access token is expired, invalid or wrongly scoped

Refresh the token at the authorization server, retry the request once

HTTP 404 on a request carrying a session id

The server has terminated that session

Discard the id, send initialize with no session header, complete notifications/initialized, then resume

Connection dropped mid-stream

The transport died

Reconnect. Do not assume the request was cancelled, and do not assume the session ended

That third row causes the most damage in practice. A disconnected HTTP or SSE connection is not equivalent to cancelling the MCP request, so a client that reissues the operation on every disconnect can trigger the same side effect twice. If your tools send messages or create records, that is a duplicate-send bug waiting to happen.

For an orderly shutdown, a client that is finished should send HTTP DELETE with the session id. The server is allowed to refuse with 405, so DELETE is a courtesy rather than a guarantee.

Ping is a Health Check, Not a Lease Renewal

MCP defines an optional ping request that either side may send to check whether the peer and connection are still responsive. Implementations should send it periodically, make the interval configurable, and pick a timeout that suits the network. No response within that timeout means the sender may treat the connection as stale and reconnect.

What ping does not do is extend the session. The ping utility specification describes connection health, and says nothing about renewing server-side session lifetime or preventing expiry. If your server has a 30 minute idle TTL, pinging every 15 seconds will keep the socket warm and the session will still expire on schedule.

For SSE streams there is a second, separate reason to send heartbeats: intermediaries. Proxies, load balancers and CDNs close idle streaming responses on their own timers, and a periodic SSE comment line stops them deciding your quiet stream is dead.

The Timers That Actually Exist in a Deployment

MCP prescribes no single timeout value. In a real deployment, several different timers control requests, connections, infrastructure, authentication, and sessions. These are easy to confuse with each other.

Timer

What it controls

Example/guidance

Per-request timeout

How long a client waits for an MCP request or tool call to complete.

Some documented client and framework examples use 10 to 20 seconds. Set this according to the slowest legitimate operation rather than treating it as an MCP default.

Keep-alive cadence

How frequently a server sends a heartbeat over a long-lived connection.

Spring AI's MCP server documentation supports a configurable 30-second keep-alive interval, disabled by default.

Intermediary idle timeout

How long infrastructure such as a load balancer or proxy allows a connection to remain inactive.

AWS ALB defaults to 60 seconds and Azure Front Door uses 90 seconds. Keep your heartbeat shorter than the tightest timeout in the path.

Access token lifetime

How long an OAuth access token remains valid.

The authorization server returns this through expires_in. Don't hard-code 3600 seconds just because the OAuth 2.1 draft uses it as an example.

Session lifetime

How long your application retains MCP session state.

Entirely application-specific. Use an idle TTL, absolute TTL, or no expiration depending on your requirements.

The important one to understand is the intermediary idle timeout. Your MCP client and server can both be working correctly while a load balancer or proxy closes their connection because it has not seen traffic within its idle window.

That's why long-lived MCP connections typically need a heartbeat:

Heartbeat → 15s → Heartbeat → 15s → Heartbeat

The rule is simple:

Your keep-alive interval should be shorter than the shortest idle timeout anywhere between the MCP client and server.

A reasonable production baseline is to match request timeouts to legitimate operation times, use a 15 to 30 second heartbeat for long-lived streams, configure intermediaries with a longer idle timeout, refresh tokens before expiry, and treat session state as disposable.

OAuth Expiry is a Different Clock

For an OAuth-protected remote server, the MCP server acts as an OAuth resource server. The client sends a bearer token on each request, the server validates expiry, scope and audience, and an invalid token gets a 401.

When a refresh token exists, the client exchanges it at the authorization server for a new access token. The refresh token goes to the authorization server and never to the MCP server. Critically, refreshing a token does not require re-initializing the session: the client keeps using the same session id, if the server still considers it valid, and simply attaches the new token.

Refresh tokens are optional and can themselves expire, be revoked, or be invalidated after inactivity. OAuth 2.1 requires public clients to use sender-constrained or rotating refresh tokens, and with rotation the client must store the new refresh token each time. If refresh fails, retrying the same refresh token will not help. The only recovery is a fresh authorization flow.

Why This Matters for a WhatsApp MCP Server

Sessions on a messaging server tend to be long and consequential, which raises the cost of getting recovery wrong.

An agent working through a backlog of conversations may hold a connection for an extended period, and a mid-run expiry that is handled badly can drop the agent's context about which conversation it was working on. Worse, a naive retry after a dropped connection can resend a customer message. Because outbound WhatsApp sends cost money and are visible to a real person, the duplicate-send risk is not theoretical.

Two design habits handle it. Make send operations idempotent, so a repeated call with the same key is recognised rather than re-executed. And keep a durable record of what was already done, so recovery re-reads state instead of re-running actions.

The tenant scoping described in MCP security for WhatsApp AI agents should be re-established from the token on every request rather than remembered against a session, precisely because the session may not survive.

Because Wati's MCP server authenticates through OAuth rather than a fixed key, token refresh is a routine event that clients hit regularly rather than a rare edge case, and connecting Wati MCP to Claude shows where re-authorization surfaces in practice.

A Server Where This is Already Handled

Handling refresh, expiry and recovery correctly is most of the work in a remote MCP client.

If you would rather connect to a server where that is already solved, book a Wati demo.

Frequently asked questions

My session died after about an hour. Is that an MCP default?

Almost certainly not. An hour is a common OAuth access token lifetime, so check whether you received a 401 rather than a 404. A 401 is a token problem, and refreshing fixes it without touching the session.

Can I stop a server expiring my session by pinging more often?

No. Ping tests connection health and has no defined effect on server-side session lifetime. If a server enforces an idle or absolute TTL, it will expire on that policy regardless of ping traffic.

Should my client re-initialize on every disconnect?

No. Reconnect the transport first and continue using the existing session id. Only re-initialize when a request that carried the session id comes back 404.

Does the 2026 revision make any of this obsolete?

For servers on the 2026-07-28 revision, yes: protocol-level sessions and the session header were removed, and state now travels as explicit tool arguments. Servers on 2025-11-25 and earlier keep this lifecycle, and plenty of deployed remote servers still run those revisions.

Related posts