Skip to content

mcp: per-caller command graphs for multi-user hosting, keyed on authorization #97

Description

@carldebilly

In a multi-user deployment — several sessions on one host, a remote console, a shared HTTP endpoint —
different callers legitimately deserve different command graphs. Repl has no way to express that
today: the routing graph is application-global, and its MCP projection varies only through module
presence predicates resolved against session services.

Why this is not simply "reinstate per-session gating"

Revision 2026-07-28 states that the advertised tool set
MUST NOT vary per-connection or as a side effect of other requests on the connection — which is
why #71 makes the modern discovery view invariant. But the same sentence carries the exception that
fits this feature exactly:

The set MAY vary by the authorization presented on the request — for example, returning only
the tools the caller's granted scopes permit — since credentials are per-request input, not
connection state.

So a per-caller graph is permitted when it is driven by authorization presented on the request,
and prohibited when it is driven by connection state (client capabilities, per-session flags). That
distinction should shape the design rather than be discovered late:

  • the graph varies as a function of the request's credentials, not of the connection;
  • two requests presenting the same authorization must receive the same set, on any connection;
  • the snapshot cache key becomes the authorization identity, not the session.

What exists today

  • CoreReplApp.InvalidateRouting() is application-global and bumps McpServerHandler._snapshotState,
    a handler-wide version.
  • McpSessionContext.SnapshotCache is per session, and BuildSnapshotCore projects against that
    session's service overlay — so the signal is global while the result is per session.
  • _toolListChanged and its siblings are handler fields shared by every server the handler builds,
    so a list_changed reaches every connection.

A per-caller graph needs the cache and the notification fan-out to become per-identity rather than
per-session or global. That is the same machinery #70 and #74 are circling, so it should be sequenced
after them.

Out of scope for #71

#71 makes the modern view invariant, which is the conformant baseline. This issue is the feature that
would reintroduce variance through the one door the specification leaves open.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions