Jeremiah Lowin commited on
Commit
da5987c
·
1 Parent(s): aa46c09

Update for 'result' kwarg instead of 'value'

Browse files
tests/tools/test_tool_manager.py CHANGED
@@ -355,7 +355,7 @@ class TestCallTools:
355
  result = await manager.call_tool("add", {"a": 1, "b": 2})
356
 
357
  assert result.content[0].text == "3" # type: ignore[attr-defined]
358
- assert result.structured_content == {"value": 3}
359
 
360
  async def test_call_async_tool(self):
361
  async def double(n: int) -> int:
@@ -367,7 +367,7 @@ class TestCallTools:
367
  manager.add_tool(tool)
368
  result = await manager.call_tool("double", {"n": 5})
369
  assert result.content[0].text == "10" # type: ignore[attr-defined]
370
- assert result.structured_content == {"value": 10}
371
 
372
  async def test_call_tool_callable_object(self):
373
  class Adder:
@@ -382,7 +382,7 @@ class TestCallTools:
382
  manager.add_tool(tool)
383
  result = await manager.call_tool("Adder", {"x": 1, "y": 2})
384
  assert result.content[0].text == "3" # type: ignore[attr-defined]
385
- assert result.structured_content == {"value": 3}
386
 
387
  async def test_call_tool_callable_object_async(self):
388
  class Adder:
@@ -397,7 +397,7 @@ class TestCallTools:
397
  manager.add_tool(tool)
398
  result = await manager.call_tool("Adder", {"x": 1, "y": 2})
399
  assert result.content[0].text == "3" # type: ignore[attr-defined]
400
- assert result.structured_content == {"value": 3}
401
 
402
  async def test_call_tool_with_default_args(self):
403
  def add(a: int, b: int = 1) -> int:
@@ -410,7 +410,7 @@ class TestCallTools:
410
  result = await manager.call_tool("add", {"a": 1})
411
 
412
  assert result.content[0].text == "2" # type: ignore[attr-defined]
413
- assert result.structured_content == {"value": 2}
414
 
415
  async def test_call_tool_with_missing_args(self):
416
  def add(a: int, b: int) -> int:
@@ -438,7 +438,7 @@ class TestCallTools:
438
 
439
  result = await manager.call_tool("sum_vals", {"vals": [1, 2, 3]})
440
  assert result.content[0].text == "6" # type: ignore[attr-defined]
441
- assert result.structured_content == {"value": 6}
442
 
443
  async def test_call_tool_with_list_str_or_str_input(self):
444
  def concat_strs(vals: list[str] | str) -> str:
@@ -451,11 +451,11 @@ class TestCallTools:
451
  # Try both with plain python object and with JSON list
452
  result = await manager.call_tool("concat_strs", {"vals": ["a", "b", "c"]})
453
  assert result.content[0].text == "abc" # type: ignore[attr-defined]
454
- assert result.structured_content == {"value": "abc"}
455
 
456
  result = await manager.call_tool("concat_strs", {"vals": "a"})
457
  assert result.content[0].text == "a" # type: ignore[attr-defined]
458
- assert result.structured_content == {"value": "a"}
459
 
460
  async def test_call_tool_with_complex_model(self):
461
  class MyShrimpTank(BaseModel):
@@ -487,7 +487,7 @@ class TestCallTools:
487
  )
488
 
489
  assert result.content[0].text == '[\n "rex",\n "gertrude"\n]' # type: ignore[attr-defined]
490
- assert result.structured_content == {"value": ["rex", "gertrude"]}
491
 
492
  async def test_call_tool_with_custom_serializer(self):
493
  """Test that a custom serializer provided to FastMCP is used by tools."""
@@ -533,7 +533,7 @@ class TestCallTools:
533
  == 'CUSTOM:[{"key": "value", "number": 123}, {"key": "value2", "number": 456}]' # type: ignore[attr-defined]
534
  )
535
  assert result.structured_content == {
536
- "value": [
537
  {"key": "value", "number": 123},
538
  {"key": "value2", "number": 456},
539
  ]
@@ -559,7 +559,7 @@ class TestCallTools:
559
  result.content[0].text # type: ignore[attr-defined]
560
  == pydantic_core.to_json(uuid_result).decode()
561
  )
562
- assert result.structured_content == {"value": str(uuid_result)}
563
 
564
 
565
  class TestToolSchema:
@@ -630,7 +630,7 @@ class TestContextHandling:
630
  async with context:
