Open Closed

AI Management: MCP client sessions are cached for the process lifetime and never invalidated (expired sessions, configuration changes, tool list changes, shutdown) #10919


User avatar
0
filipe.carneiro created

1. MCP sessions are never re-initialized after the server returns HTTP 404 (expired session)

Description

After the chat has been idle for a while, MCP tools stop working. The model still sees the tools, but every tool invocation fails. The only way to recover is to restart the application.

The MCP specification (2025-11-25, Transports → Session Management) says:

When a client receives HTTP 404 in response to a request containing an MCP-Session-Id, it MUST start a new session by sending a new InitializeRequest without a session ID attached.

https://modelcontextprotocol.io/specification/2025-11-25/basic/transports#session-management

MCP servers end idle sessions after a timeout, and lose all sessions when they restart. The AI Management module does not handle this case.

Steps to reproduce

  1. Configure an MCP server with the Streamable HTTP transport and assign it to a workspace.
  2. Open the chat for that workspace and invoke an MCP tool. It works.
  3. Make the server drop the session: wait for its idle timeout, or restart the MCP server.
  4. Ask the chat something that invokes the same MCP tool.

Expected: The client receives 404, creates a new MCP session (a new initialize request without Mcp-Session-Id), and the tool call succeeds.

Actual: The tool call fails with an HttpRequestException (404). Every later call fails the same way until the application is restarted.

Root cause (from the module source)

  • McpToolProvider caches sessions in a static ConcurrentDictionary<string, IMcpClientSession> ActiveSessions for the lifetime of the process.
  • GetOrCreateSessionAsync reuses a cached session whenever IsConnected is true.
  • McpClientSession.IsConnected is !_disposed. It does not reflect the real state of the underlying McpClient or its transport.
  • Nothing in production code disposes or evicts a cached session when a request fails, so IsConnected stays true for a dead session. The "replace disconnected session" branch in GetOrCreateSessionAsync is therefore never reached.
  • McpClientSession also caches its tool list (_cachedTools). The McpClientTool instances returned to the chat are bound to the original McpClient, so the stale session ID is reused on every invocation.
  • In ModelContextProtocol 0.6.0-preview.1, a 404 surfaces as a generic HttpRequestException (EnsureSuccessStatusCode). Newer SDK versions mark the transport as expired, but they still leave re-initialization to the caller. Upgrading the SDK alone will not fix this.

Related issues (same root cause: sessions are cached indefinitely)

2. Changing an MCP server's configuration does not invalidate the cached session

The cache key in McpToolProvider.GetOrCreateSessionAsync is {McpServerId}_{Name}. Changing the endpoint, custom headers, auth type or API key/token of an MCP server leaves the key unchanged. The existing session, created with the old configuration, keeps being used until the application restarts.

Steps to reproduce: Use an MCP server in the chat. Then change its endpoint or credentials in AI Management → MCP Servers, and use the chat again.

Expected: The new configuration is used.

Actual: The old endpoint and credentials are still used. If only the server name changes, a new session is created, but the old one stays in ActiveSessions and is never disposed.

3. Changes to the tool list on the MCP server are never picked up

McpClientSession.GetToolsAsync caches the result of ListToolsAsync in _cachedTools for the lifetime of the session. Because sessions are never evicted (see 1), the tool list is effectively cached for the lifetime of the process. The module also does not handle the notifications/tools/list_changed notification.

Steps to reproduce: Use an MCP server in the chat. Then add, remove or change a tool on the MCP server, and use the chat again.

Expected: The chat sees the updated tool list.

Actual: The chat keeps the original tool list until the application restarts. Removed tools are still offered to the model, and new tools never appear.

4. MCP sessions are not disposed on application shutdown

McpToolProvider.DisposeAllSessionsAsync() exists, but it is only called from tests (McpToolProvider_Concurrency_Tests). VoloAbpAIAIManagementModule has no OnApplicationShutdown that calls it.

Impact: On shutdown, the cached McpClient instances are not closed in an orderly way:

  • for Streamable HTTP, the session DELETE request is never sent to the server, so the server keeps the session until its own timeout;
  • for stdio, cleanup of the child process depends on the parent process exiting.
Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

No answer yet!
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on October 08, 2026, 12:23
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.