@@ -82,6 +82,18 @@ async def __call__(self) -> None:
8282 self .notification_count += 1
8383
8484
85+ class ElicitCompleteCollector :
86+ """Collector for ElicitCompleteNotification events."""
87+
88+ def __init__ (self ) -> None :
89+ """Initialize the collector."""
90+ self .notifications : list [types .ElicitCompleteNotificationParams ] = []
91+
92+ async def __call__ (self , params : types .ElicitCompleteNotificationParams ) -> None :
93+ """Collect an elicit complete notification."""
94+ self .notifications .append (params )
95+
96+
8597@pytest .fixture
8698def progress_collector () -> ProgressNotificationCollector :
8799 """Create a progress notification collector."""
@@ -112,6 +124,12 @@ def prompt_list_changed_collector() -> PromptListChangedCollector:
112124 return PromptListChangedCollector ()
113125
114126
127+ @pytest .fixture
128+ def elicit_complete_collector () -> ElicitCompleteCollector :
129+ """Create an elicit complete collector."""
130+ return ElicitCompleteCollector ()
131+
132+
115133@pytest .mark .anyio
116134async def test_progress_notification_callback (progress_collector : ProgressNotificationCollector ) -> None :
117135 """Test that progress notifications are correctly received by the callback."""
@@ -298,6 +316,41 @@ async def message_handler(
298316 assert prompt_list_changed_collector .notification_count == 1
299317
300318
319+ @pytest .mark .anyio
320+ async def test_elicit_complete_callback (elicit_complete_collector : ElicitCompleteCollector ) -> None :
321+ """Test that elicit complete notifications are correctly received by the callback."""
322+ from mcp .server .fastmcp import FastMCP
323+
324+ server = FastMCP ("test" )
325+
326+ @server .tool ("send_elicit_complete" )
327+ async def send_elicit_complete_tool (elicitation_id : str ) -> bool :
328+ """Send an elicit complete notification to the client."""
329+ await server .get_context ().session .send_elicit_complete (elicitation_id )
330+ return True
331+
332+ async def message_handler (
333+ message : RequestResponder [types .ServerRequest , types .ClientResult ] | types .ServerNotification | Exception ,
334+ ) -> None :
335+ """Handle exceptions from the session."""
336+ if isinstance (message , Exception ): # pragma: no cover
337+ raise message
338+
339+ async with create_session (
340+ server ._mcp_server ,
341+ elicit_complete_callback = elicit_complete_collector ,
342+ message_handler = message_handler ,
343+ ) as client_session :
344+ # Trigger elicit complete notification
345+ result = await client_session .call_tool ("send_elicit_complete" , {"elicitation_id" : "test-elicit-123" })
346+ assert result .isError is False
347+
348+ # Verify the notification was received
349+ assert len (elicit_complete_collector .notifications ) == 1
350+ notification = elicit_complete_collector .notifications [0 ]
351+ assert notification .elicitationId == "test-elicit-123"
352+
353+
301354@pytest .mark .anyio
302355@pytest .mark .parametrize (
303356 "notification_type,callback_param,collector_fixture,tool_name,tool_args,verification" ,
@@ -350,6 +403,17 @@ async def message_handler(
350403 {},
351404 lambda c : c .notification_count == 1 , # type: ignore[attr-defined]
352405 ),
406+ (
407+ "elicit_complete" ,
408+ "elicit_complete_callback" ,
409+ "elicit_complete_collector" ,
410+ "send_elicit_complete" ,
411+ {"elicitation_id" : "param-test-elicit-456" },
412+ lambda c : ( # type: ignore[misc]
413+ len (c .notifications ) == 1 # type: ignore[attr-defined]
414+ and c .notifications [0 ].elicitationId == "param-test-elicit-456" # type: ignore[attr-defined]
415+ ),
416+ ),
353417 ],
354418)
355419async def test_notification_callback_parametrized (
@@ -407,6 +471,12 @@ async def change_prompt_list_tool() -> bool:
407471 await server .get_context ().session .send_prompt_list_changed ()
408472 return True
409473
474+ @server .tool ("send_elicit_complete" )
475+ async def send_elicit_complete_tool (elicitation_id : str ) -> bool :
476+ """Send an elicit complete notification to the client."""
477+ await server .get_context ().session .send_elicit_complete (elicitation_id )
478+ return True
479+
410480 async def message_handler (
411481 message : RequestResponder [types .ServerRequest , types .ClientResult ] | types .ServerNotification | Exception ,
412482 ) -> None :
@@ -478,6 +548,12 @@ async def send_prompt_list_changed_tool() -> bool:
478548 await server .get_context ().session .send_prompt_list_changed ()
479549 return True
480550
551+ @server .tool ("send_elicit_complete" )
552+ async def send_elicit_complete_tool (elicitation_id : str ) -> bool :
553+ """Send an elicit complete notification."""
554+ await server .get_context ().session .send_elicit_complete (elicitation_id )
555+ return True
556+
481557 # Create session WITHOUT custom callbacks - all will use defaults
482558 async with create_session (server ._mcp_server ) as client_session :
483559 # Test progress notification with default callback
@@ -507,6 +583,10 @@ async def send_prompt_list_changed_tool() -> bool:
507583 result5 = await client_session .call_tool ("send_prompt_list_changed" , {})
508584 assert result5 .isError is False
509585
586+ # Test elicit complete with default callback
587+ result6 = await client_session .call_tool ("send_elicit_complete" , {"elicitation_id" : "test-123" })
588+ assert result6 .isError is False
589+
510590
511591@pytest .mark .anyio
512592async def test_progress_tool_without_progress_token () -> None :
0 commit comments