Skip to content

Commit 855a2e6

Browse files
fix(auth): allow requested scopes without registered scope
1 parent 3a6f299 commit 855a2e6

2 files changed

Lines changed: 44 additions & 2 deletions

File tree

src/mcp/shared/auth.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,9 @@ def validate_scope(self, requested_scope: str | None) -> list[str] | None:
109109
if requested_scope is None:
110110
return None
111111
requested_scopes = requested_scope.split(" ")
112-
allowed_scopes = [] if self.scope is None else self.scope.split(" ")
112+
if self.scope is None:
113+
return requested_scopes
114+
allowed_scopes = self.scope.split(" ")
113115
for scope in requested_scopes:
114116
if scope not in allowed_scopes:
115117
raise InvalidScopeError(f"Client was not registered with scope {scope}")

tests/shared/test_auth.py

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import pytest
44
from pydantic import ValidationError
55

6-
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata
6+
from mcp.shared.auth import InvalidScopeError, OAuthClientInformationFull, OAuthClientMetadata, OAuthMetadata
77

88

99
def test_oauth():
@@ -138,3 +138,43 @@ def test_invalid_non_empty_url_still_rejected():
138138
}
139139
with pytest.raises(ValidationError):
140140
OAuthClientMetadata.model_validate(data)
141+
142+
143+
def test_validate_scope_returns_none_when_no_scope_requested():
144+
client = OAuthClientInformationFull(
145+
client_id="client",
146+
redirect_uris=["https://example.com/callback"],
147+
scope="read write",
148+
)
149+
150+
assert client.validate_scope(None) is None
151+
152+
153+
def test_validate_scope_allows_registered_scopes():
154+
client = OAuthClientInformationFull(
155+
client_id="client",
156+
redirect_uris=["https://example.com/callback"],
157+
scope="read write",
158+
)
159+
160+
assert client.validate_scope("read write") == ["read", "write"]
161+
162+
163+
def test_validate_scope_rejects_unregistered_scopes():
164+
client = OAuthClientInformationFull(
165+
client_id="client",
166+
redirect_uris=["https://example.com/callback"],
167+
scope="read",
168+
)
169+
170+
with pytest.raises(InvalidScopeError, match="Client was not registered with scope write"):
171+
client.validate_scope("write")
172+
173+
174+
def test_validate_scope_allows_requested_scopes_when_registered_scope_omitted():
175+
client = OAuthClientInformationFull(
176+
client_id="client",
177+
redirect_uris=["https://example.com/callback"],
178+
)
179+
180+
assert client.validate_scope("read write") == ["read", "write"]

0 commit comments

Comments
 (0)