Skip to content

Commit a41187e

Browse files
committed
merge with recent branch
1 parent 482c05e commit a41187e

File tree

3 files changed

+33
-4
lines changed

3 files changed

+33
-4
lines changed

examples/servers/simple-auth/mcp_simple_auth/github_oauth_provider.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ async def revoke_token(self, token: str, token_type_hint: str | None = None) ->
245245
if token in self.tokens:
246246
del self.tokens[token]
247247

248+
async def exchange_client_credentials(
249+
self,
250+
client: OAuthClientInformationFull,
251+
scopes: list[str],
252+
) -> OAuthToken:
253+
"""Client credentials flow is not supported in this example."""
254+
raise NotImplementedError("client_credentials not supported")
255+
256+
async def exchange_token(
257+
self,
258+
client: OAuthClientInformationFull,
259+
subject_token: str,
260+
subject_token_type: str,
261+
actor_token: str | None,
262+
actor_token_type: str | None,
263+
scope: list[str] | None,
264+
audience: str | None,
265+
resource: str | None,
266+
) -> OAuthToken:
267+
"""Token exchange is not supported in this example."""
268+
raise NotImplementedError("token_exchange not supported")
269+
248270
async def get_github_user_info(self, mcp_token: str) -> dict[str, Any]:
249271
"""Get GitHub user info using MCP token."""
250272
github_token = self.token_mapping.get(mcp_token)

src/mcp/client/auth.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,15 +119,15 @@ def update_token_expiry(self, token: OAuthToken) -> None:
119119
self.token_expiry_time = None
120120

121121
def is_token_valid(self) -> bool:
122-
"""Check if current token is valid."""
122+
"""Check if the current token is valid."""
123123
return bool(
124124
self.current_tokens
125125
and self.current_tokens.access_token
126126
and (not self.token_expiry_time or time.time() <= self.token_expiry_time)
127127
)
128128

129129
def can_refresh_token(self) -> bool:
130-
"""Check if token can be refreshed."""
130+
"""Check if the token can be refreshed."""
131131
return bool(self.current_tokens and self.current_tokens.refresh_token and self.client_info)
132132

133133
def clear_tokens(self) -> None:
@@ -496,12 +496,14 @@ def __init__(
496496
server_url: str,
497497
client_metadata: OAuthClientMetadata,
498498
storage: TokenStorage,
499+
resource: str | None = None,
499500
timeout: float = 300.0,
500501
):
501502
self.server_url = server_url
502503
self.client_metadata = client_metadata
503504
self.storage = storage
504505
self.timeout = timeout
506+
self.resource = resource or resource_url_from_server_url(server_url)
505507

506508
self._current_tokens: OAuthToken | None = None
507509
self._metadata: OAuthMetadata | None = None
@@ -626,6 +628,7 @@ async def _request_token(self) -> None:
626628
token_data = {
627629
"grant_type": "client_credentials",
628630
"client_id": client_info.client_id,
631+
"resource": self.resource,
629632
}
630633

631634
if client_info.client_secret:
@@ -692,7 +695,7 @@ def __init__(
692695
resource: str | None = None,
693696
timeout: float = 300.0,
694697
):
695-
super().__init__(server_url, client_metadata, storage, timeout)
698+
super().__init__(server_url, client_metadata, storage, resource, timeout)
696699
self.subject_token_supplier = subject_token_supplier
697700
self.subject_token_type = subject_token_type
698701
self.actor_token_supplier = actor_token_supplier

tests/client/test_auth.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def oauth_client_info():
132132
def oauth_token():
133133
return OAuthToken(
134134
access_token="test_access_token",
135-
token_type="bearer",
135+
token_type="Bearer",
136136
expires_in=3600,
137137
refresh_token="test_refresh_token",
138138
scope="read write",
@@ -419,6 +419,8 @@ async def test_request_token_success(
419419
await client_credentials_provider.ensure_token()
420420

421421
mock_client.post.assert_called_once()
422+
args, kwargs = mock_client.post.call_args
423+
assert kwargs["data"]["resource"] == "https://api.example.com/v1/mcp"
422424
assert client_credentials_provider._current_tokens.access_token == oauth_token.access_token
423425

424426
@pytest.mark.anyio
@@ -466,4 +468,6 @@ async def test_request_token_success(
466468
await token_exchange_provider.ensure_token()
467469

468470
mock_client.post.assert_called_once()
471+
args, kwargs = mock_client.post.call_args
472+
assert kwargs["data"]["resource"] == "https://api.example.com/v1/mcp"
469473
assert token_exchange_provider._current_tokens.access_token == oauth_token.access_token

0 commit comments

Comments
 (0)