Summary
Approval-gated tools called through execute pause correctly with elicitation_mode=model, but an immediate resume from a new MCP session returns execution_not_found.
ChatGPT creates a separate MCP session for the resume tool call. Executor self-host stores the paused execution only in the engine belonging to the original session, so the new session cannot find it.
Environment
- Executor self-host
v1.6.0
- Image revision:
0ae7959fe03e8fb98d0b8a961438ad88e49fbd4b
- Streamable HTTP MCP
- ChatGPT developer app
- Endpoint configured with
?elicitation_mode=model
- Approval-gated tool imported from another MCP server
Reproduction
- Connect ChatGPT to Executor using
elicitation_mode=model.
- Through
execute, call an imported tool whose policy requires approval.
- Executor returns a paused result with an
executionId.
- Approve the action and immediately call
resume with that ID.
- Executor returns
execution_not_found.
Repeating the flow with a fresh execution produces the same result.
Expected behavior
The authenticated client should be able to resume its paused execution even when the resume call arrives through a new MCP session.
Actual behavior
The paused execution is visible only to the engine attached to the original MCP session. A new session receives:
Evidence
The self-host logs show the paused execute request in one MCP session at 20:00:00, followed by a new MCP initialization and the resume request at 20:00:04.
The current self-host implementation appears session-local:
makeInMemoryMcpSessionStore stores ExecutionEngine instances in an engines map keyed by MCP session ID.
- Each MCP session builds its own server and engine.
resumeExecution calls engine.resume() on the current session's engine.
- Self-host does not configure a cross-session
resumeFallback.
Relevant files:
packages/hosts/mcp/src/in-memory-session-store.ts
packages/hosts/mcp/src/tool-server.ts
apps/host-selfhost/src/mcp/session-store.ts
Suggested direction
Maintain an identity- and resource-scoped directory from paused execution ID to its owning engine, then delegate cross-session resume to that engine. Entries should be removed when the execution settles, expires, or its owning session is disposed.
Persisted resumable execution state would also solve this and would survive process restarts.
Additional context
Native elicitation is not an alternative for this client because the ChatGPT runtime connection does not advertise elicitation.form. Model resume is therefore the intended compatibility path.
Summary
Approval-gated tools called through
executepause correctly withelicitation_mode=model, but an immediateresumefrom a new MCP session returnsexecution_not_found.ChatGPT creates a separate MCP session for the
resumetool call. Executor self-host stores the paused execution only in the engine belonging to the original session, so the new session cannot find it.Environment
v1.6.00ae7959fe03e8fb98d0b8a961438ad88e49fbd4b?elicitation_mode=modelReproduction
elicitation_mode=model.execute, call an imported tool whose policy requires approval.executionId.resumewith that ID.execution_not_found.Repeating the flow with a fresh execution produces the same result.
Expected behavior
The authenticated client should be able to resume its paused execution even when the
resumecall arrives through a new MCP session.Actual behavior
The paused execution is visible only to the engine attached to the original MCP session. A new session receives:
Evidence
The self-host logs show the paused
executerequest in one MCP session at20:00:00, followed by a new MCP initialization and theresumerequest at20:00:04.The current self-host implementation appears session-local:
makeInMemoryMcpSessionStorestoresExecutionEngineinstances in anenginesmap keyed by MCP session ID.resumeExecutioncallsengine.resume()on the current session's engine.resumeFallback.Relevant files:
packages/hosts/mcp/src/in-memory-session-store.tspackages/hosts/mcp/src/tool-server.tsapps/host-selfhost/src/mcp/session-store.tsSuggested direction
Maintain an identity- and resource-scoped directory from paused execution ID to its owning engine, then delegate cross-session resume to that engine. Entries should be removed when the execution settles, expires, or its owning session is disposed.
Persisted resumable execution state would also solve this and would survive process restarts.
Additional context
Native elicitation is not an alternative for this client because the ChatGPT runtime connection does not advertise
elicitation.form. Model resume is therefore the intended compatibility path.