Skip to content

feat: add configurable limits for sessions and resource subscriptions - #314

Open
mcollina wants to merge 1 commit into
mainfrom
feat-session-subscription-limits
Open

mcollina wants to merge 1 commit into
mainfrom
feat-session-subscription-limits

Conversation

@mcollina

Copy link
Copy Markdown
Member

Adds opt-in limits so retained state cannot be grown without bound. Both default to Infinity, so existing deployments behave exactly as before.

  • maxSessionsPerPrincipal caps the non-expired sessions a caller may keep active, keyed by the (issuer, subject) pair when authorization identifies a caller and otherwise by a shared anonymous bucket. At the cap a new session is refused with SESSION_LIMIT_REACHED (-32035), while existing sessions keep working and expire on their own. The Redis store enforces it with an atomic Lua script (pruning expired ids on each create) so concurrent creates across instances cannot overshoot the cap.
  • maxResourceSubscriptionsPerSession caps the distinct URIs one session may subscribe to. Duplicates stay idempotent; only a new URI at the cap fails with SUBSCRIPTION_LIMIT_REACHED (-32036), enforced atomically on Redis.

Both memory and Redis session stores accept the new options. The resources/subscribe handler and the POST/GET /mcp session-creation paths surface these as stable protocol errors; the GET SSE path now resolves the session before hijacking the reply, so a refused session answers with a 429 instead of hanging.

Covers memory and Redis backends, duplicate subscriptions, per-principal isolation, expiry cleanup, and concurrent Redis writes. Documents both options in the README and plugin types.

Fixes #312

Add two opt-in limits so retained state cannot be grown without bound:

- maxSessionsPerPrincipal caps the non-expired sessions a caller may keep
  active. Keyed by the session's (issuer, subject) pair when authorization
  identifies a caller, else a shared anonymous bucket. At the cap a new
  session is refused with SESSION_LIMIT_REACHED, and existing sessions keep
  working and expire on their own. The Redis store enforces it with an atomic
  Lua script (pruning expired ids on each create) so concurrent creates across
  instances cannot overshoot the cap.
- maxResourceSubscriptionsPerSession caps the distinct URIs one session may
  subscribe to. Duplicates stay idempotent; only a new URI at the cap fails
  with SUBSCRIPTION_LIMIT_REACHED. Enforced atomically on Redis.

The memory and Redis session stores both accept the options (default
Infinity, no change for existing deployments). The subscribe handler and the
POST/GET /mcp session-creation paths surface the errors as stable protocol
errors. The GET SSE path now resolves the session before hijacking the reply,
so a refused session answers with a 429 instead of a hung stream.

Adds memory + Redis store tests and HTTP integration tests covering duplicate
subscriptions, per-principal isolation, expiry cleanup, and concurrent Redis
writes. Documents both options in the README and types.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add configurable limits for sessions and resource subscriptions

1 participant