Visitar URL original
Expose API to inspect and remove inactive server sessions · Issue #1063 · modelcontextprotocol/java-sdk · GitHub
Skip to content

Expose API to inspect and remove inactive server sessions #1063

Description

@ArchForge286

While integrating the Java MCP SDK 2.0, we noticed that HttpServletStreamableServerTransportProvider stores McpStreamableServerSession instances in an internal private HashMap, but currently does not expose a public API to inspect or remove server sessions.

Currently, the SDK does not expose any API to inspect, invalidate, or remove these sessions programmatically. The only supported way to remove a session appears to be an explicit HTTP DELETE request from the client.

This becomes problematic if a client terminates unexpectedly (application crash, network failure, process termination ...) and never sends the DELETE request. In this case, the server application has no possibility to clean up abandoned sessions, even if it can determine (e.g.: via an idle timeout) that a session has not been used for hours or days.

From our understanding, this means that the internal session map may continue to grow over time, as applications cannot implement their own session cleanup strategy.

We searched the existing issues and found discussions around session lifecycle management and pluggable session stores (e.g.: issue #274). However, we could not find an issue addressing the missing API to inspect and remove abandoned sessions managed by HttpServletStreamableServerTransportProvider.

Would it be possible to expose a public server-side session management API (e.g.: removeSession(), getSessions(), or a pluggable SessionStore/SessionManager) to allow applications to implement idle timeout and cleanup strategies for stateful Streamable HTTP servers?

Activity

  1. michaelboyles commented on Jul 18, 2026

    @michaelboyles

    I agree there should be some mechanism. In the meantime, here's a workaround to delete a session which might be helpful to someone. You can define stub-ish request class and pass it to doDelete manually. You can make plausible implementations for the other methods to guard against future changes to doDelete, but right now it only calls getRequestURI and getHeader.

    class FakeDeleteRequest implements HttpServletRequest {
        private final String sessionId;
    
        public FakeDeleteRequest(String sessionId) {
            this.sessionId = sessionId;
        }
    
        @Override
        public String getRequestURI() {
            return "/mcp"; // or whatever
        }
    
        @Override
        public String getHeader(String name) {
            if (name.equalsIgnoreCase("Mcp-Session-Id")) {
                return sessionId;
            }
            return null;
        }
        
        // stub the rest
    }
  2. added
    enhancementNew feature or request
    P2Moderate issues affecting some users, edge cases, potentially valuable feature
    on Aug 17, 2026
  3. added
    ready for workThe goal is clear and work towards it can be commenced
    and removed
    ready for workThe goal is clear and work towards it can be commenced
    on Aug 17, 2026
  4. CryoThrust commented on Aug 31, 2026

    @CryoThrust

    A minimal server-side API could preserve the current transport behavior while making lifecycle management explicit:

    Collection<String> sessionIds();
    Optional<McpStreamableServerSession> session(String sessionId);
    boolean removeSession(String sessionId);

    A read-only snapshot (or Set<String>) would be enough for an application-level idle-timeout job; removeSession should perform the same cleanup as the existing DELETE path and be idempotent for an unknown id. If exposing the session object is undesirable, sessionIds() plus removeSession() avoids leaking transport internals. Would this narrower API fit the intended lifecycle contract, or is a pluggable SessionStore already preferred for 2.0?

  5. matteoroxis commented on Oct 6, 2026

    @matteoroxis
    Contributor

    The main problem here, abandoned sessions piling up after a client crashes without sending DELETE, looks covered on main now. HttpServletStreamableServerTransportProvider runs a periodic sweeper (added in 1178539, caafc85 and e3e0f51) that evicts any session that has no open stream and received no request during the last interval. You configure it through the builder:

    HttpServletStreamableServerTransportProvider.builder()
        .sessionSweepInterval(Duration.ofMinutes(10)) // default is 30 minutes; null disables it
        .build();
    

    An idle session gets reclaimed somewhere between one and two intervals after its last activity, and a session holding an open GET stream is never touched. The behaviour is documented in docs/server.md and covered by sessionEviction / sessionHoldingAnOpenStreamIsNotEvicted in HttpServletStreamableIntegrationTests.

    That leaves the other two asks: a public getSessions() / removeSession() and a pluggable SessionStore. Is there still a concrete use case the sweeper doesn't handle? One example would be an app that has to drop a session right away when a user logs out or a tenant gets revoked, instead of waiting for the next sweep. If there is, I'd be glad to put together a small PR adding only removeSession(String sessionId) on the provider, which closes the session gracefully the way a DELETE does. I'd keep a SessionStore abstraction out of scope for now: it's a much bigger surface to commit to, and session state also lives in the WebFlux/WebMVC transports.

    @tzolov does that scope sound reasonable before I start?

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

    P2Moderate issues affecting some users, edge cases, potentially valuable featurearea/serverenhancementNew feature or requestneeds confirmation

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions