Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
2e6dbad
1
Parent(s): 24b96b7
Improve matching logic for quoted chars
Browse files
src/fastmcp/resources/template.py
CHANGED
|
@@ -6,6 +6,7 @@ import inspect
|
|
| 6 |
import re
|
| 7 |
from collections.abc import Callable
|
| 8 |
from typing import Annotated, Any
|
|
|
|
| 9 |
|
| 10 |
from mcp.types import ResourceTemplate as MCPResourceTemplate
|
| 11 |
from pydantic import (
|
|
@@ -38,7 +39,9 @@ def build_regex(template: str) -> re.Pattern:
|
|
| 38 |
def match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None:
|
| 39 |
regex = build_regex(uri_template)
|
| 40 |
match = regex.match(uri)
|
| 41 |
-
|
|
|
|
|
|
|
| 42 |
|
| 43 |
|
| 44 |
class MyModel(BaseModel):
|
|
|
|
| 6 |
import re
|
| 7 |
from collections.abc import Callable
|
| 8 |
from typing import Annotated, Any
|
| 9 |
+
from urllib.parse import unquote
|
| 10 |
|
| 11 |
from mcp.types import ResourceTemplate as MCPResourceTemplate
|
| 12 |
from pydantic import (
|
|
|
|
| 39 |
def match_uri_template(uri: str, uri_template: str) -> dict[str, str] | None:
|
| 40 |
regex = build_regex(uri_template)
|
| 41 |
match = regex.match(uri)
|
| 42 |
+
if match:
|
| 43 |
+
return {k: unquote(v) for k, v in match.groupdict().items()}
|
| 44 |
+
return None
|
| 45 |
|
| 46 |
|
| 47 |
class MyModel(BaseModel):
|
tests/resources/test_resource_template.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
| 1 |
import json
|
|
|
|
| 2 |
|
| 3 |
import pytest
|
| 4 |
from pydantic import BaseModel
|
|
@@ -312,6 +313,18 @@ class TestMatchUriTemplate:
|
|
| 312 |
("test://foo/123", {"x": "foo", "y": "123"}),
|
| 313 |
("test://bar/456", {"x": "bar", "y": "456"}),
|
| 314 |
("test://foo/bar", {"x": "foo", "y": "bar"}),
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 315 |
("prefix+test://foo/123", None),
|
| 316 |
("test://foo", None),
|
| 317 |
("other://foo/123", None),
|
|
|
|
| 1 |
import json
|
| 2 |
+
from urllib.parse import quote
|
| 3 |
|
| 4 |
import pytest
|
| 5 |
from pydantic import BaseModel
|
|
|
|
| 313 |
("test://foo/123", {"x": "foo", "y": "123"}),
|
| 314 |
("test://bar/456", {"x": "bar", "y": "456"}),
|
| 315 |
("test://foo/bar", {"x": "foo", "y": "bar"}),
|
| 316 |
+
("test://foo/bar/baz", None),
|
| 317 |
+
("test://foo/email@domain.com", {"x": "foo", "y": "email@domain.com"}),
|
| 318 |
+
("test://two words/foo", {"x": "two words", "y": "foo"}),
|
| 319 |
+
("test://two.words/foo+bar", {"x": "two.words", "y": "foo+bar"}),
|
| 320 |
+
(
|
| 321 |
+
f"test://escaped{quote('/', safe='')}word/bar",
|
| 322 |
+
{"x": "escaped/word", "y": "bar"},
|
| 323 |
+
),
|
| 324 |
+
(
|
| 325 |
+
f"test://escaped{quote('{', safe='')}x{quote('}', safe='')}word/bar",
|
| 326 |
+
{"x": "escaped{x}word", "y": "bar"},
|
| 327 |
+
),
|
| 328 |
("prefix+test://foo/123", None),
|
| 329 |
("test://foo", None),
|
| 330 |
("other://foo/123", None),
|