|
13 | 13 |
|
14 | 14 | async def probe_mcp_oauth_and_raise_401( |
15 | 15 | url: str, |
16 | | - chain_from: Optional[BaseException] = None, |
| 16 | + authorization: Optional[str] = None, |
17 | 17 | ) -> None: |
18 | | - """Probe MCP endpoint and raise 401 so the client can perform OAuth. |
| 18 | + """Probe MCP endpoint and raise 401 only when the server responds with 401. |
19 | 19 |
|
20 | | - Performs an async GET to the given URL to obtain a WWW-Authenticate header, |
21 | | - then raises HTTPException with status 401 and that header. If the probe |
22 | | - fails (connection error, timeout), raises 401 without the header. |
| 20 | + Performs a GET to the given URL with the optional Authorization header. |
| 21 | + If the response status is 401, raises HTTPException with status 401 and |
| 22 | + WWW-Authenticate header when present. Otherwise returns without raising. |
23 | 23 |
|
24 | 24 | Args: |
25 | 25 | url: MCP server URL to probe. |
| 26 | + authorization: Optional Authorization header value (e.g. "Bearer <token>"). |
26 | 27 | chain_from: Exception to chain the HTTPException from when |
27 | | - the probe succeeds (e.g. the original AuthenticationError). |
| 28 | + the server returns 401 (e.g. the original AuthenticationError). |
28 | 29 |
|
29 | 30 | Returns: |
30 | | - None. Always raises an HTTPException. |
| 31 | + None. Raises only when the server responds with 401. |
31 | 32 |
|
32 | 33 | Raises: |
33 | | - HTTPException: 401 with WWW-Authenticate when the probe succeeds, or |
34 | | - 401 without the header when the probe fails. |
| 34 | + HTTPException: 401 with WWW-Authenticate when the server returns 401. |
35 | 35 | """ |
36 | 36 | cause = f"MCP server at {url} requires OAuth" |
37 | 37 | error_response = UnauthorizedResponse(cause=cause) |
| 38 | + headers: Optional[dict[str, str]] = ( |
| 39 | + {"Authorization": authorization} if authorization is not None else None |
| 40 | + ) |
38 | 41 | try: |
39 | 42 | timeout = aiohttp.ClientTimeout(total=10) |
40 | 43 | async with aiohttp.ClientSession(timeout=timeout) as session: |
41 | | - async with session.get(url) as resp: |
| 44 | + async with session.get(url, headers=headers) as resp: |
| 45 | + print(resp.status) |
| 46 | + if resp.status != 401: |
| 47 | + return |
42 | 48 | www_auth = resp.headers.get("WWW-Authenticate") |
43 | 49 | if www_auth is None: |
44 | 50 | logger.warning("No WWW-Authenticate header received from %s", url) |
45 | | - raise HTTPException(**error_response.model_dump()) from chain_from |
| 51 | + raise HTTPException(**error_response.model_dump()) |
46 | 52 | raise HTTPException( |
47 | 53 | **error_response.model_dump(), |
48 | 54 | headers={"WWW-Authenticate": www_auth}, |
49 | | - ) from chain_from |
| 55 | + ) |
50 | 56 | except (aiohttp.ClientError, TimeoutError) as probe_err: |
51 | 57 | logger.warning("OAuth probe failed for %s: %s", url, probe_err) |
52 | | - raise HTTPException(**error_response.model_dump()) from probe_err |
| 58 | + # Only raise on 401; connection/timeout are not 401, so do not raise |
0 commit comments