631
  result = await manager.call_tool("tool_with_context", {"x": 42})
632
  assert result.content[0].text == "42" # type: ignore[attr-defined]
633
- assert result.structured_content == {"value": "42"}
634
 
635
  async def test_context_injection_async(self):
636
  """Test that context is properly injected in async tools."""
@@ -649,7 +649,7 @@ class TestContextHandling:
649
  async with context:
650
  result = await manager.call_tool("async_tool", {"x": 42})
651
  assert result.content[0].text == "42" # type: ignore[attr-defined]
652
- assert result.structured_content == {"value": "42"}
653
 
654
  async def test_context_optional(self):
655
  """Test that context is optional when calling tools."""
@@ -668,7 +668,7 @@ class TestContextHandling:
668
  async with context:
669
  result = await manager.call_tool("tool_with_context", {"x": 42})
670
  assert result.content[0].text == "42" # type: ignore[attr-defined]
671
- assert result.structured_content == {"value": 42}
672
 
673
  def test_parameterized_context_parameter_detection(self):
674
  """Test that context parameters are properly detected in
@@ -777,7 +777,7 @@ class TestCustomToolNames:
777
  # Tool should be callable by its custom name
778
  result = await manager.call_tool("custom_multiply", {"a": 5, "b": 3})
779
  assert result.content[0].text == "15" # type: ignore[attr-defined]
780
- assert result.structured_content == {"value": 15}
781
 
782
  # Original name should not be registered
783
  with pytest.raises(NotFoundError, match="Tool 'multiply' not found"):
 
355
  result = await manager.call_tool("add", {"a": 1, "b": 2})
356
 
357
  assert result.content[0].text == "3" # type: ignore[attr-defined]
358
+ assert result.structured_content == {"result": 3}
359
 
360
  async def test_call_async_tool(self):
361
  async def double(n: int) -> int:
 
367
  manager.add_tool(tool)
368
  result = await manager.call_tool("double", {"n": 5})
369
  assert result.content[0].text == "10" # type: ignore[attr-defined]
370
+ assert result.structured_content == {"result": 10}
371
 
372
  async def test_call_tool_callable_object(self):
373
  class Adder:
 
382
  manager.add_tool(tool)
383
  result = await manager.call_tool("Adder", {"x": 1, "y": 2})
384
  assert result.content[0].text == "3" # type: ignore[attr-defined]
385
+ assert result.structured_content == {"result": 3}
386
 
387
  async def test_call_tool_callable_object_async(self):
388
  class Adder:
 
397
  manager.add_tool(tool)
398
  result = await manager.call_tool("Adder", {"x": 1, "y": 2})
399
  assert result.content[0].text == "3" # type: ignore[attr-defined]
400
+ assert result.structured_content == {"result": 3}
401
 
402
  async def test_call_tool_with_default_args(self):
403
  def add(a: int, b: int = 1) -> int:
 
410
  result = await manager.call_tool("add", {"a": 1})
411
 
412
  assert result.content[0].text == "2" # type: ignore[attr-defined]
413
+ assert result.structured_content == {"result": 2}
414
 
415
  async def test_call_tool_with_missing_args(self):
416
  def add(a: int, b: int) -> int:
 
438
 
439
  result = await manager.call_tool("sum_vals", {"vals": [1, 2, 3]})
440
  assert result.content[0].text == "6" # type: ignore[attr-defined]
441
+ assert result.structured_content == {"result": 6}
442
 
443
  async def test_call_tool_with_list_str_or_str_input(self):
444
  def concat_strs(vals: list[str] | str) -> str:
 
451
  # Try both with plain python object and with JSON list
452
  result = await manager.call_tool("concat_strs", {"vals": ["a", "b", "c"]})
453
  assert result.content[0].text == "abc" # type: ignore[attr-defined]
454
+ assert result.structured_content == {"result": "abc"}
455
 
456
  result = await manager.call_tool("concat_strs", {"vals": "a"})
457
  assert result.content[0].text == "a" # type: ignore[attr-defined]
458
+ assert result.structured_content == {"result": "a"}
459
 
460
  async def test_call_tool_with_complex_model(self):
461
  class MyShrimpTank(BaseModel):
 
487
  )
488
 
489
  assert result.content[0].text == '[\n "rex",\n "gertrude"\n]' # type: ignore[attr-defined]
490
+ assert result.structured_content == {"result": ["rex", "gertrude"]}
491
 
492
  async def test_call_tool_with_custom_serializer(self):
493
  """Test that a custom serializer provided to FastMCP is used by tools."""
 
533
  == 'CUSTOM:[{"key": "value", "number": 123}, {"key": "value2", "number": 456}]' # type: ignore[attr-defined]
534
  )
535
  assert result.structured_content == {
536
+ "result": [
537
  {"key": "value", "number": 123},
538
  {"key": "value2", "number": 456},
539
  ]
 
559
  result.content[0].text # type: ignore[attr-defined]
560
  == pydantic_core.to_json(uuid_result).decode()
561
  )
562
+ assert result.structured_content == {"result": str(uuid_result)}
563
 
564
 
565
  class TestToolSchema:
 
630
  async with context:
631
  result = await manager.call_tool("tool_with_context", {"x": 42})
632
  assert result.content[0].text == "42" # type: ignore[attr-defined]
633
+ assert result.structured_content == {"result": "42"}
634
 
635
  async def test_context_injection_async(self):
636
  """Test that context is properly injected in async tools."""
 
649
  async with context:
650
  result = await manager.call_tool("async_tool", {"x": 42})
651
  assert result.content[0].text == "42" # type: ignore[attr-defined]
652
+ assert result.structured_content == {"result": "42"}
653
 
654
  async def test_context_optional(self):
655
  """Test that context is optional when calling tools."""
 
668
  async with context:
669
  result = await manager.call_tool("tool_with_context", {"x": 42})
670
  assert result.content[0].text == "42" # type: ignore[attr-defined]
671
+ assert result.structured_content == {"result": 42}
672
 
673
  def test_parameterized_context_parameter_detection(self):
674
  """Test that context parameters are properly detected in
 
