Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 2 additions & 0 deletions src/mcp/server/fastmcp/resources/resource_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ def add_template(
title: str | None = None,
description: str | None = None,
mime_type: str | None = None,
icons: list[Any] | None = None,
) -> ResourceTemplate:
"""Add a template from a function."""
template = ResourceTemplate.from_function(
Expand All @@ -70,6 +71,7 @@ def add_template(
title=title,
description=description,
mime_type=mime_type,
icons=icons,
)
self._templates[template.uri_template] = template
return template
Expand Down
6 changes: 5 additions & 1 deletion src/mcp/server/fastmcp/resources/templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from mcp.server.fastmcp.resources.types import FunctionResource, Resource
from mcp.server.fastmcp.utilities.context_injection import find_context_parameter, inject_context
from mcp.server.fastmcp.utilities.func_metadata import func_metadata
from mcp.types import Icon

if TYPE_CHECKING:
from mcp.server.fastmcp.server import Context
Expand All @@ -27,6 +28,7 @@ class ResourceTemplate(BaseModel):
title: str | None = Field(description="Human-readable title of the resource", default=None)
description: str | None = Field(description="Description of what the resource does")
mime_type: str = Field(default="text/plain", description="MIME type of the resource content")
icons: list[Icon] | None = Field(default=None, description="Optional list of icons for the resource template")
fn: Callable[..., Any] = Field(exclude=True)
parameters: dict[str, Any] = Field(description="JSON schema for function parameters")
context_kwarg: str | None = Field(None, description="Name of the kwarg that should receive context")
Expand All @@ -40,6 +42,7 @@ def from_function(
title: str | None = None,
description: str | None = None,
mime_type: str | None = None,
icons: list[Icon] | None = None,
context_kwarg: str | None = None,
) -> ResourceTemplate:
"""Create a template from a function."""
Expand Down Expand Up @@ -67,6 +70,7 @@ def from_function(
title=title,
description=description or fn.__doc__ or "",
mime_type=mime_type or "text/plain",
icons=icons,
fn=fn,
parameters=parameters,
context_kwarg=context_kwarg,
Expand Down Expand Up @@ -103,7 +107,7 @@ async def create_resource(
title=self.title,
description=self.description,
mime_type=self.mime_type,
icons=None, # Resource templates don't support icons
icons=self.icons,
fn=lambda: result, # Capture result in closure
)
except Exception as e:
Expand Down
3 changes: 2 additions & 1 deletion src/mcp/server/fastmcp/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ async def list_resource_templates(self) -> list[MCPResourceTemplate]:
title=template.title,
description=template.description,
mimeType=template.mime_type,
icons=template.icons,
)
for template in templates
]
Expand Down Expand Up @@ -559,7 +560,7 @@ def decorator(fn: AnyFunction) -> AnyFunction:
title=title,
description=description,
mime_type=mime_type,
# Note: Resource templates don't support icons
icons=icons,
)
else:
# Register as regular resource
Expand Down
2 changes: 2 additions & 0 deletions src/mcp/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,8 @@ class ResourceTemplate(BaseMetadata):
The MIME type for all resources that match this template. This should only be
included if all resources matching this template have the same type.
"""
icons: list[Icon] | None = None
"""An optional list of icons for this resource template."""
annotations: Annotations | None = None
meta: dict[str, Any] | None = Field(alias="_meta", default=None)
"""
Expand Down
16 changes: 16 additions & 0 deletions tests/issues/test_1338_icons_and_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,12 @@ def test_prompt(text: str) -> str:
"""A test prompt with an icon."""
return text

# Create resource template with icon
@mcp.resource("test://weather/{city}", icons=[test_icon])
def test_resource_template(city: str) -> str:
"""Get weather for a city."""
return f"Weather for {city}"

# Test server metadata includes websiteUrl and icons
assert mcp.name == "TestServer"
assert mcp.website_url == "https://example.com"
Expand Down Expand Up @@ -75,6 +81,16 @@ def test_prompt(text: str) -> str:
assert len(prompt.icons) == 1
assert prompt.icons[0].src == test_icon.src

# Test resource template includes icon
templates = await mcp.list_resource_templates()
assert len(templates) == 1
template = templates[0]
assert template.name == "test_resource_template"
assert template.uriTemplate == "test://weather/{city}"
assert template.icons is not None
assert len(template.icons) == 1
assert template.icons[0].src == test_icon.src


async def test_multiple_icons():
"""Test that multiple icons can be added to tools, resources, and prompts."""
Expand Down
Loading