File tree Expand file tree Collapse file tree 2 files changed +11
-8
lines changed
src/mcp/server/fastmcp/resources Expand file tree Collapse file tree 2 files changed +11
-8
lines changed Original file line number Diff line number Diff line change 66import re
77from collections .abc import Callable
88from typing import TYPE_CHECKING , Any
9+ from urllib .parse import unquote
910
1011from pydantic import BaseModel , Field , validate_call
1112
@@ -83,12 +84,16 @@ def from_function(
8384 )
8485
8586 def matches (self , uri : str ) -> dict [str , Any ] | None :
86- """Check if URI matches template and extract parameters."""
87+ """Check if URI matches template and extract parameters.
88+
89+ Extracted parameters are URL-decoded to handle percent-encoded characters.
90+ """
8791 # Convert template to regex pattern
8892 pattern = self .uri_template .replace ("{" , "(?P<" ).replace ("}" , ">[^/]+)" )
8993 match = re .match (f"^{ pattern } $" , uri )
9094 if match :
91- return match .groupdict ()
95+ # URL-decode all extracted parameter values
96+ return {key : unquote (value ) for key , value in match .groupdict ().items ()}
9297 return None
9398
9499 async def create_resource (
Original file line number Diff line number Diff line change @@ -39,7 +39,7 @@ def search(query: str) -> str: # pragma: no cover
3939
4040 params = template .matches ("search://caf%C3%A9" )
4141 assert params is not None
42- assert params ["query" ] == "cafe" # encoded as UTF-8
42+ assert params ["query" ] == "café"
4343
4444 def test_template_matches_decodes_complex_phrase (self ):
4545 """Test complex French phrase from the original issue."""
@@ -53,11 +53,9 @@ def search(query: str) -> str: # pragma: no cover
5353 name = "search" ,
5454 )
5555
56- params = template .matches (
57- "search://stick%20correcteur%20teint%C3%A9%20anti-imperfections"
58- )
56+ params = template .matches ("search://stick%20correcteur%20teint%C3%A9%20anti-imperfections" )
5957 assert params is not None
60- assert params ["query" ] == "stick correcteur teinte anti-imperfections"
58+ assert params ["query" ] == "stick correcteur teinté anti-imperfections"
6159
6260 def test_template_matches_preserves_plus_sign (self ):
6361 """Test that plus sign remains as plus (not converted to space).
@@ -77,4 +75,4 @@ def search(query: str) -> str: # pragma: no cover
7775
7876 params = template .matches ("search://hello+world" )
7977 assert params is not None
80- assert params ["query" ] == "hello+world"
78+ assert params ["query" ] == "hello+world"
You can’t perform that action at this time.
0 commit comments