From 0b9f2e1c67d8e843d3f5452f3c407d4f050adc6c Mon Sep 17 00:00:00 2001 From: Douwe Maan Date: Wed, 22 Oct 2025 17:05:42 +0000 Subject: [PATCH] Only list MCP tools once, not at every agent run step --- pydantic_ai_slim/pydantic_ai/mcp.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pydantic_ai_slim/pydantic_ai/mcp.py b/pydantic_ai_slim/pydantic_ai/mcp.py index 70364c0ad4..506fda4189 100644 --- a/pydantic_ai_slim/pydantic_ai/mcp.py +++ b/pydantic_ai_slim/pydantic_ai/mcp.py @@ -113,6 +113,7 @@ class MCPServer(AbstractToolset[Any], ABC): _read_stream: MemoryObjectReceiveStream[SessionMessage | Exception] _write_stream: MemoryObjectSendStream[SessionMessage] _server_info: mcp_types.Implementation + _tools: list[mcp_types.Tool] | None def __init__( self, @@ -148,6 +149,7 @@ def __post_init__(self): self._enter_lock = Lock() self._running_count = 0 self._exit_stack = None + self._tools = None @abstractmethod @asynccontextmanager @@ -194,13 +196,14 @@ def server_info(self) -> mcp_types.Implementation: async def list_tools(self) -> list[mcp_types.Tool]: """Retrieve tools that are currently active on the server. - Note: - - We don't cache tools as they might change. - - We also don't subscribe to the server to avoid complexity. + Note that we don't subscribe to the server to avoid complexity. """ + if self._tools is not None: + return self._tools async with self: # Ensure server is running result = await self._client.list_tools() - return result.tools + self._tools = result.tools + return self._tools async def direct_call_tool( self,