Always emit a tool title, derived from name when unset (#4694)

* Always emit a tool title, derived from name when unset

Some MCP clients (e.g. ChatGPT) drop tools with no `title` instead of
falling back to `name` for display as the spec allows. Deriving a
default title in Tool.to_mcp_tool() fixes this for every tool built on
top of it, including the search-transform, code-mode, and session
proxy tools that never set one explicitly.

Fixes #4414

* Derive fallback title from the overridden name, document it

Addresses Codex review on #4694.

* Resolve title precedence from effective overrides

* Normalize mapping annotations before deriving the title
This commit is contained in:
Jeremiah Lowin 2026-07-28 17:30:20 -04:00 committed by GitHub
commit baced6281c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 84 additions and 11 deletions

View file

@ -74,7 +74,7 @@ def search_products_implementation(query: str, category: str | None = None) -> l
</ParamField>
<ParamField body="title" type="str | None">
A human-readable display title for the tool. If omitted, FastMCP falls back to `annotations.title` when present.
A human-readable display title for the tool. If omitted, FastMCP falls back to `annotations.title` when present, then to a title derived from the tool's name (e.g. `find_products` becomes "Find Products") — some MCP clients drop tools that have no title at all.
</ParamField>
<ParamField body="tags" type="set[str] | None">