4242
4343# after mcp imports so any import error maps to this file, not _mcp.py
4444from . import _mcp , _utils , exceptions , messages , models
45- from .exceptions import MCPServerCapabilitiesError , MCPServerError
45+ from .exceptions import MCPServerError
4646
4747__all__ = 'MCPServer' , 'MCPServerStdio' , 'MCPServerHTTP' , 'MCPServerSSE' , 'MCPServerStreamableHTTP' , 'load_mcp_servers'
4848
@@ -322,12 +322,11 @@ async def list_resources(self) -> list[_mcp.Resource]:
322322 - We also don't subscribe to resource changes to avoid complexity.
323323
324324 Raises:
325- MCPServerCapabilitiesError: If the server does not support resources.
326325 MCPServerError: If the server returns an error.
327326 """
328327 async with self : # Ensure server is running
329328 if not self .capabilities .resources :
330- raise MCPServerCapabilitiesError ( 'Server does not support resources capability' )
329+ return []
331330 try :
332331 result = await self ._client .list_resources ()
333332 except mcp_exceptions .McpError as e :
@@ -338,29 +337,30 @@ async def list_resource_templates(self) -> list[_mcp.ResourceTemplate]:
338337 """Retrieve resource templates that are currently present on the server.
339338
340339 Raises:
341- MCPServerCapabilitiesError: If the server does not support resources.
342340 MCPServerError: If the server returns an error.
343341 """
344342 async with self : # Ensure server is running
345343 if not self .capabilities .resources :
346- raise MCPServerCapabilitiesError ( 'Server does not support resources capability' )
344+ return []
347345 try :
348346 result = await self ._client .list_resource_templates ()
349347 except mcp_exceptions .McpError as e :
350348 raise MCPServerError .from_mcp_sdk_error (e ) from e
351349 return [_mcp .map_from_mcp_resource_template (t ) for t in result .resourceTemplates ]
352350
353351 @overload
354- async def read_resource (self , uri : str ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ]: ...
352+ async def read_resource (
353+ self , uri : str
354+ ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ] | None : ...
355355
356356 @overload
357357 async def read_resource (
358358 self , uri : _mcp .Resource
359- ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ]: ...
359+ ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ] | None : ...
360360
361361 async def read_resource (
362362 self , uri : str | _mcp .Resource
363- ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ]:
363+ ) -> str | messages .BinaryContent | list [str | messages .BinaryContent ] | None :
364364 """Read the contents of a specific resource by URI.
365365
366366 Args:
@@ -369,19 +369,26 @@ async def read_resource(
369369 Returns:
370370 The resource contents. If the resource has a single content item, returns that item directly.
371371 If the resource has multiple content items, returns a list of items.
372+ Returns `None` if the server does not support resources or the resource is not found.
372373
373374 Raises:
374- MCPServerCapabilitiesError: If the server does not support resources.
375- MCPServerError: If the server returns an error (e.g., resource not found).
375+ MCPServerError: If the server returns an error other than resource not found.
376376 """
377377 resource_uri = uri if isinstance (uri , str ) else uri .uri
378378 async with self : # Ensure server is running
379379 if not self .capabilities .resources :
380- raise MCPServerCapabilitiesError ( 'Server does not support resources capability' )
380+ return None
381381 try :
382382 result = await self ._client .read_resource (AnyUrl (resource_uri ))
383383 except mcp_exceptions .McpError as e :
384+ # As per https://modelcontextprotocol.io/specification/2025-06-18/server/resources#error-handling
385+ if e .error .code == - 32002 :
386+ return None
384387 raise MCPServerError .from_mcp_sdk_error (e ) from e
388+
389+ if not result .contents :
390+ return None
391+
385392 return (
386393 self ._get_content (result .contents [0 ])
387394 if len (result .contents ) == 1
@@ -483,7 +490,9 @@ async def _map_tool_result_part(
483490 resource = part .resource
484491 return self ._get_content (resource )
485492 elif isinstance (part , mcp_types .ResourceLink ):
486- return await self .read_resource (str (part .uri ))
493+ result = await self .read_resource (str (part .uri ))
494+ # If resource not found, return an empty string as it's impossible to fetch anyway
495+ return result if result is not None else ''
487496 else :
488497 assert_never (part )
489498
0 commit comments