mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-28 02:10:38 +02:00
Fix breaking change: restore output_schema=False compatibility (#1482)
This commit is contained in:
parent
3275b3627d
commit
905a7872c8
8 changed files with 242 additions and 66 deletions
|
|
@ -73,7 +73,10 @@
|
|||
{
|
||||
"group": "Essentials",
|
||||
"icon": "cube",
|
||||
"pages": ["servers/server", "deployment/running-server"]
|
||||
"pages": [
|
||||
"servers/server",
|
||||
"deployment/running-server"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Core Components",
|
||||
|
|
@ -116,7 +119,10 @@
|
|||
{
|
||||
"group": "Essentials",
|
||||
"icon": "cube",
|
||||
"pages": ["clients/client", "clients/transports"]
|
||||
"pages": [
|
||||
"clients/client",
|
||||
"clients/transports"
|
||||
]
|
||||
},
|
||||
{
|
||||
"group": "Core Operations",
|
||||
|
|
@ -142,7 +148,10 @@
|
|||
{
|
||||
"group": "Authentication",
|
||||
"icon": "user-shield",
|
||||
"pages": ["clients/auth/oauth", "clients/auth/bearer"]
|
||||
"pages": [
|
||||
"clients/auth/oauth",
|
||||
"clients/auth/bearer"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -188,12 +197,17 @@
|
|||
},
|
||||
{
|
||||
"anchor": "What's New",
|
||||
"pages": ["updates", "changelog"]
|
||||
"pages": [
|
||||
"updates",
|
||||
"changelog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"anchor": "Community",
|
||||
"icon": "users",
|
||||
"pages": ["community/showcase"]
|
||||
"pages": [
|
||||
"community/showcase"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ sidebarTitle: transports
|
|||
|
||||
## Functions
|
||||
|
||||
### `infer_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L904" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `infer_transport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L903" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
infer_transport(transport: ClientTransport | FastMCP | FastMCP1Server | AnyUrl | Path | MCPConfig | dict[str, Any] | str) -> ClientTransport
|
||||
|
|
@ -161,61 +161,61 @@ transports like Python, Node, Uvx, etc.
|
|||
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
|
||||
```
|
||||
|
||||
#### `connect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L357" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `connect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L356" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
connect(self, **session_kwargs: Unpack[SessionKwargs]) -> ClientSession | None
|
||||
```
|
||||
|
||||
#### `disconnect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L408" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `disconnect` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L407" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
disconnect(self)
|
||||
```
|
||||
|
||||
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L423" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `close` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L422" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
close(self)
|
||||
```
|
||||
|
||||
### `PythonStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L432" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `PythonStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L431" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running Python scripts.
|
||||
|
||||
|
||||
### `FastMCPStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L478" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `FastMCPStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L477" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running FastMCP servers using the FastMCP CLI.
|
||||
|
||||
|
||||
### `NodeStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L505" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `NodeStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L504" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running Node.js scripts.
|
||||
|
||||
|
||||
### `UvStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L547" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `UvStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L546" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running commands via the uv tool.
|
||||
|
||||
|
||||
### `UvxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L604" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `UvxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L603" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running commands via the uvx tool.
|
||||
|
||||
|
||||
### `NpxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L668" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `NpxStdioTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L667" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for running commands via the npx tool.
|
||||
|
||||
|
||||
### `FastMCPTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L730" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `FastMCPTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L729" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
In-memory transport for FastMCP servers.
|
||||
|
|
@ -228,13 +228,13 @@ tests or scenarios where client and server run in the same runtime.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L749" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L748" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
|
||||
```
|
||||
|
||||
### `MCPConfigTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L784" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `MCPConfigTransport` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L783" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Transport for connecting to one or more MCP servers defined in an MCPConfig.
|
||||
|
|
@ -287,7 +287,7 @@ async with client:
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L856" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `connect_session` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/client/transports.py#L855" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
connect_session(self, **session_kwargs: Unpack[SessionKwargs]) -> AsyncIterator[ClientSession]
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ sidebarTitle: tool
|
|||
|
||||
## Functions
|
||||
|
||||
### `default_serializer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L55" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `default_serializer` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L58" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
default_serializer(data: Any) -> str
|
||||
|
|
@ -15,17 +15,17 @@ default_serializer(data: Any) -> str
|
|||
|
||||
## Classes
|
||||
|
||||
### `ToolResult` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L59" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ToolResult` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L62" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
**Methods:**
|
||||
|
||||
#### `to_mcp_result` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L90" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `to_mcp_result` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L93" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
to_mcp_result(self) -> list[ContentBlock] | tuple[list[ContentBlock], dict[str, Any]]
|
||||
```
|
||||
|
||||
### `Tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L98" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `Tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L101" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Internal tool registration info.
|
||||
|
|
@ -33,34 +33,34 @@ Internal tool registration info.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L116" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `enable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L119" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
enable(self) -> None
|
||||
```
|
||||
|
||||
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L124" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `disable` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L127" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
disable(self) -> None
|
||||
```
|
||||
|
||||
#### `to_mcp_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L132" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `to_mcp_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L135" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
to_mcp_tool(self, **overrides: Any) -> MCPTool
|
||||
```
|
||||
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L157" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L160" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT = NotSet, serializer: Callable[[Any], str] | None = None, meta: dict[str, Any] | None = None, enabled: bool | None = None) -> FunctionTool
|
||||
from_function(fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet, serializer: Callable[[Any], str] | None = None, meta: dict[str, Any] | None = None, enabled: bool | None = None) -> FunctionTool
|
||||
```
|
||||
|
||||
Create a Tool from a function.
|
||||
|
||||
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L185" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L188" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
run(self, arguments: dict[str, Any]) -> ToolResult
|
||||
|
|
@ -75,26 +75,26 @@ implemented by subclasses.
|
|||
(list of ContentBlocks, dict of structured output).
|
||||
|
||||
|
||||
#### `from_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L198" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `from_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L201" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
from_tool(cls, tool: Tool) -> TransformedTool
|
||||
```
|
||||
|
||||
### `FunctionTool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L232" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `FunctionTool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L235" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
**Methods:**
|
||||
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L236" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L239" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT = NotSet, serializer: Callable[[Any], str] | None = None, meta: dict[str, Any] | None = None, enabled: bool | None = None) -> FunctionTool
|
||||
from_function(cls, fn: Callable[..., Any], name: str | None = None, title: str | None = None, description: str | None = None, tags: set[str] | None = None, annotations: ToolAnnotations | None = None, exclude_args: list[str] | None = None, output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet, serializer: Callable[[Any], str] | None = None, meta: dict[str, Any] | None = None, enabled: bool | None = None) -> FunctionTool
|
||||
```
|
||||
|
||||
Create a Tool from a function.
|
||||
|
||||
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L284" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L297" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
run(self, arguments: dict[str, Any]) -> ToolResult
|
||||
|
|
@ -103,11 +103,11 @@ run(self, arguments: dict[str, Any]) -> ToolResult
|
|||
Run the tool with arguments.
|
||||
|
||||
|
||||
### `ParsedFunction` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L330" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ParsedFunction` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L343" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
**Methods:**
|
||||
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L338" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `from_function` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool.py#L351" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
from_function(cls, fn: Callable[..., Any], exclude_args: list[str] | None = None, validate: bool = True, wrap_non_object_output_schema: bool = True) -> ParsedFunction
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ sidebarTitle: tool_transform
|
|||
|
||||
## Functions
|
||||
|
||||
### `forward` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L35" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `forward` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L37" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
forward(**kwargs) -> ToolResult
|
||||
|
|
@ -36,7 +36,7 @@ tool has args `a` and `b`, and an `transform_args` was provided that maps `x` to
|
|||
- `TypeError`: If provided arguments don't match the transformed schema.
|
||||
|
||||
|
||||
### `forward_raw` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L65" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `forward_raw` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L67" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
forward_raw(**kwargs) -> ToolResult
|
||||
|
|
@ -62,7 +62,7 @@ y=2)` will call the parent tool with `x=1` and `y=2`.
|
|||
- `RuntimeError`: If called outside a transformed tool context.
|
||||
|
||||
|
||||
### `apply_transformations_to_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L904" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `apply_transformations_to_tools` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L915" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
apply_transformations_to_tools(tools: dict[str, Tool], transformations: dict[str, ToolTransformConfig]) -> dict[str, Tool]
|
||||
|
|
@ -75,7 +75,7 @@ are left unchanged.
|
|||
|
||||
## Classes
|
||||
|
||||
### `ArgTransform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L92" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ArgTransform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L94" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Configuration for transforming a parent tool's argument.
|
||||
|
|
@ -137,7 +137,7 @@ ArgTransform(name="new_name", description="New desc", default=None, type=int)
|
|||
```
|
||||
|
||||
|
||||
### `ArgTransformConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L206" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ArgTransformConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L208" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
A model for requesting a single argument transform.
|
||||
|
|
@ -145,7 +145,7 @@ A model for requesting a single argument transform.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `to_arg_transform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L224" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `to_arg_transform` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L226" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
to_arg_transform(self) -> ArgTransform
|
||||
|
|
@ -154,7 +154,7 @@ to_arg_transform(self) -> ArgTransform
|
|||
Convert the argument transform to a FastMCP argument transform.
|
||||
|
||||
|
||||
### `TransformedTool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L230" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `TransformedTool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L232" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
A tool that is transformed from another tool.
|
||||
|
|
@ -171,7 +171,7 @@ inherited from the parent tool but can be overridden or disabled.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L257" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `run` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L259" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
run(self, arguments: dict[str, Any]) -> ToolResult
|
||||
|
|
@ -190,10 +190,10 @@ functions.
|
|||
- ToolResult object containing content and optional structured output.
|
||||
|
||||
|
||||
#### `from_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L362" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `from_tool` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L364" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
from_tool(cls, tool: Tool, name: 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, annotations: ToolAnnotations | None | NotSetT = NotSet, output_schema: dict[str, Any] | None | NotSetT = NotSet, serializer: Callable[[Any], str] | None | NotSetT = NotSet, meta: dict[str, Any] | None | NotSetT = NotSet, enabled: bool | None = None) -> TransformedTool
|
||||
from_tool(cls, tool: Tool, name: 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, annotations: ToolAnnotations | None | NotSetT = NotSet, output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet, serializer: Callable[[Any], str] | None | NotSetT = NotSet, meta: dict[str, Any] | None | NotSetT = NotSet, enabled: bool | None = None) -> TransformedTool
|
||||
```
|
||||
|
||||
Create a transformed tool from a parent tool.
|
||||
|
|
@ -272,7 +272,7 @@ async def custom_output(**kwargs) -> ToolResult:
|
|||
```
|
||||
|
||||
|
||||
### `ToolTransformConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L858" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
### `ToolTransformConfig` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L869" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
|
||||
Provides a way to transform a tool.
|
||||
|
|
@ -280,7 +280,7 @@ Provides a way to transform a tool.
|
|||
|
||||
**Methods:**
|
||||
|
||||
#### `apply` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L890" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
#### `apply` <sup><a href="https://github.com/jlowin/fastmcp/blob/main/src/fastmcp/tools/tool_transform.py#L901" target="_blank"><Icon icon="github" style="width: 14px; height: 14px;" /></a></sup>
|
||||
|
||||
```python
|
||||
apply(self, tool: Tool) -> TransformedTool
|
||||
|
|
|
|||
|
|
@ -346,8 +346,7 @@ class StdioTransport(ClientTransport):
|
|||
) -> AsyncIterator[ClientSession]:
|
||||
try:
|
||||
await self.connect(**session_kwargs)
|
||||
assert self._session is not None
|
||||
yield self._session
|
||||
yield cast(ClientSession, self._session)
|
||||
finally:
|
||||
if not self.keep_alive:
|
||||
await self.disconnect()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import warnings
|
||||
from collections.abc import Callable
|
||||
from dataclasses import dataclass
|
||||
from typing import (
|
||||
|
|
@ -8,6 +9,7 @@ from typing import (
|
|||
Annotated,
|
||||
Any,
|
||||
Generic,
|
||||
Literal,
|
||||
TypeVar,
|
||||
get_type_hints,
|
||||
)
|
||||
|
|
@ -18,6 +20,7 @@ from mcp.types import ContentBlock, TextContent, ToolAnnotations
|
|||
from mcp.types import Tool as MCPTool
|
||||
from pydantic import Field, PydanticSchemaGenerationError
|
||||
|
||||
import fastmcp
|
||||
from fastmcp.server.dependencies import get_context
|
||||
from fastmcp.utilities.components import FastMCPComponent
|
||||
from fastmcp.utilities.json_schema import compress_schema
|
||||
|
|
@ -162,7 +165,7 @@ class Tool(FastMCPComponent):
|
|||
tags: set[str] | None = None,
|
||||
annotations: ToolAnnotations | None = None,
|
||||
exclude_args: list[str] | None = None,
|
||||
output_schema: dict[str, Any] | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet,
|
||||
serializer: Callable[[Any], str] | None = None,
|
||||
meta: dict[str, Any] | None = None,
|
||||
enabled: bool | None = None,
|
||||
|
|
@ -204,7 +207,7 @@ class Tool(FastMCPComponent):
|
|||
description: str | None | NotSetT = NotSet,
|
||||
tags: set[str] | None = None,
|
||||
annotations: ToolAnnotations | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet,
|
||||
serializer: Callable[[Any], str] | None = None,
|
||||
meta: dict[str, Any] | None | NotSetT = NotSet,
|
||||
transform_args: dict[str, ArgTransform] | None = None,
|
||||
|
|
@ -242,7 +245,7 @@ class FunctionTool(Tool):
|
|||
tags: set[str] | None = None,
|
||||
annotations: ToolAnnotations | None = None,
|
||||
exclude_args: list[str] | None = None,
|
||||
output_schema: dict[str, Any] | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet,
|
||||
serializer: Callable[[Any], str] | None = None,
|
||||
meta: dict[str, Any] | None = None,
|
||||
enabled: bool | None = None,
|
||||
|
|
@ -255,16 +258,26 @@ class FunctionTool(Tool):
|
|||
raise ValueError("You must provide a name for lambda functions")
|
||||
|
||||
if isinstance(output_schema, NotSetT):
|
||||
output_schema = parsed_fn.output_schema
|
||||
final_output_schema = parsed_fn.output_schema
|
||||
elif output_schema is False:
|
||||
output_schema = None
|
||||
# Handle False as deprecated synonym for None (deprecated in 2.11.4)
|
||||
if fastmcp.settings.deprecation_warnings:
|
||||
warnings.warn(
|
||||
"Passing output_schema=False is deprecated. Use output_schema=None instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
final_output_schema = None
|
||||
else:
|
||||
# At this point output_schema is not NotSetT and not False, so it must be dict | None
|
||||
final_output_schema = output_schema
|
||||
# Note: explicit schemas (dict) are used as-is without auto-wrapping
|
||||
|
||||
# Validate that explicit schemas are object type for structured content
|
||||
if output_schema is not None and isinstance(output_schema, dict):
|
||||
if output_schema.get("type") != "object":
|
||||
if final_output_schema is not None and isinstance(final_output_schema, dict):
|
||||
if final_output_schema.get("type") != "object":
|
||||
raise ValueError(
|
||||
f'Output schemas must have "type" set to "object" due to MCP spec limitations. Received: {output_schema!r}'
|
||||
f'Output schemas must have "type" set to "object" due to MCP spec limitations. Received: {final_output_schema!r}'
|
||||
)
|
||||
|
||||
return cls(
|
||||
|
|
@ -273,7 +286,7 @@ class FunctionTool(Tool):
|
|||
title=title,
|
||||
description=description or parsed_fn.description,
|
||||
parameters=parsed_fn.input_schema,
|
||||
output_schema=output_schema,
|
||||
output_schema=final_output_schema,
|
||||
annotations=annotations,
|
||||
tags=tags or set(),
|
||||
serializer=serializer,
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
from __future__ import annotations
|
||||
|
||||
import inspect
|
||||
import warnings
|
||||
from collections.abc import Callable
|
||||
from contextvars import ContextVar
|
||||
from dataclasses import dataclass
|
||||
from typing import Annotated, Any, Literal
|
||||
from typing import Annotated, Any, Literal, cast
|
||||
|
||||
import pydantic_core
|
||||
from mcp.types import ToolAnnotations
|
||||
|
|
@ -12,6 +13,7 @@ from pydantic import ConfigDict
|
|||
from pydantic.fields import Field
|
||||
from pydantic.functional_validators import BeforeValidator
|
||||
|
||||
import fastmcp
|
||||
from fastmcp.tools.tool import ParsedFunction, Tool, ToolResult, _convert_to_content
|
||||
from fastmcp.utilities.components import _convert_set_default_none
|
||||
from fastmcp.utilities.json_schema import compress_schema
|
||||
|
|
@ -369,7 +371,7 @@ class TransformedTool(Tool):
|
|||
transform_fn: Callable[..., Any] | None = None,
|
||||
transform_args: dict[str, ArgTransform] | None = None,
|
||||
annotations: ToolAnnotations | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT = NotSet,
|
||||
output_schema: dict[str, Any] | None | NotSetT | Literal[False] = NotSet,
|
||||
serializer: Callable[[Any], str] | None | NotSetT = NotSet,
|
||||
meta: dict[str, Any] | None | NotSetT = NotSet,
|
||||
enabled: bool | None = None,
|
||||
|
|
@ -471,8 +473,8 @@ class TransformedTool(Tool):
|
|||
if output_schema is NotSet:
|
||||
# Use smart fallback: try custom function, then parent
|
||||
if transform_fn is not None:
|
||||
assert parsed_fn is not None
|
||||
final_output_schema = parsed_fn.output_schema
|
||||
# parsed fn is not none here
|
||||
final_output_schema = cast(ParsedFunction, parsed_fn).output_schema
|
||||
if final_output_schema is None:
|
||||
# Check if function returns ToolResult - if so, don't fall back to parent
|
||||
return_annotation = inspect.signature(
|
||||
|
|
@ -484,16 +486,25 @@ class TransformedTool(Tool):
|
|||
final_output_schema = tool.output_schema
|
||||
else:
|
||||
final_output_schema = tool.output_schema
|
||||
elif output_schema is False:
|
||||
# Handle False as deprecated synonym for None (deprecated in 2.11.4)
|
||||
if fastmcp.settings.deprecation_warnings:
|
||||
warnings.warn(
|
||||
"Passing output_schema=False is deprecated. Use output_schema=None instead.",
|
||||
DeprecationWarning,
|
||||
stacklevel=2,
|
||||
)
|
||||
final_output_schema = None
|
||||
else:
|
||||
assert isinstance(output_schema, dict | None)
|
||||
final_output_schema = output_schema
|
||||
final_output_schema = cast(dict | None, output_schema)
|
||||
|
||||
if transform_fn is None:
|
||||
# User wants pure transformation - use forwarding_fn as the main function
|
||||
final_fn = forwarding_fn
|
||||
final_schema = schema
|
||||
else:
|
||||
assert parsed_fn is not None
|
||||
# parsed fn is not none here
|
||||
parsed_fn = cast(ParsedFunction, parsed_fn)
|
||||
# User provided custom function - merge schemas
|
||||
final_fn = transform_fn
|
||||
|
||||
|
|
|
|||
139
tests/deprecated/test_output_schema_false.py
Normal file
139
tests/deprecated/test_output_schema_false.py
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
"""Test deprecated output_schema=False behavior (deprecated in 2.11.4)."""
|
||||
|
||||
import warnings
|
||||
|
||||
import pytest
|
||||
|
||||
from fastmcp import FastMCP
|
||||
from fastmcp.tools import Tool
|
||||
|
||||
|
||||
class TestDeprecatedOutputSchemaFalse:
|
||||
"""Test that output_schema=False is deprecated but still works."""
|
||||
|
||||
async def test_tool_decorator_output_schema_false_deprecated(self):
|
||||
"""Test that @mcp.tool(output_schema=False) shows deprecation warning."""
|
||||
mcp = FastMCP()
|
||||
|
||||
with pytest.warns(
|
||||
DeprecationWarning, match="output_schema=False is deprecated"
|
||||
):
|
||||
|
||||
@mcp.tool(output_schema=False) # type: ignore[arg-type]
|
||||
def simple_tool() -> int:
|
||||
"""A simple tool."""
|
||||
return 42
|
||||
|
||||
# Verify the tool was created with None as output_schema
|
||||
tool = mcp._tool_manager._tools["simple_tool"]
|
||||
assert tool.output_schema is None
|
||||
|
||||
async def test_tool_from_function_output_schema_false_deprecated(self):
|
||||
"""Test that Tool.from_function(output_schema=False) shows deprecation warning."""
|
||||
|
||||
def my_function() -> str:
|
||||
"""A simple function."""
|
||||
return "hello"
|
||||
|
||||
with pytest.warns(
|
||||
DeprecationWarning, match="output_schema=False is deprecated"
|
||||
):
|
||||
tool = Tool.from_function(my_function, output_schema=False) # type: ignore[arg-type]
|
||||
|
||||
# Verify the tool was created with None as output_schema
|
||||
assert tool.output_schema is None
|
||||
|
||||
async def test_tool_from_tool_output_schema_false_deprecated(self):
|
||||
"""Test that Tool.from_tool(output_schema=False) shows deprecation warning."""
|
||||
|
||||
# Create a parent tool
|
||||
def parent_function() -> dict[str, str]:
|
||||
"""A parent function."""
|
||||
return {"status": "ok"}
|
||||
|
||||
parent_tool = Tool.from_function(parent_function)
|
||||
|
||||
with pytest.warns(
|
||||
DeprecationWarning, match="output_schema=False is deprecated"
|
||||
):
|
||||
transformed_tool = Tool.from_tool(parent_tool, output_schema=False) # type: ignore[arg-type]
|
||||
|
||||
# Verify the tool was created with None as output_schema
|
||||
assert transformed_tool.output_schema is None
|
||||
|
||||
async def test_output_schema_false_functionality_preserved(self):
|
||||
"""Test that output_schema=False still works functionally like output_schema=None."""
|
||||
mcp = FastMCP()
|
||||
|
||||
# Create two tools - one with False, one with None
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
|
||||
@mcp.tool(output_schema=False) # type: ignore[arg-type]
|
||||
def tool_with_false() -> dict[str, str]:
|
||||
"""Tool with output_schema=False."""
|
||||
return {"result": "false"}
|
||||
|
||||
@mcp.tool(output_schema=None)
|
||||
def tool_with_none() -> dict[str, str]:
|
||||
"""Tool with output_schema=None."""
|
||||
return {"result": "none"}
|
||||
|
||||
# Both should have None as output_schema
|
||||
assert mcp._tool_manager._tools["tool_with_false"].output_schema is None
|
||||
assert mcp._tool_manager._tools["tool_with_none"].output_schema is None
|
||||
|
||||
# Both should work the same way
|
||||
result_false = await mcp._tool_manager._tools["tool_with_false"].run({})
|
||||
result_none = await mcp._tool_manager._tools["tool_with_none"].run({})
|
||||
|
||||
# Both should return structured content for dict-like objects
|
||||
assert result_false.structured_content == {"result": "false"}
|
||||
assert result_none.structured_content == {"result": "none"}
|
||||
|
||||
async def test_output_schema_false_with_scalar_return(self):
|
||||
"""Test that output_schema=False works with scalar returns (no structured content)."""
|
||||
mcp = FastMCP()
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
|
||||
@mcp.tool(output_schema=False) # type: ignore[arg-type]
|
||||
def scalar_tool() -> int:
|
||||
"""Tool returning a scalar."""
|
||||
return 42
|
||||
|
||||
tool = mcp._tool_manager._tools["scalar_tool"]
|
||||
assert tool.output_schema is None
|
||||
|
||||
result = await tool.run({})
|
||||
# Scalar values don't produce structured content
|
||||
assert result.structured_content is None
|
||||
assert len(result.content) == 1
|
||||
assert result.content[0].text == "42" # type: ignore[attr-defined]
|
||||
|
||||
async def test_transform_with_output_schema_false(self):
|
||||
"""Test that transformation with output_schema=False still works."""
|
||||
|
||||
# Create a parent tool
|
||||
def parent_function(x: int) -> dict[str, int]:
|
||||
"""A parent function."""
|
||||
return {"value": x * 2}
|
||||
|
||||
parent_tool = Tool.from_function(parent_function)
|
||||
|
||||
with warnings.catch_warnings():
|
||||
warnings.simplefilter("ignore", DeprecationWarning)
|
||||
|
||||
# Transform with output_schema=False
|
||||
transformed = Tool.from_tool(
|
||||
parent_tool,
|
||||
name="doubled",
|
||||
output_schema=False, # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
assert transformed.output_schema is None
|
||||
|
||||
# Tool should still work
|
||||
result = await transformed.run({"x": 5})
|
||||
assert result.structured_content == {"value": 10}
|
||||
Loading…
Add table
Add a link
Reference in a new issue