777
  # Tool should be callable by its custom name
778
  result = await manager.call_tool("custom_multiply", {"a": 5, "b": 3})
779
  assert result.content[0].text == "15" # type: ignore[attr-defined]
780
+ assert result.structured_content == {"result": 15}
781
 
782
  # Original name should not be registered
783
  with pytest.raises(NotFoundError, match="Tool 'multiply' not found"):
tests/tools/test_tool_transform.py CHANGED
@@ -53,7 +53,7 @@ async def test_tool_defaults_are_maintained_on_unmapped_args(add_tool):
53
  )
54
  result = await new_tool.run(arguments={"new_x": 1})
55
  # The parent tool returns int which gets wrapped as structured output
56
- assert result.structured_content == {"value": 11}
57
 
58
 
59
  async def test_tool_defaults_are_maintained_on_mapped_args(add_tool):
@@ -62,7 +62,7 @@ async def test_tool_defaults_are_maintained_on_mapped_args(add_tool):
62
  )
63
  result = await new_tool.run(arguments={"old_x": 1})
64
  # The parent tool returns int which gets wrapped as structured output
65
- assert result.structured_content == {"value": 11}
66
 
67
 
68
  def test_tool_change_arg_name(add_tool):
@@ -89,7 +89,7 @@ async def test_tool_drop_arg(add_tool):
89
  )
90
  assert sorted(new_tool.parameters["properties"]) == ["old_x"]
91
  result = await new_tool.run(arguments={"old_x": 1})
92
- assert result.structured_content == {"value": 11}
93
 
94
 
95
  async def test_dropped_args_error_if_provided(add_tool):
@@ -111,7 +111,7 @@ async def test_hidden_arg_with_constant_default(add_tool):
111
  assert sorted(new_tool.parameters["properties"]) == ["old_x"]
112
  # Should pass old_x=5 and old_y=20 to parent
113
  result = await new_tool.run(arguments={"old_x": 5})
114
- assert result.structured_content == {"value": 25}
115
 
116
 
117
  async def test_hidden_arg_without_default_uses_parent_default(add_tool):
@@ -124,7 +124,7 @@ async def test_hidden_arg_without_default_uses_parent_default(add_tool):
124
  # Should pass old_x=3 and let parent use its default old_y=10
125
  result = await new_tool.run(arguments={"old_x": 3})
126
  assert result.content[0].text == "13" # type: ignore[attr-defined]
127
- assert result.structured_content == {"value": 13}
128
 
129
 
130
  async def test_mixed_hidden_args_with_custom_function(add_tool):
@@ -150,7 +150,7 @@ async def test_mixed_hidden_args_with_custom_function(add_tool):
150
  # Should pass visible_x=7 as old_x=7 and old_y=25 to parent
151
  result = await new_tool.run(arguments={"visible_x": 7})
