From 8a61b16cdadf4efea139cee6d4aa8417bfcbb849 Mon Sep 17 00:00:00 2001 From: Jeremiah Lowin <153965+jlowin@users.noreply.github.com> Date: Sun, 1 Jun 2025 18:14:57 -0400 Subject: [PATCH] Document exclude_args --- docs/docs.json | 15 +++++++++++---- docs/servers/tools.mdx | 21 ++++++++++++++++++++- src/fastmcp/tools/tool.py | 9 +++------ 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/docs/docs.json b/docs/docs.json index 14facc32c..884017db4 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -46,10 +46,17 @@ "group": "Servers", "pages": [ "servers/fastmcp", - "servers/tools", - "servers/resources", - "servers/prompts", - "servers/context", + { + "group": "Core Components", + "hidden": false, + "icon": "toolbox", + "pages": [ + "servers/tools", + "servers/resources", + "servers/prompts", + "servers/context" + ] + }, "servers/openapi", "servers/proxy", "servers/composition" diff --git a/docs/servers/tools.mdx b/docs/servers/tools.mdx index 879ceab02..365a8611d 100644 --- a/docs/servers/tools.mdx +++ b/docs/servers/tools.mdx @@ -158,7 +158,7 @@ While FastMCP infers the name and description from your function, you can overri @mcp.tool( name="find_products", # Custom tool name for the LLM description="Search the product catalog with optional category filtering.", # Custom description - tags={"catalog", "search"} # Optional tags for organization/filtering + tags={"catalog", "search"}, # Optional tags for organization/filtering ) def search_products_implementation(query: str, category: str | None = None) -> list[dict]: """Internal function description (ignored if description is provided above).""" @@ -172,6 +172,25 @@ def search_products_implementation(query: str, category: str | None = None) -> l - **`tags`**: A set of strings used to categorize the tool. Clients *might* use tags to filter or group available tools. +- **`exclude_args`**: + + A list of argument names to exclude from the tool schema shown to the LLM. This is useful for arguments that are injected at runtime (such as `state`, `user_id`, or credentials) and should not be exposed to the LLM or client. Only arguments with default values can be excluded; attempting to exclude a required argument will raise an error. + + + Example: + + ```python + @mcp.tool( + name="get_user_details", + exclude_args=["user_id"] + ) + def get_user_details(user_id: str = None) -> str: + # user_id will be injected by the server, not provided by the LLM + ... + ``` + + With this configuration, `user_id` will not appear in the tool's parameter schema, but can still be set by the server or framework at runtime. + ### Async Tools FastMCP seamlessly supports both standard (`def`) and asynchronous (`async def`) functions as tools. diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py index b1982c429..3d22a1810 100644 --- a/src/fastmcp/tools/tool.py +++ b/src/fastmcp/tools/tool.py @@ -102,15 +102,12 @@ class Tool(BaseModel): type_adapter = get_cached_typeadapter(fn) schema = type_adapter.json_schema() + prune_params: list[str] = [] context_kwarg = find_kwarg_by_type(fn, kwarg_type=Context) - temp_prune_params: list[str] = [] if context_kwarg: - temp_prune_params.append(context_kwarg) + prune_params.append(context_kwarg) if exclude_args: - temp_prune_params.extend(exclude_args) - prune_params: list[str] | None = ( - None if not temp_prune_params else temp_prune_params - ) + prune_params.extend(exclude_args) schema = compress_schema(schema, prune_params=prune_params)