From 2233b5844b104d484f4f97ac1f8a2f32a4868c87 Mon Sep 17 00:00:00 2001 From: deepak-stratforge Date: Thu, 29 May 2025 20:05:18 +0530 Subject: [PATCH] feat(tool): validate and enforce default values - Added validation to ensure all parameters listed in `exclude_args` exist in the function. - Ensured parameters in `exclude_args` have default values to avoid runtime errors. - Added test. --- src/fastmcp/tools/tool.py | 12 ++++++++++++ tests/server/test_tool_exclude_args.py | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py index ded10ff0c..b1982c429 100644 --- a/src/fastmcp/tools/tool.py +++ b/src/fastmcp/tools/tool.py @@ -76,6 +76,18 @@ class Tool(BaseModel): if param.kind == inspect.Parameter.VAR_KEYWORD: raise ValueError("Functions with **kwargs are not supported as tools") + if exclude_args: + for arg_name in exclude_args: + if arg_name not in sig.parameters: + raise ValueError( + f"Parameter '{arg_name}' in exclude_args does not exist in function." + ) + param = sig.parameters[arg_name] + if param.default == inspect.Parameter.empty: + raise ValueError( + f"Parameter '{arg_name}' in exclude_args must have a default value." + ) + func_name = name or getattr(fn, "__name__", None) or fn.__class__.__name__ if func_name == "": diff --git a/tests/server/test_tool_exclude_args.py b/tests/server/test_tool_exclude_args.py index 99e4ef571..959d2c1b6 100644 --- a/tests/server/test_tool_exclude_args.py +++ b/tests/server/test_tool_exclude_args.py @@ -1,5 +1,6 @@ from typing import Any +import pytest from mcp.types import TextContent from fastmcp import Client, FastMCP @@ -24,6 +25,21 @@ async def test_tool_exclude_args_in_tool_manager(): assert args not in tools[0].parameters +async def test_tool_exclude_args_without_default_value_raises_error(): + """Test that excluding args without default values raises ValueError""" + mcp = FastMCP("Test Server") + + with pytest.raises(ValueError): + + @mcp.tool(exclude_args=["state"]) + def echo(message: str, state: dict[str, Any] | None) -> str: + """Echo back the message provided.""" + if state: + # State was read + pass + return message + + async def test_add_tool_method_exclude_args(): """Test that tool exclude_args work with the add_tool method.""" mcp = FastMCP("Test Server")