152
  assert result.content[0].text == "32" # type: ignore[attr-defined]
153
- assert result.structured_content == {"value": 32}
154
 
155
 
156
  async def test_hide_required_param_without_default_raises_error():
@@ -188,7 +188,7 @@ async def test_hide_required_param_with_user_default_works():
188
  assert sorted(new_tool.parameters["properties"]) == ["optional_param"]
189
  # Should pass required_param=5 and optional_param=20 to parent
190
  result = await new_tool.run(arguments={"optional_param": 20})
191
- assert result.structured_content == {"value": 25}
192
 
193
 
194
  async def test_forward_with_argument_mapping(add_tool):
@@ -208,7 +208,7 @@ async def test_forward_with_argument_mapping(add_tool):
208
 
209
  result = await new_tool.run(arguments={"new_x": 2, "new_y": 3})
210
  assert result.content[0].text == "5" # type: ignore[attr-defined]
211
- assert result.structured_content == {"value": 5}
212
 
213
 
214
  async def test_forward_with_incorrect_args_raises_error(add_tool):
@@ -249,7 +249,7 @@ async def test_forward_raw_without_argument_mapping(add_tool):
249
 
250
  result = await new_tool.run(arguments={"new_x": 2, "new_y": 3})
251
  assert result.content[0].text == "5" # type: ignore[attr-defined]
252
- assert result.structured_content == {"value": 5}
253
 
254
 
255
  async def test_custom_fn_with_kwargs_and_no_transform_args(add_tool):
@@ -260,7 +260,7 @@ async def test_custom_fn_with_kwargs_and_no_transform_args(add_tool):
260
  new_tool = Tool.from_tool(add_tool, transform_fn=custom_fn)
261
  result = await new_tool.run(arguments={"extra": 1, "old_x": 2, "old_y": 3})
262
  assert result.content[0].text == "6" # type: ignore[attr-defined]
263
- assert result.structured_content == {"value": 6}
264
  assert new_tool.parameters["required"] == IsList(
265
  "extra", "old_x", check_order=False
266
  )
@@ -278,7 +278,7 @@ async def test_fn_with_kwargs_passes_through_original_args(add_tool):
278
  new_tool = Tool.from_tool(add_tool, transform_fn=custom_fn)
279
  result = await new_tool.run(arguments={"new_y": 2, "old_y": 3})
280
  assert result.content[0].text == "5" # type: ignore[attr-defined]
281
- assert result.structured_content == {"value": 5}
282
 
283
 
284
  async def test_fn_with_kwargs_receives_transformed_arg_names(add_tool):
@@ -297,7 +297,7 @@ async def test_fn_with_kwargs_receives_transformed_arg_names(add_tool):
297
  )
298
  result = await new_tool.run(arguments={"new_x": 2, "old_y": 3})
299
  assert result.content[0].text == "5" # type: ignore[attr-defined]
300
- assert result.structured_content == {"value": 5}
301
 
302
 
303
  async def test_fn_with_kwargs_handles_partial_explicit_args(add_tool):
@@ -318,7 +318,7 @@ async def test_fn_with_kwargs_handles_partial_explicit_args(add_tool):
318
  arguments={"new_x": 3, "old_y": 7, "some_other_param": "test"}
319
  )
320
  assert result.content[0].text == "10" # type: ignore[attr-defined]
321
- assert result.structured_content == {"value": 10}
322
 
323
 
324
  async def test_fn_with_kwargs_mixed_mapped_and_unmapped_args(add_tool):
@@ -337,7 +337,7 @@ async def test_fn_with_kwargs_mixed_mapped_and_unmapped_args(add_tool):
337
  ) # only map 'a'
338
  result = await new_tool.run(arguments={"new_x": 1, "old_y": 5})
339
  assert result.content[0].text == "6" # type: ignore[attr-defined]
340
- assert result.structured_content == {"value": 6}
341
 
342
 
343
  async def test_fn_with_kwargs_dropped_args_not_in_kwargs(add_tool):
 
53
  )
54
  result = await new_tool.run(arguments={"new_x": 1})
55
  # The parent tool returns int which gets wrapped as structured output
56
+ assert result.structured_content == {"result": 11}
57
 
58
 
59
  async def test_tool_defaults_are_maintained_on_mapped_args(add_tool):
 
62
  )
63
  result = await new_tool.run(arguments={"old_x": 1})
64
  # The parent tool returns int which gets wrapped as structured output
