Skip to content

Commit 8c872a7

Browse files
committed
fix: add status field in Resource class and Resource as a return type in CallToolResult
1 parent 1cb7407 commit 8c872a7

File tree

8 files changed

+56
-5
lines changed

8 files changed

+56
-5
lines changed

src/mcp/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
ReadResourceResult,
3939
Resource,
4040
ResourcesCapability,
41+
ResourceStatus,
4142
ResourceUpdatedNotification,
4243
RootsCapability,
4344
SamplingMessage,
@@ -90,6 +91,7 @@
9091
"ReadResourceRequest",
9192
"ReadResourceResult",
9293
"ResourcesCapability",
94+
"ResourceStatus",
9395
"ResourceUpdatedNotification",
9496
"Resource",
9597
"RootsCapability",

src/mcp/server/fastmcp/resources/base.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
field_validator,
1414
)
1515

16+
from mcp.types import ResourceStatus as MCPResourceStatus
17+
1618

1719
class Resource(BaseModel, abc.ABC):
1820
"""Base class for all resources."""
@@ -31,6 +33,10 @@ class Resource(BaseModel, abc.ABC):
3133
description="MIME type of the resource content",
3234
pattern=r"^[a-zA-Z0-9]+/[a-zA-Z0-9\-+.]+$",
3335
)
36+
status: MCPResourceStatus = Field(
37+
default=MCPResourceStatus.PENDING,
38+
description="Status of the resource",
39+
)
3440

3541
@field_validator("name", mode="before")
3642
@classmethod

src/mcp/server/fastmcp/resources/resource_manager.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,22 @@ def list_resources(self) -> list[Resource]:
8989
logger.debug("Listing resources", extra={"count": len(self._resources)})
9090
return list(self._resources.values())
9191

92+
def update_resource(self, resource: Resource) -> Resource:
93+
"""Update an existing resource."""
94+
logger.debug(
95+
"Updating resource",
96+
extra={
97+
"uri": resource.uri,
98+
"type": type(resource).__name__,
99+
"status": resource.status,
100+
"resource_name": resource.name,
101+
},
102+
)
103+
if str(resource.uri) not in self._resources:
104+
raise ValueError(f"Resource not found: {resource.uri}")
105+
self._resources[str(resource.uri)] = resource
106+
return resource
107+
92108
def list_templates(self) -> list[ResourceTemplate]:
93109
"""List all registered templates."""
94110
logger.debug("Listing templates", extra={"count": len(self._templates)})

src/mcp/server/fastmcp/server.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ def get_context(self) -> Context[ServerSession, object]:
269269

270270
async def call_tool(
271271
self, name: str, arguments: dict[str, Any]
272-
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
272+
) -> Sequence[TextContent | ImageContent | EmbeddedResource | MCPResource]:
273273
"""Call a tool by name with arguments."""
274274
context = self.get_context()
275275
result = await self._tool_manager.call_tool(name, arguments, context=context)
@@ -282,10 +282,12 @@ async def list_resources(self) -> list[MCPResource]:
282282
resources = self._resource_manager.list_resources()
283283
return [
284284
MCPResource(
285+
type="resource",
285286
uri=resource.uri,
286287
name=resource.name or "",
287288
description=resource.description,
288289
mimeType=resource.mime_type,
290+
status=resource.status,
289291
)
290292
for resource in resources
291293
]
@@ -869,7 +871,7 @@ async def get_prompt(
869871

870872
def _convert_to_content(
871873
result: Any,
872-
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
874+
) -> Sequence[TextContent | ImageContent | EmbeddedResource | MCPResource]:
873875
"""Convert a result to a sequence of content objects."""
874876
if result is None:
875877
return []

src/mcp/server/lowlevel/server.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,10 @@ def decorator(
399399
...,
400400
Awaitable[
401401
Iterable[
402-
types.TextContent | types.ImageContent | types.EmbeddedResource
402+
types.TextContent
403+
| types.ImageContent
404+
| types.EmbeddedResource
405+
| types.Resource
403406
]
404407
],
405408
],

src/mcp/types.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from collections.abc import Callable
2+
from enum import Enum
23
from typing import (
34
Annotated,
45
Any,
@@ -368,15 +369,31 @@ class Annotations(BaseModel):
368369
model_config = ConfigDict(extra="allow")
369370

370371

372+
class ResourceStatus(str, Enum):
373+
"""The status of a resource."""
374+
375+
READY = "ready"
376+
"""Resource is ready to be read."""
377+
PENDING = "pending"
378+
"""Resource is being created or processed."""
379+
ERROR = "error"
380+
"""Resource has an error state."""
381+
DELETED = "deleted"
382+
"""Resource has been deleted."""
383+
384+
371385
class Resource(BaseModel):
372386
"""A known resource that the server is capable of reading."""
373387

388+
type: Literal["resource"]
374389
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
375390
"""The URI of this resource."""
376391
name: str
377392
"""A human-readable name for this resource."""
378393
description: str | None = None
379394
"""A description of what this resource represents."""
395+
status: ResourceStatus | None = None
396+
"""The status of this resource."""
380397
mimeType: str | None = None
381398
"""The MIME type of this resource, if known."""
382399
size: int | None = None
@@ -791,7 +808,7 @@ class CallToolRequest(Request[CallToolRequestParams, Literal["tools/call"]]):
791808
class CallToolResult(Result):
792809
"""The server's response to a tool call."""
793810

794-
content: list[TextContent | ImageContent | EmbeddedResource]
811+
content: list[TextContent | ImageContent | EmbeddedResource | Resource]
795812
isError: bool = False
796813

797814

tests/issues/test_152_resource_mime_type.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,12 +83,16 @@ async def test_lowlevel_resource_mime_type():
8383
# Create test resources with specific mime types
8484
test_resources = [
8585
types.Resource(
86-
uri=AnyUrl("test://image"), name="test image", mimeType="image/png"
86+
uri=AnyUrl("test://image"),
87+
name="test image",
88+
mimeType="image/png",
89+
type="resource",
8790
),
8891
types.Resource(
8992
uri=AnyUrl("test://image_bytes"),
9093
name="test image bytes",
9194
mimeType="image/png",
95+
type="resource",
9296
),
9397
]
9498

tests/shared/test_memory.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ async def handle_list_resources():
2424
uri=AnyUrl("memory://test"),
2525
name="Test Resource",
2626
description="A test resource",
27+
type="resource",
2728
)
2829
]
2930

0 commit comments

Comments
 (0)