diff --git a/src/mcp/server/fastmcp/resources/templates.py b/src/mcp/server/fastmcp/resources/templates.py index 40afaf801a..fde5ff8c96 100644 --- a/src/mcp/server/fastmcp/resources/templates.py +++ b/src/mcp/server/fastmcp/resources/templates.py @@ -55,7 +55,7 @@ def from_function( def matches(self, uri: str) -> dict[str, Any] | None: """Check if URI matches template and extract parameters.""" # Convert template to regex pattern - pattern = self.uri_template.replace("{", "(?P<").replace("}", ">[^/]+)") + pattern = self.uri_template.replace("{", "(?P<").replace("}", ">.+)") match = re.match(f"^{pattern}$", uri) if match: return match.groupdict() diff --git a/tests/issues/test_141_resource_templates.py b/tests/issues/test_141_resource_templates.py index d6526e9ff4..67f8f49b7e 100644 --- a/tests/issues/test_141_resource_templates.py +++ b/tests/issues/test_141_resource_templates.py @@ -58,11 +58,6 @@ def get_user_profile_missing(user_id: str) -> str: with pytest.raises(ValueError, match="Unknown resource"): await mcp.read_resource("resource://users/123/posts") # Missing post_id - with pytest.raises(ValueError, match="Unknown resource"): - await mcp.read_resource( - "resource://users/123/posts/456/extra" - ) # Extra path component - @pytest.mark.anyio async def test_resource_template_client_interaction(): diff --git a/tests/server/fastmcp/resources/test_resource_template.py b/tests/server/fastmcp/resources/test_resource_template.py index 09bc600d01..8075989d59 100644 --- a/tests/server/fastmcp/resources/test_resource_template.py +++ b/tests/server/fastmcp/resources/test_resource_template.py @@ -46,6 +46,25 @@ def my_func(key: str, value: int) -> dict: assert template.matches("test://foo") is None assert template.matches("other://foo/123") is None + def test_template_matches_slashes_in_value(self): + """Test matching URIs against a template, the value containing slashes.""" + + def my_func(path: str) -> dict: + return {"path": path} + + template = ResourceTemplate.from_function( + fn=my_func, + uri_template="test://content/{path}", + name="test", + ) + + # Valid match + params = template.matches("test://content/path/with/slashes") + assert params == {"path": "path/with/slashes"} + + # No match + assert template.matches("test://content/") is None + @pytest.mark.anyio async def test_create_resource(self): """Test creating a resource from a template."""