Skip to content
Open
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
15 changes: 13 additions & 2 deletions src/mcp/server/mcpserver/resources/resource_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,18 @@ def add_resource(self, resource: Resource) -> Resource:
self._resources[str(resource.uri)] = resource
return resource

def add_resource_template(self, template: ResourceTemplate) -> ResourceTemplate:
"""Add a resource template to the manager.

Args:
template: A ResourceTemplate instance to add.

Returns:
The added resource template.
"""
self._templates[template.uri_template] = template
return template

def add_template(
self,
fn: Callable[..., Any],
Expand All @@ -83,8 +95,7 @@ def add_template(
meta=meta,
security=security,
)
self._templates[template.uri_template] = template
return template
return self.add_resource_template(template)

async def get_resource(
self, uri: AnyUrl | str, context: Context[LifespanContextT, RequestT]
Expand Down
12 changes: 11 additions & 1 deletion src/mcp/server/mcpserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
Resource,
ResourceManager,
ResourceSecurity,
ResourceTemplate,
)
from mcp.server.mcpserver.tools import Tool, ToolManager
from mcp.server.mcpserver.utilities.context_injection import find_context_parameter
Expand Down Expand Up @@ -729,6 +730,14 @@ def add_resource(self, resource: Resource) -> None:
"""
self._resource_manager.add_resource(resource)

def add_resource_template(self, template: ResourceTemplate) -> None:
"""Add a resource template to the server.

Args:
template: A ResourceTemplate instance to add
"""
self._resource_manager.add_resource_template(template)

def resource(
self,
uri: str,
Expand Down Expand Up @@ -846,7 +855,7 @@ def decorator(fn: _CallableT) -> _CallableT:
)

# Register as template
self._resource_manager.add_template(
template = ResourceTemplate.from_function(
fn=fn,
uri_template=uri,
name=name,
Expand All @@ -858,6 +867,7 @@ def decorator(fn: _CallableT) -> _CallableT:
security=security if security is not None else self._resource_security,
meta=meta,
)
self._resource_manager.add_resource_template(template)
else:
if func_params:
raise ValueError(
Expand Down
12 changes: 12 additions & 0 deletions tests/server/mcpserver/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -1004,6 +1004,18 @@ def get_csv(user: str) -> str:
)
)

async def test_add_resource_template(self):
"""Test that a resource template can be added without using the @resource decorator."""
from mcp.server.mcpserver.resources import ResourceTemplate

mcp = MCPServer()

def get_data(param: str) -> str: # type: ignore # pragma: no cover
return "Data"

template = ResourceTemplate.from_function(get_data, "resource://{param}")
mcp.add_resource_template(template)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Missing assertions: test_add_resource_template never verifies the template was actually registered. Call await mcp.list_resource_templates() and assert the expected count, or use Client to read a resource through the template, so the test catches regressions. Without assertions the test will pass even if add_resource_template is a no-op.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At tests/server/mcpserver/test_server.py, line 1017:

<comment>Missing assertions: `test_add_resource_template` never verifies the template was actually registered. Call `await mcp.list_resource_templates()` and assert the expected count, or use `Client` to read a resource through the template, so the test catches regressions. Without assertions the test will pass even if `add_resource_template` is a no-op.</comment>

<file context>
@@ -1004,6 +1004,18 @@ def get_csv(user: str) -> str:
+            return "Data"
+
+        template = ResourceTemplate.from_function(get_data, "resource://{param}")
+        mcp.add_resource_template(template)
+
 
</file context>

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MCPServer.add_resource_template() returns None, just like add_resource().



class TestServerResourceMetadata:
"""Test MCPServer @resource decorator meta parameter for list operations.
Expand Down
Loading