@@ -4,11 +4,10 @@ import {
44 CallToolResult ,
55 GetTaskResult ,
66 Task ,
7+ ElicitResult ,
78 ElicitResultSchema ,
8- ServerRequest ,
99} from "@modelcontextprotocol/sdk/types.js" ;
10- import { CreateTaskResult } from "@modelcontextprotocol/sdk/experimental" ;
11- import type { AnySchema , SchemaOutput } from "@modelcontextprotocol/sdk/server/zod-compat.js" ;
10+ import { CreateTaskResult } from "@modelcontextprotocol/sdk/experimental/tasks" ;
1211
1312// Tool input schema
1413const SimulateResearchQuerySchema = z . object ( {
@@ -48,7 +47,11 @@ const researchStates = new Map<string, ResearchState>();
4847/**
4948 * Runs the background research process.
5049 * Updates task status as it progresses through stages.
51- * If clarification is needed, sends elicitation request directly.
50+ * If clarification is needed, attempts elicitation via sendRequest.
51+ *
52+ * Note: Elicitation only works on STDIO transport. On HTTP transport,
53+ * sendRequest will fail and the task will use a default interpretation.
54+ * Full HTTP support requires SDK PR #1210's elicitInputStream API.
5255 */
5356async function runResearchProcess (
5457 taskId : string ,
@@ -65,11 +68,8 @@ async function runResearchProcess(
6568 result : CallToolResult
6669 ) => Promise < void > ;
6770 } ,
68- sendRequest : < U extends AnySchema > (
69- request : ServerRequest ,
70- resultSchema : U ,
71- options ?: { timeout ?: number }
72- ) => Promise < SchemaOutput < U > >
71+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72+ sendRequest : any
7373) : Promise < void > {
7474 const state = researchStates . get ( taskId ) ;
7575 if ( ! state ) return ;
@@ -86,56 +86,63 @@ async function runResearchProcess(
8686
8787 // At synthesis stage (index 2), check if clarification is needed
8888 if ( i === 2 && state . ambiguous && ! state . clarification ) {
89- // Update status to show we're requesting input
89+ // Update status to show we're requesting input (spec SHOULD)
9090 await taskStore . updateTaskStatus (
9191 taskId ,
9292 "input_required" ,
9393 `Found multiple interpretations for "${ state . topic } ". Requesting clarification...`
9494 ) ;
9595
96- // Send elicitation directly and await response
97- const elicitationResult = await sendRequest (
98- {
99- method : "elicitation/create" ,
100- params : {
101- message : `The research query "${ state . topic } " could have multiple interpretations. Please clarify what you're looking for:` ,
102- requestedSchema : {
103- type : "object" ,
104- properties : {
105- interpretation : {
106- type : "string" ,
107- title : "Clarification" ,
108- description : "Which interpretation of the topic do you mean?" ,
109- oneOf : getInterpretationsForTopic ( state . topic ) ,
96+ try {
97+ // Try elicitation via sendRequest (works on STDIO, fails on HTTP)
98+ const elicitResult : ElicitResult = await sendRequest (
99+ {
100+ method : "elicitation/create" ,
101+ params : {
102+ message : `The research query "${ state . topic } " could have multiple interpretations. Please clarify what you're looking for:` ,
103+ requestedSchema : {
104+ type : "object" ,
105+ properties : {
106+ interpretation : {
107+ type : "string" ,
108+ title : "Clarification" ,
109+ description : "Which interpretation of the topic do you mean?" ,
110+ oneOf : getInterpretationsForTopic ( state . topic ) ,
111+ } ,
110112 } ,
113+ required : [ "interpretation" ] ,
111114 } ,
112- required : [ "interpretation" ] ,
113115 } ,
114116 } ,
115- } ,
116- ElicitResultSchema ,
117- { timeout : 5 * 60 * 1000 /* 5 minutes */ }
118- ) ;
119-
120- // Process elicitation response
121- if (
122- elicitationResult . action === "accept" &&
123- elicitationResult . content
124- ) {
117+ ElicitResultSchema
118+ ) ;
119+
120+ // Process elicitation response
121+ if ( elicitResult . action === "accept" && elicitResult . content ) {
122+ state . clarification =
123+ ( elicitResult . content as { interpretation ?: string } )
124+ . interpretation || "User accepted without selection" ;
125+ } else if ( elicitResult . action === "decline" ) {
126+ state . clarification = "User declined - using default interpretation" ;
127+ } else {
128+ state . clarification = "User cancelled - using default interpretation" ;
129+ }
130+ } catch ( error ) {
131+ // Elicitation failed (likely HTTP transport without streaming support)
132+ // Use default interpretation and continue - task should still complete
133+ console . warn (
134+ `Elicitation failed for task ${ taskId } (HTTP transport?):` ,
135+ error instanceof Error ? error . message : String ( error )
136+ ) ;
125137 state . clarification =
126- ( elicitationResult . content as { interpretation ?: string } )
127- . interpretation || "User accepted without selection" ;
128- } else if ( elicitationResult . action === "decline" ) {
129- state . clarification = "User declined - using default interpretation" ;
130- } else {
131- state . clarification = "User cancelled - using default interpretation" ;
138+ "technical (default - elicitation unavailable on HTTP)" ;
132139 }
133140
134- // Resume with working status
141+ // Resume with working status (spec SHOULD)
135142 await taskStore . updateTaskStatus (
136143 taskId ,
137144 "working" ,
138- `Received clarification : "${ state . clarification } ". Continuing ...`
145+ `Continuing with interpretation : "${ state . clarification } "...`
139146 ) ;
140147
141148 // Continue processing (no return - just keep going through the loop)
@@ -185,9 +192,12 @@ This tool demonstrates MCP's task-based execution pattern for long-running opera
185192
186193${ state . clarification ? `**Elicitation Flow:**
187194When the query was ambiguous, the server sent an \`elicitation/create\` request
188- directly to the client. The task status changed to \`input_required\` while
189- awaiting user input. After receiving clarification ("${ state . clarification } "),
190- the task resumed processing and completed.
195+ to the client. The task status changed to \`input_required\` while awaiting user input.
196+ ${ state . clarification . includes ( "unavailable on HTTP" ) ? `
197+ **Note:** Elicitation was skipped because this server is running over HTTP transport.
198+ The current SDK's \`sendRequest\` only works over STDIO. Full HTTP elicitation support
199+ requires SDK PR #1210's streaming \`elicitInputStream\` API.
200+ ` : `After receiving clarification ("${ state . clarification } "), the task resumed processing and completed.` }
191201` : "" }
192202**Key Concepts:**
193203- Tasks enable "call now, fetch later" patterns
@@ -258,7 +268,7 @@ export const registerSimulateResearchQueryTool = (server: McpServer) => {
258268 researchStates . set ( task . taskId , state ) ;
259269
260270 // Start background research (don't await - runs asynchronously)
261- // Pass sendRequest so elicitation can be sent directly from the background process
271+ // Pass sendRequest for elicitation (works on STDIO, gracefully degrades on HTTP)
262272 runResearchProcess (
263273 task . taskId ,
264274 validatedArgs ,
0 commit comments