Skip to content

Commit e889da9

Browse files
committed
fix(client): respect server capabilities before querying components
ClientSessionGroup unconditionally called list_tools(), list_prompts(), and list_resources() on every connect, regardless of whether the server advertised those capabilities. This violates the MCP lifecycle spec which states clients MUST only use capabilities that were successfully negotiated. Fix: check session.initialize_result.capabilities before each list call. Only query prompts/resources/tools if the server advertised the corresponding capability (caps.prompts/resources/tools is not None). Fixes #2689 Signed-off-by: Gaurav Kumar Sinha <gaurav@substrai.dev>
1 parent 2472563 commit e889da9

1 file changed

Lines changed: 21 additions & 16 deletions

File tree

src/mcp/client/session_group.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -345,33 +345,38 @@ async def _aggregate_components(self, server_info: types.Implementation, session
345345
tool_to_session_temp: dict[str, mcp.ClientSession] = {}
346346

347347
# Query the server for its prompts and aggregate to list.
348+
# Only query if the server advertised the capability (spec compliance).
349+
caps = session.initialize_result.capabilities if session.initialize_result else None
348350
try:
349-
prompts = (await session.list_prompts()).prompts
350-
for prompt in prompts:
351-
name = self._component_name(prompt.name, server_info)
352-
prompts_temp[name] = prompt
353-
component_names.prompts.add(name)
351+
if caps and caps.prompts is not None:
352+
prompts = (await session.list_prompts()).prompts
353+
for prompt in prompts:
354+
name = self._component_name(prompt.name, server_info)
355+
prompts_temp[name] = prompt
356+
component_names.prompts.add(name)
354357
except MCPError as err: # pragma: no cover
355358
logging.warning(f"Could not fetch prompts: {err}")
356359

357360
# Query the server for its resources and aggregate to list.
358361
try:
359-
resources = (await session.list_resources()).resources
360-
for resource in resources:
361-
name = self._component_name(resource.name, server_info)
362-
resources_temp[name] = resource
363-
component_names.resources.add(name)
362+
if caps and caps.resources is not None:
363+
resources = (await session.list_resources()).resources
364+
for resource in resources:
365+
name = self._component_name(resource.name, server_info)
366+
resources_temp[name] = resource
367+
component_names.resources.add(name)
364368
except MCPError as err: # pragma: no cover
365369
logging.warning(f"Could not fetch resources: {err}")
366370

367371
# Query the server for its tools and aggregate to list.
368372
try:
369-
tools = (await session.list_tools()).tools
370-
for tool in tools:
371-
name = self._component_name(tool.name, server_info)
372-
tools_temp[name] = tool
373-
tool_to_session_temp[name] = session
374-
component_names.tools.add(name)
373+
if caps and caps.tools is not None:
374+
tools = (await session.list_tools()).tools
375+
for tool in tools:
376+
name = self._component_name(tool.name, server_info)
377+
tools_temp[name] = tool
378+
tool_to_session_temp[name] = session
379+
component_names.tools.add(name)
375380
except MCPError as err: # pragma: no cover
376381
logging.warning(f"Could not fetch tools: {err}")
377382

0 commit comments

Comments
 (0)