Skip to content

Commit 00145de

Browse files
committed
wip
1 parent da2294b commit 00145de

File tree

16 files changed

+420
-386
lines changed

16 files changed

+420
-386
lines changed

CLAUDE.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This document contains critical information about working with this codebase. Fo
1919
- Line length: 88 chars maximum
2020

2121
3. Testing Requirements
22-
- Framework: `uv run pytest`
22+
- Framework: `uv run --frozen pytest`
2323
- Async testing: use anyio, not asyncio
2424
- Coverage: test edge cases and errors
2525
- New features require tests
@@ -54,9 +54,9 @@ This document contains critical information about working with this codebase. Fo
5454
## Code Formatting
5555

5656
1. Ruff
57-
- Format: `uv run ruff format .`
58-
- Check: `uv run ruff check .`
59-
- Fix: `uv run ruff check . --fix`
57+
- Format: `uv run --frozen ruff format .`
58+
- Check: `uv run --frozen ruff check .`
59+
- Fix: `uv run --frozen ruff check . --fix`
6060
- Critical issues:
6161
- Line length (88 chars)
6262
- Import sorting (I001)
@@ -67,7 +67,7 @@ This document contains critical information about working with this codebase. Fo
6767
- Imports: split into multiple lines
6868

6969
2. Type Checking
70-
- Tool: `uv run pyright`
70+
- Tool: `uv run --frozen pyright`
7171
- Requirements:
7272
- Explicit None checks for Optional
7373
- Type narrowing for strings

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,9 @@ include = ["src/mcp", "tests"]
6767
venvPath = "."
6868
venv = ".venv"
6969

70+
[tool.pytest.ini_options]
71+
markers = ["anyio"]
72+
7073
[tool.ruff.lint]
7174
select = ["E", "F", "I"]
7275
ignore = []

src/mcp/server/auth/handlers/authorize.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99
from typing import Any, Callable, Dict, List, Literal, Optional
1010
from urllib.parse import urlencode, parse_qs
1111

12-
from fastapi import Request, Response
12+
from starlette.requests import Request
13+
from starlette.responses import JSONResponse, RedirectResponse, Response
1314
from pydantic import AnyHttpUrl, AnyUrl, BaseModel, Field, ValidationError
1415
from pydantic_core import Url
15-
from starlette.responses import JSONResponse, RedirectResponse
1616

