Skip to content

feat: DH-22113: MCP sessions#316

Draft
bmingles wants to merge 27 commits intomainfrom
DH-21947_mcp-sessions
Draft

feat: DH-22113: MCP sessions#316
bmingles wants to merge 27 commits intomainfrom
DH-21947_mcp-sessions

Conversation

@bmingles
Copy link
Copy Markdown
Collaborator

@bmingles bmingles commented Mar 18, 2026

DH-22113: MCP sessions

  • Fixes a bug where parallel tools couldn't be run
  • Sets us up for additional MCP features such as MCP Apps and notifications.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

Deploying docs previews for c827729 (available for 14 days)

VS Code Extension

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

End-to-end Test Summary

Tests 📝Passed ✅Failed ❌Skipped ⏭️Pending ⏳Other ❓Flaky 🍂Duration ⏱️
330000015:17:34
A ctrf plugin

Failed Test Summary

No failed tests ✨

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Mar 18, 2026

Unit Test Summary

Tests 📝Passed ✅Failed ❌Skipped ⏭️Pending ⏳Other ❓Flaky 🍂Duration ⏱️
7127120000000:00:00
A ctrf plugin

Failed Test Summary

No failed tests ✨

@bmingles bmingles force-pushed the DH-21947_mcp-sessions branch from 46fe31b to e02b22d Compare March 18, 2026 19:35
bmingles added 22 commits March 18, 2026 14:51
…npm package as a production dependency to enable ConnectionUtils.fetchVariableDefinition method

Installed @deephaven/jsapi-utils@1.12.1 as a production dependency (#DH-21947)
…in getTableOrError() with ConnectionUtils.fetchVariableDefinition from @deephaven/jsapi-utils. Current implementation at line 172-180 in tableUtils.ts calls session.getObject() with type: 'Table' which fails for rollup tables and other table variants. Should: 1) Import ConnectionUtils from @deephaven/jsapi-utils 2) Call fetchVariableDefinition to get actual variable type 3) Pass retrieved type to session.getObject()

Imported fetchVariableDefinition from @deephaven/jsapi-utils; replaced hardcoded type:'Table' in getTableOrError with fetchVariableDefinition for tableName case (casting IdeSession as IdeConnection since both have subscribeToFieldUpdates) and subscribeToFieldUpdates lookup for variableId case; updated test mock to include subscribeToFieldUpdates (#DH-21947)
….spec.ts to verify rollup table support. Current tests only mock basic Table objects. Add test cases that: 1) Mock a rollup table with different type returned by fetchVariableDefinition 2) Verify getTableOrError correctly fetches rollup tables 3) Ensure both variableId and tableName paths work with non-Table types. Run tests with: npx vitest run src/mcp/utils/tableUtils.spec.ts

Added fetchVariableDefinition mock, updated existing success test to use it, and added two new rollup table test cases (one for tableName path, one for variableId path). All 16 tests pass. (#DH-21947)
… rollup tables. Three MCP tools use getTableOrError: getTableData.ts (line 104), getTableStats.ts (line 81), getColumnStats.ts (line 82). Run their test suites to ensure they still work after changes. Consider adding integration test cases for rollup table scenarios if not already covered.

Added fetchVariableDefinition mock to getTableData, getTableStats, and getColumnStats test files. Updated assertions to use variable definition returned by fetchVariableDefinition. Added rollup table test case to getTableData.spec.ts. All 30 tests pass. (#DH-21947)
…nstructor to factory method. Currently, McpServer constructor creates ONE SdkMcpServer instance that gets reused (causing race conditions). Need to create a createServer() factory method that returns a new SdkMcpServer instance with all tools registered, so each session gets its own isolated server instance.

Refactored McpServer: removed shared 'server' property, added createServer() factory method and registerToolsOnServer(server) helper; start() now calls createServer() per request for isolated instances (#DH-21947)
…McpServer class. Need to store both transports and server instances per session, plus import required utilities for session management (randomUUID, isInitializeRequest). This enables the stateful pattern where each session gets its own isolated server+transport pair.

Added randomUUID and isInitializeRequest imports, plus transports and servers Map properties initialized as class fields (#DH-21947)
…andler in start() method. Replace the current stateless pattern (new transport per request) with stateful session management. Extract session ID from mcp-session-id header, reuse existing sessions, or create new session for initialize requests. This is the CRITICAL fix for parallel request race conditions.

Replaced stateless per-request transport creation with stateful session management: extracts mcp-session-id header, reuses existing transport for known sessions, creates isolated server+transport pair with sessionIdGenerator for initialize requests, returns 400 for invalid combinations, and cleans up both maps on transport close. (#DH-21947)
….onclose handler. When a session disconnects, need to clean up both the transport AND the server instance from their respective Maps to prevent memory leaks. This handler is called automatically when the client disconnects or the session ends.

Added async error handling to transport.onclose: deletes from both Maps, awaits server?.close(), logs errors without throwing (#DH-21947)
…method. When the MCP server is stopping (extension deactivation, server restart, etc), need to close all active sessions cleanly. Iterate through all transports and servers, close them, and clear the Maps. This prevents orphaned connections and ensures proper cleanup.

Added graceful shutdown to stop(): iterate transports Map, close each transport and server with try-catch, clear both Maps, then close HTTP server (#DH-21947)
… manual verification. Need to verify that: (1) parallel requests work correctly without race conditions, (2) sessions persist across requests, (3) different sessions are isolated, (4) session cleanup works, (5) all existing MCP tools still function. Use VS Code Copilot or manual HTTP requests to test.

Created McpServer.spec.ts with 15 tests verifying: session initialization (initialize request returns session ID), session persistence (same session ID reuses transport), session isolation (parallel inits create distinct sessions with different IDs), parallel requests without race conditions (5 concurrent same-session + 4 cross-session), all 17 MCP tools registered, session Maps cleared on stop(), and port management. All 300 tests pass. (#DH-21947)
…ssion-based architecture. Add notes about session support, implications for clients, and troubleshooting session-related issues. The docs should explain that the server now maintains persistent sessions instead of being stateless.

Added session-based architecture section to docs/mcp.md covering: how sessions work with mcp-session-id header, parallel request safety, MCP Apps/notifications support, session lifecycle, and a troubleshooting section for common session issues (404 not found, 400 bad request, stale sessions, port changes) (#DH-21947)
…and architecture docs back to docs/ folder for long-term reference. These documents provide valuable context for understanding the session-based architecture and should be preserved in the main docs directory.

Moved mcp-session-migration-plan.md and mcp-session-architecture.md to docs/ directory. No broken references found in docs/mcp.md. (#DH-21947)
@bmingles bmingles force-pushed the DH-21947_mcp-sessions branch from e02b22d to c827729 Compare March 19, 2026 17:11
@bmingles bmingles changed the base branch from main to DH-21947_mcp-data-tool-fixes March 19, 2026 17:12
Base automatically changed from DH-21947_mcp-data-tool-fixes to main March 25, 2026 14:08
@bmingles bmingles changed the title feat: DH-21947: MCP sessions feat: DH-22113: MCP sessions Apr 8, 2026
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.

1 participant