65
+ assert result.structured_content == {"result": 11}
66
 
67
 
68
  def test_tool_change_arg_name(add_tool):
 
89
  )
90
  assert sorted(new_tool.parameters["properties"]) == ["old_x"]
91
  result = await new_tool.run(arguments={"old_x": 1})
92
+ assert result.structured_content == {"result": 11}
93
 
94
 
95
  async def test_dropped_args_error_if_provided(add_tool):
 
111
  assert sorted(new_tool.parameters["properties"]) == ["old_x"]
112
  # Should pass old_x=5 and old_y=20 to parent
113
  result = await new_tool.run(arguments={"old_x": 5})
114
+ assert result.structured_content == {"result": 25}
115
 
116
 
117
  async def test_hidden_arg_without_default_uses_parent_default(add_tool):
 
124
  # Should pass old_x=3 and let parent use its default old_y=10
125
  result = await new_tool.run(arguments={"old_x": 3})
126
  assert result.content[0].text == "13" # type: ignore[attr-defined]
127
+ assert result.structured_content == {"result": 13}
128
 
129
 
130
  async def test_mixed_hidden_args_with_custom_function(add_tool):
 
150
  # Should pass visible_x=7 as old_x=7 and old_y=25 to parent
151
  result = await new_tool.run(arguments={"visible_x": 7})
152
  assert result.content[0].text == "32" # type: ignore[attr-defined]
153
+ assert result.structured_content == {"result": 32}
154
 
155
 
156
  async def test_hide_required_param_without_default_raises_error():
 
188
  assert sorted(new_tool.parameters["properties"]) == ["optional_param"]
189
  # Should pass required_param=5 and optional_param=20 to parent
190
  result = await new_tool.run(arguments={"optional_param": 20})
191
+ assert result.structured_content == {"result": 25}
192
 
193
 
194
  async def test_forward_with_argument_mapping(add_tool):
 
208
 
209
  result = await new_tool.run(arguments={"new_x": 2, "new_y": 3})
210
  assert result.content[0].text == "5" # type: ignore[attr-defined]
211
+ assert result.structured_content == {"result": 5}
212
 
213
 
214
  async def test_forward_with_incorrect_args_raises_error(add_tool):
 
249
 
250
  result = await new_tool.run(arguments={"new_x": 2, "new_y": 3})
251
  assert result.content[0].text == "5" # type: ignore[attr-defined]
252
+ assert result.structured_content == {"result": 5}
253
 
254
 
255
  async def test_custom_fn_with_kwargs_and_no_transform_args(add_tool):
 
260
  new_tool = Tool.from_tool(add_tool, transform_fn=custom_fn)
261
  result = await new_tool.run(arguments={"extra": 1, "old_x": 2, "old_y": 3})
262
  assert result.content[0].text == "6" # type: ignore[attr-defined]
263
+ assert result.structured_content == {"result": 6}
264
  assert new_tool.parameters["required"] == IsList(
265
  "extra", "old_x", check_order=False
266
  )
 
278
  new_tool = Tool.from_tool(add_tool, transform_fn=custom_fn)
279
  result = await new_tool.run(arguments={"new_y": 2, "old_y": 3})
280
  assert result.content[0].text == "5" # type: ignore[attr-defined]
281
+ assert result.structured_content == {"result": 5}
282
 
283
 
284
  async def test_fn_with_kwargs_receives_transformed_arg_names(add_tool):
 
297
  )
298
  result = await new_tool.run(arguments={"new_x": 2, "old_y": 3})
299
  assert result.content[0].text == "5" # type: ignore[attr-defined]
300
+ assert result.structured_content == {"result": 5}
301
 
302
 
303
  async def test_fn_with_kwargs_handles_partial_explicit_args(add_tool):
 
318
  arguments={"new_x": 3, "old_y": 7, "some_other_param": "test"}
319
  )
320
  assert result.content[0].text == "10" # type: ignore[attr-defined]
321
+ assert result.structured_content == {"result": 10}
322
 
323
 
324
  async def test_fn_with_kwargs_mixed_mapped_and_unmapped_args(add_tool):
 
337
  ) # only map 'a'
338
  result = await new_tool.run(arguments={"new_x": 1, "old_y": 5})
339
  assert result.content[0].text == "6" # type: ignore[attr-defined]
340
+ assert result.structured_content == {"result": 6}
341
 
342
 
343
  async def test_fn_with_kwargs_dropped_args_not_in_kwargs(add_tool):