Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/mcp/server/experimental/request_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def validate_task_mode(
error = ErrorData(code=METHOD_NOT_FOUND, message="This tool does not support task-augmented invocation")

if error is not None and raise_error:
raise MCPError(code=error.code, message=error.message)
raise MCPError.from_error_data(error)

return error

Expand Down
7 changes: 1 addition & 6 deletions src/mcp/server/lowlevel/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -795,12 +795,7 @@ async def _handle_request(

await message.respond(response)
else: # pragma: no cover
await message.respond(
types.ErrorData(
code=types.METHOD_NOT_FOUND,
message="Method not found",
)
)
await message.respond(types.ErrorData(code=types.METHOD_NOT_FOUND, message="Method not found"))

logger.debug("Response sent")

Expand Down
6 changes: 2 additions & 4 deletions src/mcp/server/mcpserver/resources/resource_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,8 @@ def add_template(
return template

async def get_resource(
self,
uri: AnyUrl | str,
context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None,
) -> Resource | None:
self, uri: AnyUrl | str, context: Context[ServerSessionT, LifespanContextT, RequestT] | None = None
) -> Resource:
"""Get resource by URI, checking concrete resources first, then templates."""
uri_str = str(uri)
logger.debug("Getting resource", extra={"uri": uri_str})
Expand Down
12 changes: 7 additions & 5 deletions src/mcp/server/mcpserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,16 +347,18 @@ async def read_resource(self, uri: AnyUrl | str) -> Iterable[ReadResourceContent
"""Read a resource by URI."""

context = self.get_context()
resource = await self._resource_manager.get_resource(uri, context=context)
if not resource: # pragma: no cover
try:
resource = await self._resource_manager.get_resource(uri, context=context)
except ValueError:
raise ResourceError(f"Unknown resource: {uri}")

try:
content = await resource.read()
return [ReadResourceContents(content=content, mime_type=resource.mime_type, meta=resource.meta)]
except Exception as e: # pragma: no cover
logger.exception(f"Error reading resource {uri}")
raise ResourceError(str(e))
except Exception as exc:
logger.exception(f"Error getting resource {uri}")
# If an exception happens when reading the resource, we should not leak the exception to the client.
raise ResourceError(f"Error reading resource {uri}") from exc

def add_tool(
self,
Expand Down
5 changes: 3 additions & 2 deletions tests/issues/test_141_resource_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from mcp import Client
from mcp.server.mcpserver import MCPServer
from mcp.server.mcpserver.exceptions import ResourceError
from mcp.types import (
ListResourceTemplatesResult,
TextResourceContents,
Expand Down Expand Up @@ -54,10 +55,10 @@ def get_user_profile_missing(user_id: str) -> str: # pragma: no cover
assert result_list[0].mime_type == "text/plain"

# Verify invalid parameters raise error
with pytest.raises(ValueError, match="Unknown resource"):
with pytest.raises(ResourceError, match="Unknown resource"):
await mcp.read_resource("resource://users/123/posts") # Missing post_id

with pytest.raises(ValueError, match="Unknown resource"):
with pytest.raises(ResourceError, match="Unknown resource"):
await mcp.read_resource("resource://users/123/posts/456/extra") # Extra path component


Expand Down
Loading