Add icons support for ResourceTemplate (#1412)
Some checks failed
Main branch checks / checks (push) Has been cancelled
Some checks failed
Main branch checks / checks (push) Has been cancelled
This commit is contained in:
parent
f676f6c0f0
commit
3e798bfc01
5 changed files with 28 additions and 2 deletions
|
|
@ -10,6 +10,7 @@ from pydantic import AnyUrl
|
|||
from mcp.server.fastmcp.resources.base import Resource
|
||||
from mcp.server.fastmcp.resources.templates import ResourceTemplate
|
||||
from mcp.server.fastmcp.utilities.logging import get_logger
|
||||
from mcp.types import Icon
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from mcp.server.fastmcp.server import Context
|
||||
|
|
@ -61,6 +62,7 @@ class ResourceManager:
|
|||
title: str | None = None,
|
||||
description: str | None = None,
|
||||
mime_type: str | None = None,
|
||||
icons: list[Icon] | None = None,
|
||||
) -> ResourceTemplate:
|
||||
"""Add a template from a function."""
|
||||
template = ResourceTemplate.from_function(
|
||||
|
|
@ -70,6 +72,7 @@ class ResourceManager:
|
|||
title=title,
|
||||
description=description,
|
||||
mime_type=mime_type,
|
||||
icons=icons,
|
||||
)
|
||||
self._templates[template.uri_template] = template
|
||||
return template
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ from pydantic import BaseModel, Field, validate_call
|
|||
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
|
||||
|
|
@ -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")
|
||||
|
|
@ -40,6 +42,7 @@ class ResourceTemplate(BaseModel):
|
|||
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."""
|
||||
|
|
@ -67,6 +70,7 @@ class ResourceTemplate(BaseModel):
|
|||
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,
|
||||
|
|
@ -103,7 +107,7 @@ class ResourceTemplate(BaseModel):
|
|||
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:
|
||||
|
|
|
|||
|
|
@ -335,6 +335,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
title=template.title,
|
||||
description=template.description,
|
||||
mimeType=template.mime_type,
|
||||
icons=template.icons,
|
||||
)
|
||||
for template in templates
|
||||
]
|
||||
|
|
@ -559,7 +560,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|||
title=title,
|
||||
description=description,
|
||||
mime_type=mime_type,
|
||||
# Note: Resource templates don't support icons
|
||||
icons=icons,
|
||||
)
|
||||
else:
|
||||
# Register as regular resource
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -39,6 +39,12 @@ async def test_icons_and_website_url():
|
|||
"""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"
|
||||
|
|
@ -75,6 +81,16 @@ async def test_icons_and_website_url():
|
|||
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."""
|
||||
|
|
|
|||
Loading…
Reference in a new issue