fix(core): keep mcp elicitations alive

This commit is contained in:
Aiden Cline
2026-07-03 12:16:08 -05:00
parent 12d9f4b29b
commit 2c5cc78cd5
+26 -3
View File
@@ -32,6 +32,7 @@ import { InstallationVersion } from "../installation/version"
const DEFAULT_STARTUP_TIMEOUT = 30_000
const DEFAULT_REQUEST_TIMEOUT = 30_000
const ELICITATION_PROGRESS_INTERVAL = 10_000
type Transport = StdioClientTransport | StreamableHTTPClientTransport
@@ -182,9 +183,31 @@ export const connect = Effect.fnUntraced(function* (
Promise.resolve({ roots: [{ uri: pathToFileURL(directory).href }] }),
)
if (elicitation) {
client.setRequestHandler(ElicitRequestSchema, (request, extra) =>
Effect.runPromise(elicitation.create({ server, params: request.params, signal: extra.signal })),
)
client.setRequestHandler(ElicitRequestSchema, async (request, extra) => {
const progressToken = extra._meta?.progressToken
const started = Date.now()
// Human input can exceed the server's request timeout; progress keeps cooperative callers alive.
const sendProgress = () => {
if (progressToken === undefined) return
void extra
.sendNotification({
method: "notifications/progress",
params: {
progressToken,
progress: Date.now() - started,
message: "Waiting for user response",
},
})
.catch(() => undefined)
}
const interval = progressToken === undefined ? undefined : setInterval(sendProgress, ELICITATION_PROGRESS_INTERVAL)
sendProgress()
try {
return await Effect.runPromise(elicitation.create({ server, params: request.params, signal: extra.signal }))
} finally {
if (interval !== undefined) clearInterval(interval)
}
})
client.setNotificationHandler(ElicitationCompleteNotificationSchema, (notification) =>
Effect.runPromise(elicitation.complete({ server, elicitationID: notification.params.elicitationId })),
)