diff --git a/src/mcp/types.py b/src/mcp/types.py index 654c00660..1a3f78857 100644 --- a/src/mcp/types.py +++ b/src/mcp/types.py @@ -1290,6 +1290,12 @@ class ToolAnnotations(BaseModel): Default: true """ + agencyHint: bool | None = None + """ + If true, this tool encapsulates an internal "agent loop" (e.g., plan–act–observe cycles, tool-chaining, or autonomous retries). + Default: false + """ + model_config = ConfigDict(extra="allow") diff --git a/tests/server/fastmcp/test_tool_manager.py b/tests/server/fastmcp/test_tool_manager.py index d83d48474..a766f4bc0 100644 --- a/tests/server/fastmcp/test_tool_manager.py +++ b/tests/server/fastmcp/test_tool_manager.py @@ -428,6 +428,7 @@ def read_data(path: str) -> str: # pragma: no cover title="File Reader", readOnlyHint=True, openWorldHint=False, + agencyHint=True, ) manager = ToolManager() @@ -437,6 +438,7 @@ def read_data(path: str) -> str: # pragma: no cover assert tool.annotations.title == "File Reader" assert tool.annotations.readOnlyHint is True assert tool.annotations.openWorldHint is False + assert tool.annotations.agencyHint is True @pytest.mark.anyio async def test_tool_annotations_in_fastmcp(self): @@ -444,7 +446,7 @@ async def test_tool_annotations_in_fastmcp(self): app = FastMCP() - @app.tool(annotations=ToolAnnotations(title="Echo Tool", readOnlyHint=True)) + @app.tool(annotations=ToolAnnotations(title="Echo Tool", readOnlyHint=True, agencyHint=False)) def echo(message: str) -> str: # pragma: no cover """Echo a message back.""" return message @@ -454,6 +456,7 @@ def echo(message: str) -> str: # pragma: no cover assert tools[0].annotations is not None assert tools[0].annotations.title == "Echo Tool" assert tools[0].annotations.readOnlyHint is True + assert tools[0].annotations.agencyHint is False class TestStructuredOutput: diff --git a/tests/server/test_lowlevel_tool_annotations.py b/tests/server/test_lowlevel_tool_annotations.py index f812c4877..31595475c 100644 --- a/tests/server/test_lowlevel_tool_annotations.py +++ b/tests/server/test_lowlevel_tool_annotations.py @@ -35,6 +35,7 @@ async def list_tools(): # pragma: no cover annotations=ToolAnnotations( title="Echo Tool", readOnlyHint=True, + agencyHint=True, ), ) ] @@ -98,3 +99,4 @@ async def handle_messages(): assert tools_result.tools[0].annotations is not None assert tools_result.tools[0].annotations.title == "Echo Tool" assert tools_result.tools[0].annotations.readOnlyHint is True + assert tools_result.tools[0].annotations.agencyHint is True