Skip to content

Commit 5a752ad

Browse files
author
Tapan Chugh
committed
refactor: Make URI fields required and block all MCP scheme usage in resources
- Changed Tool and Prompt URI fields from optional to required (auto-generated) - Updated Resource validator to block any URI using the MCP scheme (mcp://) - Removed unnecessary None checks in URI validators since fields are now required - Updated tests to match new error message This provides stronger type safety and clearer API contracts while maintaining backward compatibility through auto-generation.
1 parent d360e8d commit 5a752ad

File tree

2 files changed

+14
-18
lines changed

2 files changed

+14
-18
lines changed

src/mcp/types.py

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -440,12 +440,10 @@ class Resource(BaseMetadata):
440440

441441
@model_validator(mode="after")
442442
def validate_uri_scheme(self) -> "Resource":
443-
"""Ensure resource URI doesn't use reserved schemes."""
443+
"""Ensure resource URI doesn't use reserved MCP scheme."""
444444
uri_str = str(self.uri)
445-
if uri_str.startswith((TOOL_SCHEME, PROMPT_SCHEME)):
446-
raise ValueError(
447-
f"Resource URI cannot use reserved schemes '{TOOL_SCHEME}' or '{PROMPT_SCHEME}', got: {self.uri}"
448-
)
445+
if uri_str.startswith(f"{MCP_SCHEME}://"):
446+
raise ValueError(f"Resource URI cannot use reserved MCP scheme '{MCP_SCHEME}://', got: {self.uri}")
449447
return self
450448

451449

@@ -642,7 +640,7 @@ class PromptArgument(BaseModel):
642640
class Prompt(BaseMetadata):
643641
"""A prompt or prompt template that the server offers."""
644642

645-
uri: Annotated[AnyUrl, UrlConstraints(allowed_schemes=[MCP_SCHEME], host_required=False)] | None = None
643+
uri: Annotated[AnyUrl, UrlConstraints(allowed_schemes=[MCP_SCHEME], host_required=False)]
646644
"""URI for the prompt. Auto-generated if not provided."""
647645
description: str | None = None
648646
"""An optional description of what this prompt provides."""
@@ -664,10 +662,9 @@ def __init__(self, **data: Any) -> None:
664662
@model_validator(mode="after")
665663
def validate_prompt_uri(self) -> "Prompt":
666664
"""Validate that prompt URI starts with the correct prefix."""
667-
if self.uri is not None:
668-
uri_str = str(self.uri)
669-
if not uri_str.startswith(f"{PROMPT_SCHEME}/"):
670-
raise ValueError(f"Prompt URI must start with {PROMPT_SCHEME}/")
665+
uri_str = str(self.uri)
666+
if not uri_str.startswith(f"{PROMPT_SCHEME}/"):
667+
raise ValueError(f"Prompt URI must start with {PROMPT_SCHEME}/")
671668
return self
672669

673670

@@ -878,7 +875,7 @@ class ToolAnnotations(BaseModel):
878875
class Tool(BaseMetadata):
879876
"""Definition for a tool the client can call."""
880877

881-
uri: Annotated[AnyUrl, UrlConstraints(allowed_schemes=[MCP_SCHEME], host_required=False)] | None = None
878+
uri: Annotated[AnyUrl, UrlConstraints(allowed_schemes=[MCP_SCHEME], host_required=False)]
882879
"""URI for the tool. Auto-generated if not provided."""
883880
description: str | None = None
884881
"""A human-readable description of the tool."""
@@ -907,10 +904,9 @@ def __init__(self, **data: Any) -> None:
907904
@model_validator(mode="after")
908905
def validate_tool_uri(self) -> "Tool":
909906
"""Validate that tool URI starts with the correct prefix."""
910-
if self.uri is not None:
911-
uri_str = str(self.uri)
912-
if not uri_str.startswith(f"{TOOL_SCHEME}/"):
913-
raise ValueError(f"Tool URI must start with {TOOL_SCHEME}/")
907+
uri_str = str(self.uri)
908+
if not uri_str.startswith(f"{TOOL_SCHEME}/"):
909+
raise ValueError(f"Tool URI must start with {TOOL_SCHEME}/")
914910
return self
915911

916912

tests/test_types.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@ def test_resource_uri():
5858
assert resource.name == "test"
5959
assert str(resource.uri) == "file://test.txt/" # AnyUrl adds trailing slash
6060

61-
# Should reject TOOL_SCHEME and PROMPT_SCHEME schemes
62-
with pytest.raises(ValueError, match="reserved schemes"):
61+
# Should reject MCP scheme
62+
with pytest.raises(ValueError, match="reserved MCP scheme"):
6363
Resource(name="test", uri=AnyUrl(f"{TOOL_SCHEME}/test"))
6464

65-
with pytest.raises(ValueError, match="reserved schemes"):
65+
with pytest.raises(ValueError, match="reserved MCP scheme"):
6666
Resource(name="test", uri=AnyUrl(f"{PROMPT_SCHEME}/test"))
6767

6868

0 commit comments

Comments
 (0)