1717
from mcp.server.auth.errors import (
1818
InvalidClientError,
@@ -81,9 +81,14 @@ async def authorization_handler(request: Request) -> Response:
8181
# Validate request parameters
8282
try:
8383
if request.method == "GET":
84-
auth_request = AuthorizationRequest.model_validate(request.query_params)
84+
# Convert query_params to dict for pydantic validation
85+
params = dict(request.query_params)
86+
auth_request = AuthorizationRequest.model_validate(params)
8587
else:
86-
auth_request = AuthorizationRequest.model_validate_json(await request.body())
88+
# Parse form data for POST requests
89+
form_data = await request.form()
90+
params = dict(form_data)
91+
auth_request = AuthorizationRequest.model_validate(params)
8792
except ValidationError as e:
8893
raise InvalidRequestError(str(e))
8994

src/mcp/server/auth/handlers/metadata.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
"""
66

77
from typing import Any, Callable, Dict, Optional
8-
from fastapi import Request, Response
9-
from starlette.responses import JSONResponse
8+
9+
from starlette.requests import Request
10+
from starlette.responses import JSONResponse, Response
1011

1112

1213
def create_metadata_handler(metadata: Dict[str, Any]) -> Callable:
@@ -19,15 +20,15 @@ def create_metadata_handler(metadata: Dict[str, Any]) -> Callable:
1920
metadata: The metadata to return in the response
2021
2122
Returns:
22-
A FastAPI route handler function
23+
A Starlette endpoint handler function
2324
"""
2425

2526
async def metadata_handler(request: Request) -> Response:
2627
"""
2728
Handler for the OAuth 2.0 Authorization Server Metadata endpoint.
2829
2930
Args:
30-
request: The FastAPI request
31+
request: The Starlette request
3132
3233
Returns:
3334
JSON response with the authorization server metadata

src/mcp/server/auth/handlers/register.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,16 @@
1010
from typing import Any, Callable, Dict, List, Optional
1111
from uuid import uuid4
1212

13-
from fastapi import Request, Response
13+
from starlette.requests import Request
14+
from starlette.responses import JSONResponse, Response
1415
from pydantic import ValidationError
15-
from starlette.responses import JSONResponse
1616

1717
from mcp.server.auth.errors import (
1818
InvalidRequestError,
1919
ServerError,
2020
OAuthError,
2121
)
22+
from mcp.server.auth.json_response import PydanticJSONResponse
2223
from mcp.server.auth.provider import OAuthRegisteredClientsStore
2324
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata
2425

@@ -31,25 +32,27 @@ def create_registration_handler(clients_store: OAuthRegisteredClientsStore, clie
3132
3233
Args:
3334
clients_store: The store for registered clients
35+
client_secret_expiry_seconds: Optional expiry time for client secrets
3436
3537
Returns:
36-
A FastAPI route handler function
38+
A Starlette endpoint handler function
3739
"""
3840

3941
async def registration_handler(request: Request) -> Response:
4042
"""
4143
Handler for the OAuth 2.0 Dynamic Client Registration endpoint.
4244
4345
Args:
44-
request: The FastAPI request
46+
request: The Starlette request
4547
4648
Returns:
4749
JSON response with client information or error
4850
"""
4951
try:
50-
# Validate client metadata
52+
# Parse request body as JSON
5153
try:
52-
client_metadata = OAuthClientMetadata.model_validate_json(await request.body())
54+
body = await request.json()
55+
client_metadata = OAuthClientMetadata.model_validate(body)
5356
except ValidationError as e:
5457
raise InvalidRequestError(f"Invalid client metadata: {str(e)}")
5558

@@ -90,8 +93,8 @@ async def registration_handler(request: Request) -> Response:
9093
raise ServerError("Failed to register client")
9194

9295
# Return client information
93-
return JSONResponse(
94-
content=client.model_dump(exclude_none=True),
96+
return PydanticJSONResponse(
97+
content=client,
9598
status_code=201
9699
)
97100

src/mcp/server/auth/handlers/revoke.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,24 @@
66

77
from typing import Any, Callable, Dict, Optional
88

9-
from fastapi import Request, Response
9+
from starlette.requests import Request
10+
from starlette.responses import Response
1011
from pydantic import ValidationError
11-
from starlette.responses import JSONResponse, Response as StarletteResponse
1212

1313
from mcp.server.auth.errors import (
1414
InvalidRequestError,
1515
ServerError,
1616
OAuthError,
1717
)
18+
from mcp.server.auth.middleware import client_auth
1819
from mcp.server.auth.provider import OAuthServerProvider
1920
from mcp.shared.auth import OAuthClientInformationFull, OAuthTokenRevocationRequest
21+
from mcp.server.auth.middleware.client_auth import ClientAuthRequest, ClientAuthenticator
2022

23+
class RevocationRequest(OAuthTokenRevocationRequest, ClientAuthRequest):
24+
pass
2125

22-
def create_revocation_handler(provider: OAuthServerProvider) -> Callable:
26+
def create_revocation_handler(provider: OAuthServerProvider, client_authenticator: ClientAuthenticator) -> Callable:
2327
"""
2428
Create a handler for OAuth 2.0 Token Revocation.
2529
@@ -29,25 +33,27 @@ def create_revocation_handler(provider: OAuthServerProvider) -> Callable:
2933
provider: The OAuth server provider
3034
3135
Returns:
32-
A FastAPI route handler function
36+
A Starlette endpoint handler function
3337
"""
3438

35-
async def revocation_handler(request: Request, client_auth: OAuthClientInformationFull) -> Response:
39+
async def revocation_handler(request: Request) -> Response:
3640
"""
3741
Handler for the OAuth 2.0 Token Revocation endpoint.
3842
"""
39-
# Validate revocation request
4043
try:
41-
revocation_request = OAuthTokenRevocationRequest.model_validate_json(await request.body())
44+
revocation_request = RevocationRequest.model_validate_json(await request.body())
4245
except ValidationError as e:
43-
raise InvalidRequestError(str(e))
46+
raise InvalidRequestError(f"Invalid request body: {e}")
47+
48+
# Authenticate client
49+
client_auth_result = await client_authenticator(revocation_request)
4450

4551
# Revoke token
4652
if provider.revoke_token:
47-
await provider.revoke_token(client_auth, revocation_request)
53+
await provider.revoke_token(client_auth_result, revocation_request)
4854

4955
# Return successful empty response
50-
return StarletteResponse(
56+
return Response(
5157
status_code=200,
5258
headers={
5359
"Cache-Control": "no-store",

0 commit comments

Comments
 (0)