Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 68fcf92

Browse filesBrowse files
hmwildermuthdsp-ant
authored andcommitted
Update URL validation to allow file and other nonstandard schemas
1 parent 701a86e commit 68fcf92
Copy full SHA for 68fcf92

File tree

Expand file treeCollapse file tree

2 files changed

+19
-12
lines changed
Filter options
Expand file treeCollapse file tree

2 files changed

+19
-12
lines changed

‎examples/servers/simple-resource/mcp_simple_resource/server.py

Copy file name to clipboardExpand all lines: examples/servers/simple-resource/mcp_simple_resource/server.py
+3-4Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import click
33
import mcp.types as types
44
from mcp.server.lowlevel import Server
5-
from pydantic import AnyUrl
5+
from pydantic import FileUrl
66

77
SAMPLE_RESOURCES = {
88
"greeting": "Hello! This is a sample text resource.",
@@ -26,7 +26,7 @@ def main(port: int, transport: str) -> int:
2626
async def list_resources() -> list[types.Resource]:
2727
return [
2828
types.Resource(
29-
uri=AnyUrl(f"file:///{name}.txt"),
29+
uri=FileUrl(f"file:///{name}.txt"),
3030
name=name,
3131
description=f"A sample text resource named {name}",
3232
mimeType="text/plain",
@@ -35,8 +35,7 @@ async def list_resources() -> list[types.Resource]:
3535
]
3636

3737
@app.read_resource()
38-
async def read_resource(uri: AnyUrl) -> str | bytes:
39-
assert uri.path is not None
38+
async def read_resource(uri: FileUrl) -> str | bytes:
4039
name = uri.path.replace(".txt", "").lstrip("/")
4140

4241
if name not in SAMPLE_RESOURCES:

‎src/mcp/types.py

Copy file name to clipboardExpand all lines: src/mcp/types.py
+16-8Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,15 @@
1-
from typing import Annotated, Any, Callable, Generic, Literal, TypeAlias, TypeVar
1+
from typing import (
2+
Annotated,
3+
Any,
4+
Callable,
5+
Generic,
6+
Literal,
7+
TypeAlias,
8+
TypeVar,
9+
)
210

311
from pydantic import BaseModel, ConfigDict, Field, FileUrl, RootModel
4-
from pydantic.networks import AnyUrl
12+
from pydantic.networks import AnyUrl, UrlConstraints
513

614
"""
715
Model Context Protocol bindings for Python
@@ -353,7 +361,7 @@ class Annotations(BaseModel):
353361
class Resource(BaseModel):
354362
"""A known resource that the server is capable of reading."""
355363

356-
uri: AnyUrl
364+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
357365
"""The URI of this resource."""
358366
name: str
359367
"""A human-readable name for this resource."""
@@ -415,7 +423,7 @@ class ListResourceTemplatesResult(PaginatedResult):
415423
class ReadResourceRequestParams(RequestParams):
416424
"""Parameters for reading a resource."""
417425

418-
uri: AnyUrl
426+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
419427
"""
420428
The URI of the resource to read. The URI can use any protocol; it is up to the
421429
server how to interpret it.
@@ -433,7 +441,7 @@ class ReadResourceRequest(Request):
433441
class ResourceContents(BaseModel):
434442
"""The contents of a specific resource or sub-resource."""
435443

436-
uri: AnyUrl
444+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
437445
"""The URI of this resource."""
438446
mimeType: str | None = None
439447
"""The MIME type of this resource, if known."""
@@ -476,7 +484,7 @@ class ResourceListChangedNotification(Notification):
476484
class SubscribeRequestParams(RequestParams):
477485
"""Parameters for subscribing to a resource."""
478486

479-
uri: AnyUrl
487+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
480488
"""
481489
The URI of the resource to subscribe to. The URI can use any protocol; it is up to
482490
the server how to interpret it.
@@ -497,7 +505,7 @@ class SubscribeRequest(Request):
497505
class UnsubscribeRequestParams(RequestParams):
498506
"""Parameters for unsubscribing from a resource."""
499507

500-
uri: AnyUrl
508+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
501509
"""The URI of the resource to unsubscribe from."""
502510
model_config = ConfigDict(extra="allow")
503511

@@ -515,7 +523,7 @@ class UnsubscribeRequest(Request):
515523
class ResourceUpdatedNotificationParams(NotificationParams):
516524
"""Parameters for resource update notifications."""
517525

518-
uri: AnyUrl
526+
uri: Annotated[AnyUrl, UrlConstraints(host_required=False)]
519527
"""
520528
The URI of the resource that has been updated. This might be a sub-resource of the
521529
one that the client actually subscribed to.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.