Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/mcp/shared/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,9 @@ def validate_scope(self, requested_scope: str | None) -> list[str] | None:
if requested_scope is None:
return None
requested_scopes = requested_scope.split(" ")
allowed_scopes = [] if self.scope is None else self.scope.split(" ")
if self.scope is None:
return requested_scopes
allowed_scopes = self.scope.split(" ")
for scope in requested_scopes:
if scope not in allowed_scopes:
raise InvalidScopeError(f"Client was not registered with scope {scope}")
Expand Down
42 changes: 41 additions & 1 deletion tests/shared/test_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import pytest
from pydantic import ValidationError

from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata
from mcp.shared.auth import InvalidScopeError, OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata


def test_oauth():
Expand Down Expand Up @@ -138,3 +138,43 @@ def test_invalid_non_empty_url_still_rejected():
}
with pytest.raises(ValidationError):
OAuthClientMetadata.model_validate(data)


def test_validate_scope_returns_none_when_no_scope_requested():
client = OAuthClientInformationFull(
client_id="client",
redirect_uris=["https://example.com/callback"],
scope="read write",
)

assert client.validate_scope(None) is None


def test_validate_scope_allows_registered_scopes():
client = OAuthClientInformationFull(
client_id="client",
redirect_uris=["https://example.com/callback"],
scope="read write",
)

assert client.validate_scope("read write") == ["read", "write"]


def test_validate_scope_rejects_unregistered_scopes():
client = OAuthClientInformationFull(
client_id="client",
redirect_uris=["https://example.com/callback"],
scope="read",
)

with pytest.raises(InvalidScopeError, match="Client was not registered with scope write"):
client.validate_scope("write")


def test_validate_scope_allows_requested_scopes_when_registered_scope_omitted():
client = OAuthClientInformationFull(
client_id="client",
redirect_uris=["https://example.com/callback"],
)

assert client.validate_scope("read write") == ["read", "write"]
Loading