SIGN IN SIGN UP

Support stateless MCP connections with cache TTL and statefulness tracking (#254)

## Summary

This PR adds support for stateless MCP connections (the 2026-07-28 model
where any request may hit any server instance) by introducing connection
statefulness tracking, time-based cache expiry for stateless
connections, and improved session state management.

## Key Changes

- **Statefulness Detection**: Added `SessionStatefulness` type and
`deriveStatefulness()` method to distinguish between:
- `stateful`: stdio processes or HTTP servers with a session ID
(resumable)
- `stateless`: HTTP servers without a session ID (not resumable, any
request may hit any instance)
  - `unknown`: not yet determined
  
- **Tools Cache TTL**: Implemented time-based expiry
(`STATELESS_TOOLS_CACHE_TTL_MS = 60s`) for stateless connections as a
fallback since they don't receive `tools/list_changed` push
notifications. Stateful connections continue to rely on
notification-driven invalidation with no expiry.

- **Client Capabilities Extraction**: Moved hardcoded capabilities into
a new `buildClientCapabilities()` function in `src/core/capabilities.ts`
as a single source of truth for protocol generation evolution.

- **Tasks API Accessor**: Added `tasksApi` getter to centralize access
to the SDK's experimental tasks API, simplifying future migration to the
2026-07-28 Tasks extension.

- **Session State Persistence**: Updated `SessionData` to persist
`statefulness` alongside `mcpSessionId` so the session list can display
connection mode without extra round-trips.

- **Session Expiry Logic**: Refined session expiry detection to only
treat bare HTTP 404 as expiry when the connection actually has a
server-assigned session ID (stateless connections cannot expire).

- **CLI Output**: Enhanced `formatServerDetails()` to display protocol
version with statefulness suffix (e.g., "2026-07-28 (stateless)"),
omitting the suffix when statefulness is unknown.

- **Tests**: Added unit tests for statefulness display in server details
formatting.

## Implementation Details

- Statefulness is derived at connect time from the transport type
(presence of `terminateSession()` method indicates HTTP) and session ID
presence
- Cache expiry check is performed before returning cached tools in
`listAllTools()`
- The `cachedToolsExpiresAt` field is set when caching tools and cleared
on explicit invalidation
- Session resumption logic now guards against marking stateless sessions
as "expired" since they have no persistent state to lose

https://claude.ai/code/session_012C98WbuwkvUPipfaeXf5ym

Co-authored-by: Claude <noreply@anthropic.com>
J
Jan Curn committed
0fd565c345eed6ae387f45a9e0cfd67d64d59991
Parent: c89da28
Committed by GitHub <noreply@github.com> on 5/30/2026, 9:26:53 PM