@@ -5,14 +5,7 @@ import { McpServer } from '../../server/mcp.js';
55import { StreamableHTTPServerTransport } from '../../server/streamableHttp.js' ;
66import { getOAuthProtectedResourceMetadataUrl , mcpAuthMetadataRouter } from '../../server/auth/router.js' ;
77import { requireBearerAuth } from '../../server/auth/middleware/bearerAuth.js' ;
8- import {
9- CallToolResult ,
10- UrlElicitationRequiredError ,
11- ElicitRequestURLParams ,
12- ElicitResult ,
13- isInitializeRequest ,
14- ElicitationCompleteNotification
15- } from '../../types.js' ;
8+ import { CallToolResult , UrlElicitationRequiredError , ElicitRequestURLParams , ElicitResult , isInitializeRequest } from '../../types.js' ;
169import { InMemoryEventStore } from '../shared/inMemoryEventStore.js' ;
1710import { setupAuthServer } from './demoInMemoryOAuthProvider.js' ;
1811import { OAuthMetadata } from '../../shared/auth.js' ;
@@ -51,9 +44,9 @@ const getServer = () => {
5144 }
5245
5346 // Create and track the elicitation
54- const elicitationId = generateTrackedElicitation ( sessionId , async ( notification : ElicitationCompleteNotification ) => {
55- await mcpServer . server . notification ( notification ) ;
56- } ) ;
47+ const elicitationId = generateTrackedElicitation ( sessionId , elicitationId =>
48+ mcpServer . server . createElicitationCompletionNotifier ( elicitationId )
49+ ) ;
5750 throw new UrlElicitationRequiredError ( [
5851 {
5952 mode : 'url' ,
@@ -87,9 +80,9 @@ const getServer = () => {
8780 }
8881
8982 // Create and track the elicitation
90- const elicitationId = generateTrackedElicitation ( sessionId , async ( notification : ElicitationCompleteNotification ) => {
91- await mcpServer . server . notification ( notification ) ;
92- } ) ;
83+ const elicitationId = generateTrackedElicitation ( sessionId , elicitationId =>
84+ mcpServer . server . createElicitationCompletionNotifier ( elicitationId )
85+ ) ;
9386
9487 // Simulate OAuth callback and token exchange after 5 seconds
9588 // In a real app, this would be called from your OAuth callback handler
@@ -122,7 +115,7 @@ interface ElicitationMetadata {
122115 completeResolver : ( ) => void ;
123116 createdAt : Date ;
124117 sessionId : string ;
125- notificationSender ?: ( notification : ElicitationCompleteNotification ) => Promise < void > ;
118+ completionNotifier ?: ( ) => Promise < void > ;
126119}
127120
128121const elicitationsMap = new Map < string , ElicitationMetadata > ( ) ;
@@ -154,10 +147,7 @@ function generateElicitationId(): string {
154147/**
155148 * Helper function to create and track a new elicitation.
156149 */
157- function generateTrackedElicitation (
158- sessionId : string ,
159- notificationSender ?: ( notification : ElicitationCompleteNotification ) => Promise < void >
160- ) : string {
150+ function generateTrackedElicitation ( sessionId : string , createCompletionNotifier ?: ElicitationCompletionNotifierFactory ) : string {
161151 const elicitationId = generateElicitationId ( ) ;
162152
163153 // Create a Promise and its resolver for tracking completion
@@ -166,14 +156,16 @@ function generateTrackedElicitation(
166156 completeResolver = resolve ;
167157 } ) ;
168158
159+ const completionNotifier = createCompletionNotifier ? createCompletionNotifier ( elicitationId ) : undefined ;
160+
169161 // Store the elicitation in our map
170162 elicitationsMap . set ( elicitationId , {
171163 status : 'pending' ,
172164 completedPromise,
173165 completeResolver : completeResolver ! ,
174166 createdAt : new Date ( ) ,
175167 sessionId,
176- notificationSender
168+ completionNotifier
177169 } ) ;
178170
179171 return elicitationId ;
@@ -198,19 +190,12 @@ function completeURLElicitation(elicitationId: string) {
198190 elicitation . status = 'complete' ;
199191
200192 // Send completion notification to the client
201- if ( elicitation . notificationSender ) {
193+ if ( elicitation . completionNotifier ) {
202194 console . log ( `Sending notifications/elicitation/complete notification for elicitation ${ elicitationId } ` ) ;
203195
204- elicitation
205- . notificationSender ( {
206- method : 'notifications/elicitation/complete' ,
207- params : {
208- elicitationId
209- }
210- } )
211- . catch ( error => {
212- console . error ( `Failed to send completion notification for elicitation ${ elicitationId } :` , error ) ;
213- } ) ;
196+ elicitation . completionNotifier ( ) . catch ( error => {
197+ console . error ( `Failed to send completion notification for elicitation ${ elicitationId } :` , error ) ;
198+ } ) ;
214199 }
215200
216201 // Resolve the promise to unblock any waiting code
@@ -303,14 +288,18 @@ authMiddleware = requireBearerAuth({
303288 * URL-mode elicitation enables the server to host a simple form and get the secret data securely from the user without involving the LLM or client.
304289 **/
305290
306- async function sendApiKeyElicitation ( sessionId : string , sender : ElicitationSender , notificationSender : ElicitationNotificationSender ) {
291+ async function sendApiKeyElicitation (
292+ sessionId : string ,
293+ sender : ElicitationSender ,
294+ createCompletionNotifier : ElicitationCompletionNotifierFactory
295+ ) {
307296 if ( ! sessionId ) {
308297 console . error ( 'No session ID provided' ) ;
309298 throw new Error ( 'Expected a Session ID to track elicitation' ) ;
310299 }
311300
312301 console . log ( '🔑 URL elicitation demo: Requesting API key from client...' ) ;
313- const elicitationId = generateTrackedElicitation ( sessionId , notificationSender ) ;
302+ const elicitationId = generateTrackedElicitation ( sessionId , createCompletionNotifier ) ;
314303 try {
315304 const result = await sender ( {
316305 mode : 'url' ,
@@ -593,12 +582,12 @@ const transports: { [sessionId: string]: StreamableHTTPServerTransport } = {};
593582
594583// Interface for a function that can send an elicitation request
595584type ElicitationSender = ( params : ElicitRequestURLParams ) => Promise < ElicitResult > ;
596- type ElicitationNotificationSender = ( notification : ElicitationCompleteNotification ) => Promise < void > ;
585+ type ElicitationCompletionNotifierFactory = ( elicitationId : string ) => ( ) => Promise < void > ;
597586
598587// Track sessions that need an elicitation request to be sent
599588interface SessionElicitationInfo {
600589 elicitationSender : ElicitationSender ;
601- notificationSender : ElicitationNotificationSender ;
590+ createCompletionNotifier : ElicitationCompletionNotifierFactory ;
602591}
603592const sessionsNeedingElicitation : { [ sessionId : string ] : SessionElicitationInfo } = { } ;
604593
@@ -626,9 +615,7 @@ const mcpPostHandler = async (req: Request, res: Response) => {
626615 transports [ sessionId ] = transport ;
627616 sessionsNeedingElicitation [ sessionId ] = {
628617 elicitationSender : server . server . elicitUrl . bind ( server . server ) ,
629- notificationSender : async ( notification : ElicitationCompleteNotification ) => {
630- await server . server . notification ( notification ) ;
631- }
618+ createCompletionNotifier : elicitationId => server . server . createElicitationCompletionNotifier ( elicitationId )
632619 } ;
633620 }
634621 } ) ;
@@ -703,10 +690,10 @@ const mcpGetHandler = async (req: Request, res: Response) => {
703690 await transport . handleRequest ( req , res ) ;
704691
705692 if ( sessionsNeedingElicitation [ sessionId ] ) {
706- const { elicitationSender, notificationSender } = sessionsNeedingElicitation [ sessionId ] ;
693+ const { elicitationSender, createCompletionNotifier } = sessionsNeedingElicitation [ sessionId ] ;
707694
708695 // Send an elicitation request to the client in the background
709- sendApiKeyElicitation ( sessionId , elicitationSender , notificationSender )
696+ sendApiKeyElicitation ( sessionId , elicitationSender , createCompletionNotifier )
710697 . then ( ( ) => {
711698 // Only delete on successful send for this demo
712699 delete sessionsNeedingElicitation [ sessionId ] ;
0 commit comments