|
9 | 9 |
|
10 | 10 | import re |
11 | 11 | from typing import Annotated, Any, Literal |
12 | | -from urllib.parse import urlsplit |
| 12 | +from urllib.parse import unquote, urlsplit |
13 | 13 |
|
14 | 14 | from mcp_types import CacheableResult, PaginatedRequestParams, PaginatedResult, Request, RequestParams, Resource |
15 | 15 | from pydantic import AfterValidator, BaseModel, ConfigDict, Field, model_validator |
@@ -250,7 +250,8 @@ def _validate_resource_uri_in_skill(skill_uri: str, resource_uri: str) -> None: |
250 | 250 | root = skill_parts.path[: -len("/SKILL.md")] |
251 | 251 | if resource_parts.path != skill_parts.path and not resource_parts.path.startswith(root + "/"): |
252 | 252 | raise ValueError(f"resource URI {resource_uri!r} is outside the skill root {skill_uri!r}") |
253 | | - if any(segment in (".", "..") for segment in resource_parts.path.split("/")): |
| 253 | + unquoted_path = unquote(resource_parts.path) |
| 254 | + if any(segment in (".", "..") for segment in unquoted_path.split("/")): |
254 | 255 | raise ValueError(f"resource URI {resource_uri!r} contains a traversal segment") |
255 | 256 |
|
256 | 257 |
|
@@ -290,7 +291,13 @@ def validate_directory_result(uri: str, result: ReadDirectoryResult) -> None: |
290 | 291 | if child.scheme != scheme or child.netloc != netloc: |
291 | 292 | raise ValueError(f"resource {resource.uri!r} is not a child of directory {uri!r}") |
292 | 293 | relative = child.path.removeprefix(prefix) |
293 | | - if relative == child.path or not relative or "/" in relative or relative in (".", ".."): |
| 294 | + unquoted_relative = unquote(relative) |
| 295 | + if ( |
| 296 | + relative == child.path |
| 297 | + or not relative |
| 298 | + or "/" in unquoted_relative |
| 299 | + or unquoted_relative in (".", "..") |
| 300 | + ): |
294 | 301 | raise ValueError(f"resource {resource.uri!r} is not a direct child of directory {uri!r}") |
295 | 302 | if resource.uri in seen_uris: |
296 | 303 | raise ValueError(f"directory {uri!r} contains a duplicate child {resource.uri!r}") |
|
0 commit comments