You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PR #3208 introduced an in-process session pool for external MCP capability operations (one downstream handshake reused across search_capabilities/execute_capability instead of a fresh initialize per operation). While writing its e2e spec we found the pool was bypassed on the live path: external-mcp-client-runtime.ts had standardized list/call/inspect on @openwork/enterprise-mcp-client (#2810), while the pool lives in the den-api SDK client (external-mcp-client.ts).
The stopgap shipped in #3208 flips tool operations (listExternalMcpTools / callExternalMcpTool / inspectExternalMcpToolCall) back to the pooled SDK client, while connect/OAuth stays on the enterprise client. That splits one logical concern across two clients and partially reverses #2810's standardization.
Goal
Make @openwork/enterprise-mcp-client the single runtime again — now with pooling:
Move the session pool inside the enterprise client (or its Den adapter). runEnterpriseMcpOperation in ee/apps/den-api/src/capability-sources/enterprise-mcp-client-adapter.ts currently builds a client per operation and already threads lifecycleDeadline — that is where pooled acquisition slots in. Preserve the feat(den): reuse downstream MCP sessions across capability operations #3208 pool contract: per-member keying (connection row revision + membership + connected-account revision), idle/absolute TTLs, LRU, single-flight connects, evict + exactly one retry on session-shaped failures, invalidation hooks on token save/refresh/invalidate and connection mutations, and the DEN_EXTERNAL_MCP_SESSION_REUSE=0 kill switch.
Flip external-mcp-client-runtime.ts tool ops back to the enterprise client.
Retire the SDK client path (external-mcp-client.ts) once nothing routes through it.
Safety net
evals/specs/org-connector-session-reuse.test.ts proves the behavior from outside Den and is client-agnostic:
search→execute = one downstream initialize, same session id;
member isolation (distinct session id + token per member, negative halves asserted);
credential rotation forces a fresh handshake;
killed session → evict + exactly one retry;
kill switch restores session-per-operation.
It must stay green through steps 1–3 unchanged. It has already demonstrated it discriminates: with tool ops routed to the (unpooled) enterprise client, the reuse claim fails.
Non-goals
Any change to OAuth/DCR/PKCE handling — that is exactly what the enterprise client owns today and why we are consolidating onto it rather than away from it.
Context
PR #3208 introduced an in-process session pool for external MCP capability operations (one downstream handshake reused across
search_capabilities/execute_capabilityinstead of a fresh initialize per operation). While writing its e2e spec we found the pool was bypassed on the live path:external-mcp-client-runtime.tshad standardizedlist/call/inspecton@openwork/enterprise-mcp-client(#2810), while the pool lives in the den-api SDK client (external-mcp-client.ts).The stopgap shipped in #3208 flips tool operations (
listExternalMcpTools/callExternalMcpTool/inspectExternalMcpToolCall) back to the pooled SDK client, while connect/OAuth stays on the enterprise client. That splits one logical concern across two clients and partially reverses #2810's standardization.Goal
Make
@openwork/enterprise-mcp-clientthe single runtime again — now with pooling:runEnterpriseMcpOperationinee/apps/den-api/src/capability-sources/enterprise-mcp-client-adapter.tscurrently builds a client per operation and already threadslifecycleDeadline— that is where pooled acquisition slots in. Preserve the feat(den): reuse downstream MCP sessions across capability operations #3208 pool contract: per-member keying (connection row revision + membership + connected-account revision), idle/absolute TTLs, LRU, single-flight connects, evict + exactly one retry on session-shaped failures, invalidation hooks on token save/refresh/invalidate and connection mutations, and theDEN_EXTERNAL_MCP_SESSION_REUSE=0kill switch.external-mcp-client-runtime.tstool ops back to the enterprise client.external-mcp-client.ts) once nothing routes through it.Safety net
evals/specs/org-connector-session-reuse.test.tsproves the behavior from outside Den and is client-agnostic:It must stay green through steps 1–3 unchanged. It has already demonstrated it discriminates: with tool ops routed to the (unpooled) enterprise client, the reuse claim fails.
Non-goals