@@ -214,3 +214,77 @@ async def poll(task_id):
214214 result = await client .call_tool_async (tool_use_id = "t" , name = "success_tool" , arguments = {})
215215 assert result ["status" ] == "success"
216216 assert "Done" in result ["content" ][0 ].get ("text" , "" )
217+
218+
219+ class TestTaskMetaForwarding :
220+ """Tests for meta parameter forwarding in task-augmented execution."""
221+
222+ def _setup_task_tool_with_meta (self , mock_session , tool_name : str ) -> MagicMock :
223+ """Helper to set up a mock task-enabled tool and return the experimental mock."""
224+ mock_session .get_server_capabilities = MagicMock (return_value = create_server_capabilities (True ))
225+ mock_tool = MCPTool (
226+ name = tool_name ,
227+ description = "A test tool" ,
228+ inputSchema = {"type" : "object" },
229+ execution = ToolExecution (taskSupport = "optional" ),
230+ )
231+ mock_session .list_tools = AsyncMock (return_value = ListToolsResult (tools = [mock_tool ], nextCursor = None ))
232+ mock_create_result = MagicMock ()
233+ mock_create_result .task .taskId = "test-task-id"
234+ mock_session .experimental = MagicMock ()
235+ mock_session .experimental .call_tool_as_task = AsyncMock (return_value = mock_create_result )
236+
237+ async def successful_poll (task_id ):
238+ yield MagicMock (status = "completed" , statusMessage = None )
239+
240+ mock_session .experimental .poll_task = successful_poll
241+ mock_session .experimental .get_task_result = AsyncMock (
242+ return_value = MCPCallToolResult (content = [MCPTextContent (type = "text" , text = "Done" )], isError = False )
243+ )
244+
245+ return mock_session .experimental
246+
247+ def test_call_tool_sync_forwards_meta_to_task (self , mock_transport , mock_session ):
248+ """Test that call_tool_sync forwards meta to call_tool_as_task."""
249+ experimental = self ._setup_task_tool_with_meta (mock_session , "meta_tool" )
250+ meta = {"com.example/request_id" : "abc-123" }
251+
252+ with MCPClient (mock_transport ["transport_callable" ], tasks_config = TasksConfig ()) as client :
253+ client .list_tools_sync ()
254+ client .call_tool_sync (
255+ tool_use_id = "test-id" , name = "meta_tool" , arguments = {"param" : "value" }, meta = meta
256+ )
257+
258+ experimental .call_tool_as_task .assert_called_once ()
259+ call_kwargs = experimental .call_tool_as_task .call_args
260+ assert call_kwargs .kwargs .get ("meta" ) == meta
261+
262+ @pytest .mark .asyncio
263+ async def test_call_tool_async_forwards_meta_to_task (self , mock_transport , mock_session ):
264+ """Test that call_tool_async forwards meta to call_tool_as_task."""
265+ experimental = self ._setup_task_tool_with_meta (mock_session , "meta_tool" )
266+ meta = {"com.example/trace_id" : "xyz-456" }
267+
268+ with MCPClient (mock_transport ["transport_callable" ], tasks_config = TasksConfig ()) as client :
269+ client .list_tools_sync ()
270+ await client .call_tool_async (
271+ tool_use_id = "test-id" , name = "meta_tool" , arguments = {"param" : "value" }, meta = meta
272+ )
273+
274+ experimental .call_tool_as_task .assert_called_once ()
275+ call_kwargs = experimental .call_tool_as_task .call_args
276+ assert call_kwargs .kwargs .get ("meta" ) == meta
277+
278+ def test_call_tool_sync_forwards_none_meta_to_task (self , mock_transport , mock_session ):
279+ """Test that call_tool_sync forwards None meta to call_tool_as_task when not provided."""
280+ experimental = self ._setup_task_tool_with_meta (mock_session , "no_meta_tool" )
281+
282+ with MCPClient (mock_transport ["transport_callable" ], tasks_config = TasksConfig ()) as client :
283+ client .list_tools_sync ()
284+ client .call_tool_sync (
285+ tool_use_id = "test-id" , name = "no_meta_tool" , arguments = {"param" : "value" }
286+ )
287+
288+ experimental .call_tool_as_task .assert_called_once ()
289+ call_kwargs = experimental .call_tool_as_task .call_args
290+ assert call_kwargs .kwargs .get ("meta" ) is None
0 commit comments