Skip to content

Commit 41c0262

Browse files
authored
refactor: polish sample (#9)
1 parent 43d9b70 commit 41c0262

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

samples/server/whoami.py

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
"""
2+
An FastMCP server that provides a "WhoAmI" tool to return the current user's information.
3+
4+
This server is compatible with OpenID Connect (OIDC) providers and uses the `mcpauth` library
5+
to handle authorization. Please check https://mcp-auth.dev/docs/tutorials/whoami for more
6+
information on how to use this server.
7+
"""
8+
19
import os
210
from typing import Any
311
from mcp.server.fastmcp import FastMCP
@@ -41,6 +49,11 @@ def whoami() -> dict[str, Any]:
4149

4250

4351
def verify_access_token(token: str) -> AuthInfo:
52+
"""
53+
Verifies the provided Bearer token by fetching user information from the authorization server.
54+
If the token is valid, it returns an `AuthInfo` object containing the user's information.
55+
"""
56+
4457
endpoint = auth_server_config.metadata.userinfo_endpoint
4558
if not endpoint:
4659
raise ValueError(
@@ -50,37 +63,41 @@ def verify_access_token(token: str) -> AuthInfo:
5063
try:
5164
response = requests.get(
5265
endpoint,
53-
headers={"Authorization": f"Bearer {token}"},
66+
headers={
67+
"Authorization": f"Bearer {token}"
68+
}, # Standard Bearer token header
5469
)
55-
response.raise_for_status()
56-
json = response.json()
70+
response.raise_for_status() # Ensure we raise an error for HTTP errors
71+
json = response.json() # Parse the JSON response
5772
return AuthInfo(
5873
token=token,
59-
subject=json.get("sub"),
60-
issuer=auth_issuer,
61-
claims=json,
74+
subject=json.get(
75+
"sub"
76+
), # 'sub' is a standard claim for the subject (user's ID)
77+
issuer=auth_issuer, # Use the configured issuer
78+
claims=json, # Include all claims (JSON fields) returned by the userinfo endpoint
6279
)
80+
# `AuthInfo` is a Pydantic model, so validation errors usually mean the response didn't match
81+
# the expected structure
6382
except pydantic.ValidationError as e:
6483
raise MCPAuthTokenVerificationException(
6584
MCPAuthTokenVerificationExceptionCode.INVALID_TOKEN,
6685
cause=e,
6786
)
87+
# Handle other exceptions that may occur during the request
6888
except Exception as e:
6989
raise MCPAuthTokenVerificationException(
7090
MCPAuthTokenVerificationExceptionCode.TOKEN_VERIFICATION_FAILED,
7191
cause=e,
7292
)
7393

7494

95+
bearer_auth = Middleware(mcp_auth.bearer_auth_middleware(verify_access_token))
7596
app = Starlette(
7697
routes=[
98+
# Add the metadata route (`/.well-known/oauth-authorization-server`)
7799
mcp_auth.metadata_route(),
78-
Mount(
79-
"/",
80-
app=mcp.sse_app(),
81-
middleware=[
82-
Middleware(mcp_auth.bearer_auth_middleware(verify_access_token))
83-
],
84-
),
85-
]
100+
# Protect the MCP server with the Bearer auth middleware
101+
Mount("/", app=mcp.sse_app(), middleware=[bearer_auth]),
102+
],
86103
)

0 commit comments

Comments
 (0)