Skip to content

Question: How to get a resource argument containing "/" ? #436

Closed

Description

@Gelembjuk

I want to make the resource like

@mcp.resource("folder://{path}") def folder_contents(path: str) -> list[str]:

The path should be something like xxx/. or xxx/abc/zzz/

With the @mcp.resource("folder://{path}") it doesn't work. Is there a way to implement it?

Activity

  1. added
    bugSomething isn't working
    needs reproneeds additional information to be able to reproduce bug
    needs confirmationNeeds confirmation that the PR is actually required or needed.
    and removed
    needs reproneeds additional information to be able to reproduce bug
    on Oct 7, 2025
  2. felixweinberger commented on Oct 7, 2025

    @felixweinberger
    Contributor

    Hi is this still a problem? If yes could you provide a code snippet that demonstrates the issue, your expectations and where it fails?

  3. maxisbey commented on Oct 8, 2025

    @maxisbey
    Contributor

    Seems this could still be relevant, maybe we could consider looking into doing something similar to FastAPI/Starlette with {file_path:path} where path specifies this can have slashes in it.

    @Kludex do you think this makes sense? Did it work well for Starlette?

  4. maxisbey commented on Oct 8, 2025

    @maxisbey
    Contributor

    Claude's repro:

    """Test resource templates with path parameters containing forward slashes."""
    
    import json
    from typing import Any
    
    import pytest
    
    from mcp.server.fastmcp.resources import FunctionResource, ResourceTemplate
    
    
    def test_template_with_path_parameter_single_level():
        """Test matching URIs with single-level path parameters."""
    
        def folder_contents(path: str) -> list[str]:
            return ["file1.txt", "file2.txt"]
    
        template = ResourceTemplate.from_function(
            fn=folder_contents,
            uri_template="folder://{path}",
            name="folder",
        )
    
        # Single level path should work
        params = template.matches("folder://root")
        assert params == {"path": "root"}
    
    
    def test_template_with_path_parameter_nested_path():
        """Test matching URIs with nested path parameters containing forward slashes.
    
        This is the issue reported in #436.
        A user wants to define a resource like:
          @mcp.resource("folder://{path}")
          def folder_contents(path: str) -> list[str]:
    
        And then be able to match URIs like "folder://xxx/abc/zzz/" where the path
        parameter contains forward slashes.
    
        Currently, this fails because the regex pattern uses [^/]+ which excludes
        forward slashes.
        """
    
        def folder_contents(path: str) -> list[str]:
            # This would return the contents of the nested directory
            return ["file1.txt", "file2.txt"]
    
        template = ResourceTemplate.from_function(
            fn=folder_contents,
            uri_template="folder://{path}",
            name="folder",
        )
    
        # Nested paths with slashes should work but currently fail
        params = template.matches("folder://xxx/abc/zzz/")
    
        # This should match and extract the full path
        assert params is not None, "Failed to match nested path with slashes"
        assert params == {"path": "xxx/abc/zzz/"}
    
    
    def test_template_with_path_parameter_various_paths():
        """Test matching various nested paths."""
    
        def get_file(path: str) -> str:
            return f"Content of {path}"
    
        template = ResourceTemplate.from_function(
            fn=get_file,
            uri_template="file://{path}",
            name="file",
        )
    
        # Test various nested paths
        test_cases = [
            ("file://simple", {"path": "simple"}),
            ("file://one/two", {"path": "one/two"}),
            ("file://one/two/three", {"path": "one/two/three"}),
            ("file://very/deep/nested/path/to/file.txt",
             {"path": "very/deep/nested/path/to/file.txt"}),
            ("file://path/with/trailing/slash/",
             {"path": "path/with/trailing/slash/"}),
            ("file://path.with.dots/file.txt",
             {"path": "path.with.dots/file.txt"}),
        ]
    
        for uri, expected_params in test_cases:
            params = template.matches(uri)
            assert params is not None, f"Failed to match URI: {uri}"
            assert params == expected_params, (
                f"For URI {uri}, expected {expected_params} but got {params}"
            )
    
    
    def test_template_with_multiple_params_and_path():
        """Test template with multiple parameters where one is a path."""
    
        def get_resource(bucket: str, path: str) -> dict[str, Any]:
            return {"bucket": bucket, "path": path}
    
        template = ResourceTemplate.from_function(
            fn=get_resource,
            uri_template="s3://{bucket}/{path}",
            name="s3",
        )
    
        # This should extract bucket and path separately,
        # with path potentially containing slashes
        params = template.matches("s3://mybucket/folder/subfolder/file.txt")
    
        assert params is not None
    
        # If the regex allowed slashes in the last parameter,
        # this would work correctly
        assert params["bucket"] == "mybucket"
        # The path might contain slashes
        assert "file.txt" in params["path"]
    
    
    @pytest.mark.anyio
    async def test_create_resource_with_nested_path():
        """Test creating a resource from template with nested path parameter."""
    
        def read_folder(path: str) -> list[str]:
            # Simulate reading a folder at the given path
            if path == "project/src/components":
                return ["Button.tsx", "Card.tsx", "Header.tsx"]
            return []
    
        template = ResourceTemplate.from_function(
            fn=read_folder,
            uri_template="folder://{path}",
            name="folder",
        )
    
        # Try to match and create a resource with a nested path
        uri = "folder://project/src/components"
        params = template.matches(uri)
    
        assert params is not None
        resource = await template.create_resource(uri, params)
        assert isinstance(resource, FunctionResource)
        content = await resource.read()
        assert isinstance(content, str)
        data = json.loads(content)
        assert "Button.tsx" in data
        assert "Card.tsx" in data
        assert "Header.tsx" in data
  5. added and removed
    needs confirmationNeeds confirmation that the PR is actually required or needed.
    on Oct 8, 2025
  6. Kludex commented on Oct 8, 2025

    @Kludex
    Member

    Seems this could still be relevant, maybe we could consider looking into doing something similar to FastAPI/Starlette with {file_path:path} where path specifies this can have slashes in it.

    @Kludex do you think this makes sense? Did it work well for Starlette?

    It does work well, there's no way to do that without the converters.

  7. maxisbey commented on Oct 8, 2025

    @maxisbey
    Contributor

    Seems this could still be relevant, maybe we could consider looking into doing something similar to FastAPI/Starlette with {file_path:path} where path specifies this can have slashes in it.
    @Kludex do you think this makes sense? Did it work well for Starlette?

    It does work well, there's no way to do that without the converters.

    Can we just import from starlette or do we need to implement something custom

  8. Kludex commented on Dec 4, 2025

    @Kludex
    Member

    Seems this could still be relevant, maybe we could consider looking into doing something similar to FastAPI/Starlette with {file_path:path} where path specifies this can have slashes in it.
    @Kludex do you think this makes sense? Did it work well for Starlette?

    It does work well, there's no way to do that without the converters.

    Can we just import from starlette or do we need to implement something custom

    I think we can copy that logic in here.

  9. maxisbey commented on Dec 8, 2025

    @maxisbey
    Contributor

    related: #220

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingready for workEnough information for someone to start working on

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions