|
| 1 | +"""Tests for issue #1574: Python SDK incorrectly validates Resource URIs. |
| 2 | +
|
| 3 | +The Python SDK uses Pydantic's AnyUrl for URI fields, which rejects relative paths |
| 4 | +like 'users/me' that are valid according to the MCP spec and accepted by the |
| 5 | +TypeScript SDK. |
| 6 | +
|
| 7 | +The spec defines uri fields as plain strings with no JSON Schema format validation. |
| 8 | +""" |
| 9 | + |
| 10 | +from mcp import types |
| 11 | + |
| 12 | + |
| 13 | +class TestResourceUriValidation: |
| 14 | + """Test that Resource URI fields accept all valid MCP URIs.""" |
| 15 | + |
| 16 | + def test_relative_path_uri(self): |
| 17 | + """ |
| 18 | + REPRODUCER: Relative paths like 'users/me' should be accepted. |
| 19 | +
|
| 20 | + Currently fails with: |
| 21 | + ValidationError: Input should be a valid URL, relative URL without a base |
| 22 | + """ |
| 23 | + # This should NOT raise - relative paths are valid per MCP spec |
| 24 | + resource = types.Resource(name="test", uri="users/me") |
| 25 | + assert str(resource.uri) == "users/me" |
| 26 | + |
| 27 | + def test_custom_scheme_uri(self): |
| 28 | + """Custom scheme URIs should be accepted.""" |
| 29 | + resource = types.Resource(name="test", uri="custom://resource") |
| 30 | + assert str(resource.uri) == "custom://resource" |
| 31 | + |
| 32 | + def test_file_url(self): |
| 33 | + """File URLs should be accepted.""" |
| 34 | + resource = types.Resource(name="test", uri="file:///path/to/file") |
| 35 | + assert str(resource.uri) == "file:///path/to/file" |
| 36 | + |
| 37 | + def test_http_url(self): |
| 38 | + """HTTP URLs should be accepted.""" |
| 39 | + resource = types.Resource(name="test", uri="https://example.com/resource") |
| 40 | + assert str(resource.uri) == "https://example.com/resource" |
| 41 | + |
| 42 | + |
| 43 | +class TestReadResourceRequestParamsUri: |
| 44 | + """Test that ReadResourceRequestParams.uri accepts all valid MCP URIs.""" |
| 45 | + |
| 46 | + def test_relative_path_uri(self): |
| 47 | + """Relative paths should be accepted in read requests.""" |
| 48 | + params = types.ReadResourceRequestParams(uri="users/me") |
| 49 | + assert str(params.uri) == "users/me" |
| 50 | + |
| 51 | + |
| 52 | +class TestResourceContentsUri: |
| 53 | + """Test that ResourceContents.uri accepts all valid MCP URIs.""" |
| 54 | + |
| 55 | + def test_relative_path_uri(self): |
| 56 | + """Relative paths should be accepted in resource contents.""" |
| 57 | + contents = types.TextResourceContents(uri="users/me", text="content") |
| 58 | + assert str(contents.uri) == "users/me" |
| 59 | + |
| 60 | + |
| 61 | +class TestSubscribeRequestParamsUri: |
| 62 | + """Test that SubscribeRequestParams.uri accepts all valid MCP URIs.""" |
| 63 | + |
| 64 | + def test_relative_path_uri(self): |
| 65 | + """Relative paths should be accepted in subscribe requests.""" |
| 66 | + params = types.SubscribeRequestParams(uri="users/me") |
| 67 | + assert str(params.uri) == "users/me" |
| 68 | + |
| 69 | + |
| 70 | +class TestUnsubscribeRequestParamsUri: |
| 71 | + """Test that UnsubscribeRequestParams.uri accepts all valid MCP URIs.""" |
| 72 | + |
| 73 | + def test_relative_path_uri(self): |
| 74 | + """Relative paths should be accepted in unsubscribe requests.""" |
| 75 | + params = types.UnsubscribeRequestParams(uri="users/me") |
| 76 | + assert str(params.uri) == "users/me" |
| 77 | + |
| 78 | + |
| 79 | +class TestResourceUpdatedNotificationParamsUri: |
| 80 | + """Test that ResourceUpdatedNotificationParams.uri accepts all valid MCP URIs.""" |
| 81 | + |
| 82 | + def test_relative_path_uri(self): |
| 83 | + """Relative paths should be accepted in resource updated notifications.""" |
| 84 | + params = types.ResourceUpdatedNotificationParams(uri="users/me") |
| 85 | + assert str(params.uri) == "users/me" |
0 commit comments