8000 fix(mcp): reuse shared MCP session across toolset and tool calls by Varun-S10 · Pull Request #1211 · google/adk-js · GitHub
[go: up one dir, main page]

Skip to content

fix(mcp): reuse shared MCP session across toolset and tool calls - #1211

Open
Varun-S10 wants to merge 1 commit into
google:mainfrom
Varun-S10:fix/issue-1210
Open

Varun-S10 wants to merge 1 commit into
google:mainfrom
Varun-S10:fix/issue-1210

Conversation

@Varun-S10
Copy link
Copy Markdown
Contributor

Please ensure you have read the contribution guide before creating a pull request.

Link to Issue or Description of Change

1. Link to an existing issue (if applicable):

2. Or, if no issue exists, describe the change:

If applicable, please follow the issue templates to provide as much detail as
possible.

Problem:
MCPToolset (getTools, listResources, getResourceInfo, and readResource) and MCPTool.runAsync created a fresh MCP Client via MCPSessionManager.createSession() and closed it in a finally block on every operation. Because stdio transports launch the MCP server as a child process per client session, every discovery, resource read, and tool call started a new server process and discarded all in-memory server state (such as navigated browser tabs, cookies, or login state) before the next call. Stateful Streamable HTTP and SSE MCP servers likewise received a new session on every call.

Solution:
Added MCPSessionManager.getSession(), MCPSessionManager.close(), and isDisconnectedSessionError() in core/src/tools/mcp/mcp_session_manager.ts to lazily establish and cache one shared MCP session per manager, deduplicate concurrent connection attempts, automatically reconnect if the transport closes or a Streamable HTTP session expires, and cleanly close active and in-flight sessions on close(). Updated MCPTool.runAsync and MCPToolset methods to reuse the shared session until MCPToolset.close() (which Runner.runAsync invokes automatically in its finally block), updated AgentRegistrySingleMCPToolset.close() to close any execution sessions opened by its returned MCPTool instances, and updated docs/guides/tools/mcp_tool/index.md to document the shared session lifecycle.

Testing Plan

Please describe the tests that you ran to verify your changes. This is required
for all PRs that are not small documentation or typo fixes.

Unit Tests:

  • I have added or updated unit tests for my change.
  • All unit tests pass locally.

Added and updated unit tests in core/test/tools/mcp/mcp_session_manager_test.ts, core/test/tools/mcp/mcp_tool_test.ts, core/test/tools/mcp/mcp_toolset_test.ts, and core/test/integrations/agent_registry_mcp_toolset_test.ts covering shared session caching, concurrent getSession() deduplication, disconnect error eviction (-32000, 404, Not connected, Session terminated), keeping healthy sessions open across regular tool errors, automatic reconnection after client.onclose and transport.onclose, race-safe close() during in-flight connections, and reopening after close(). Ran npm run test:unit -- --run (345 test files passed, 6278 tests passed), tests/e2e/tools/mcp/load_mcp_resource_e2e_test.ts (3 passed), npm run build, npm run ts:check, npm run ts:check:samples, npm run lint, npm run format:check, and npm run docs:check.

Manual End-to-End (E2E) Tests:

Built the workspace with npm run build and tested against real stateful stdio and Streamable HTTP MCP servers exposing navigate_page, list_pages, set_cookie, get_cookies, and a selected_page resource:

  • Before fix (main): calling getTools(), navigate_page({url: 'state-check'}), list_pages(), and readResource('selected_page') spawned 5 stdio server processes and list_pages returned 1: about:blank [selected].
  • After fix: all sequential and parallel tool calls, LoadMcpResourceTool reads, and multi-step InMemoryRunner.runAsync agent turns shared 1 stdio process (1: state-check [selected]), automatically reconnected after simulated stdio process exit and Streamable HTTP 404 session expiry, and terminated child processes cleanly when toolset.close() / Runner.runAsync finished.

Checklist

  • I have read the CONTRIBUTING.md document.
  • I have performed a self-review of my own code.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have added tests that prove my fix is effective or that my feature works.
  • New and existing unit tests pass locally with my changes.
  • I have manually tested my changes end-to-end.
  • Any dependent changes have been merged and published in downstream modules.

Additional context

N/A

@Varun-S10 Varun-S10 self-assigned this Nov 4, 2026
@Varun-S10
Copy link
Copy Markdown
Contributor Author

Hi @kalenkevich, Could you please take a look?

@Varun-S10 Varun-S10 added the needs review [Status] The PR/issue is awaiting review from the maintainer label Nov 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs review [Status] The PR/issue is awaiting review from the maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

MCPToolset starts a new MCP session (and stdio server process) for every tool call, so stateful servers lose state

1 participant

0