mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-21 04:54:17 +02:00
Fix title field preservation in tool transformations
Add title parameter to Tool.from_tool() and TransformedTool.from_tool() to properly inherit or override title field when transforming tools. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
45228c5cfa
commit
9326cb91db
3 changed files with 98 additions and 4 deletions
|
|
@ -185,8 +185,9 @@ class Tool(FastMCPComponent):
|
|||
tool: Tool,
|
||||
transform_fn: Callable[..., Any] | None = None,
|
||||
name: str | None = None,
|
||||
title: str | None | NotSetT = NotSet,
|
||||
transform_args: dict[str, ArgTransform] | None = None,
|
||||
description: str | None = None,
|
||||
description: str | None | NotSetT = NotSet,
|
||||
tags: set[str] | None = None,
|
||||
annotations: ToolAnnotations | None = None,
|
||||
output_schema: dict[str, Any] | None | Literal[False] = None,
|
||||
|
|
@ -199,6 +200,7 @@ class Tool(FastMCPComponent):
|
|||
tool=tool,
|
||||
transform_fn=transform_fn,
|
||||
name=name,
|
||||
title=title,
|
||||
transform_args=transform_args,
|
||||
description=description,
|
||||
tags=tags,
|
||||
|
|
|
|||
|
|
@ -325,7 +325,8 @@ class TransformedTool(Tool):
|
|||
cls,
|
||||
tool: Tool,
|
||||
name: str | None = None,
|
||||
description: str | None = None,
|
||||
title: str | None | NotSetT = NotSet,
|
||||
description: str | None | NotSetT = NotSet,
|
||||
tags: set[str] | None = None,
|
||||
transform_fn: Callable[..., Any] | None = None,
|
||||
transform_args: dict[str, ArgTransform] | None = None,
|
||||
|
|
@ -342,6 +343,7 @@ class TransformedTool(Tool):
|
|||
to call the parent tool. Functions with **kwargs receive transformed
|
||||
argument names.
|
||||
name: New name for the tool. Defaults to parent tool's name.
|
||||
title: New title for the tool. Defaults to parent tool's title.
|
||||
transform_args: Optional transformations for parent tool arguments.
|
||||
Only specified arguments are transformed, others pass through unchanged:
|
||||
- Simple rename (str)
|
||||
|
|
@ -506,13 +508,18 @@ class TransformedTool(Tool):
|
|||
f"{', '.join(sorted(duplicates))}"
|
||||
)
|
||||
|
||||
final_description = description if description is not None else tool.description
|
||||
final_name = name or tool.name
|
||||
final_description = (
|
||||
description if not isinstance(description, NotSetT) else tool.description
|
||||
)
|
||||
final_title = title if not isinstance(title, NotSetT) else tool.title
|
||||
|
||||
transformed_tool = cls(
|
||||
fn=final_fn,
|
||||
forwarding_fn=forwarding_fn,
|
||||
parent_tool=tool,
|
||||
name=name or tool.name,
|
||||
name=final_name,
|
||||
title=final_title,
|
||||
description=final_description,
|
||||
parameters=final_schema,
|
||||
output_schema=final_output_schema,
|
||||
|
|
|
|||
|
|
@ -1316,3 +1316,88 @@ class TestTransformToolOutputSchema:
|
|||
# Should use ToolResult content directly
|
||||
assert result.content[0].text == "Direct: 6" # type: ignore[attr-defined]
|
||||
assert result.structured_content == {"direct_value": 6, "doubled": 12}
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_tool():
|
||||
"""Sample tool for testing transformations."""
|
||||
|
||||
def sample_func(x: int) -> str:
|
||||
return f"Result: {x}"
|
||||
|
||||
return Tool.from_function(
|
||||
sample_func,
|
||||
name="sample_tool",
|
||||
title="Original Tool Title",
|
||||
description="Original description",
|
||||
)
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def sample_tool_no_title():
|
||||
"""Sample tool without title for testing."""
|
||||
|
||||
def sample_func(x: int) -> str:
|
||||
return f"Result: {x}"
|
||||
|
||||
return Tool.from_function(sample_func, name="no_title_tool")
|
||||
|
||||
|
||||
def test_transform_inherits_title(sample_tool):
|
||||
"""Test that transformed tools inherit title when none specified."""
|
||||
transformed = Tool.from_tool(sample_tool)
|
||||
assert transformed.title == "Original Tool Title"
|
||||
|
||||
|
||||
def test_transform_overrides_title(sample_tool):
|
||||
"""Test that transformed tools can override title."""
|
||||
transformed = Tool.from_tool(sample_tool, title="New Tool Title")
|
||||
assert transformed.title == "New Tool Title"
|
||||
|
||||
|
||||
def test_transform_sets_title_to_none(sample_tool):
|
||||
"""Test that transformed tools can explicitly set title to None."""
|
||||
transformed = Tool.from_tool(sample_tool, title=None)
|
||||
assert transformed.title is None
|
||||
|
||||
|
||||
def test_transform_inherits_none_title(sample_tool_no_title):
|
||||
"""Test that transformed tools inherit None title."""
|
||||
transformed = Tool.from_tool(sample_tool_no_title)
|
||||
assert transformed.title is None
|
||||
|
||||
|
||||
def test_transform_adds_title_to_none(sample_tool_no_title):
|
||||
"""Test that transformed tools can add title when parent has None."""
|
||||
transformed = Tool.from_tool(sample_tool_no_title, title="Added Title")
|
||||
assert transformed.title == "Added Title"
|
||||
|
||||
|
||||
def test_transform_inherits_description(sample_tool):
|
||||
"""Test that transformed tools inherit description when none specified."""
|
||||
transformed = Tool.from_tool(sample_tool)
|
||||
assert transformed.description == "Original description"
|
||||
|
||||
|
||||
def test_transform_overrides_description(sample_tool):
|
||||
"""Test that transformed tools can override description."""
|
||||
transformed = Tool.from_tool(sample_tool, description="New description")
|
||||
assert transformed.description == "New description"
|
||||
|
||||
|
||||
def test_transform_sets_description_to_none(sample_tool):
|
||||
"""Test that transformed tools can explicitly set description to None."""
|
||||
transformed = Tool.from_tool(sample_tool, description=None)
|
||||
assert transformed.description is None
|
||||
|
||||
|
||||
def test_transform_inherits_none_description(sample_tool_no_title):
|
||||
"""Test that transformed tools inherit None description."""
|
||||
transformed = Tool.from_tool(sample_tool_no_title)
|
||||
assert transformed.description is None
|
||||
|
||||
|
||||
def test_transform_adds_description_to_none(sample_tool_no_title):
|
||||
"""Test that transformed tools can add description when parent has None."""
|
||||
transformed = Tool.from_tool(sample_tool_no_title, description="Added description")
|
||||
assert transformed.description == "Added description"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue