1616from mcp .shared .inbound import MCP_PROTOCOL_VERSION_HEADER
1717
1818
19+ def _split_www_authenticate_segments (header_value : str ) -> list [str ]:
20+ """Split a WWW-Authenticate header on top-level commas."""
21+ segments : list [str ] = []
22+ current : list [str ] = []
23+ in_quotes = False
24+
25+ for char in header_value :
26+ if char == '"' :
27+ in_quotes = not in_quotes
28+ if char == "," and not in_quotes :
29+ segment = "" .join (current ).strip ()
30+ if segment :
31+ segments .append (segment )
32+ current = []
33+ continue
34+ current .append (char )
35+
36+ tail = "" .join (current ).strip ()
37+ if tail :
38+ segments .append (tail )
39+ return segments
40+
41+
42+ def _extract_bearer_auth_params (www_auth_header : str ) -> str | None :
43+ """Return the auth-param portion of the first Bearer challenge."""
44+ segments = _split_www_authenticate_segments (www_auth_header )
45+ collecting = False
46+ auth_params : list [str ] = []
47+
48+ for segment in segments :
49+ scheme , separator , remainder = segment .partition (" " )
50+ if scheme .lower () == "bearer" and separator :
51+ collecting = True
52+ auth_params = [remainder .strip ()]
53+ continue
54+
55+ if collecting :
56+ if separator and "=" not in scheme :
57+ break
58+ auth_params .append (segment )
59+
60+ if not auth_params :
61+ return None
62+ return ", " .join (part for part in auth_params if part )
63+
64+
1965def extract_field_from_www_auth (response : Response , field_name : str ) -> str | None :
2066 """Extract field from WWW-Authenticate header.
2167
@@ -26,15 +72,12 @@ def extract_field_from_www_auth(response: Response, field_name: str) -> str | No
2672 if not www_auth_header :
2773 return None
2874
29- # Strip the auth scheme (e.g. "Bearer") so parsing only sees auth-params.
30- _ , separator , auth_params = www_auth_header .partition (" " )
31- if not separator :
32- auth_params = www_auth_header
75+ auth_params = _extract_bearer_auth_params (www_auth_header )
76+ if auth_params is None :
77+ return None
3378
3479 # Match comma-delimited auth-params while respecting quoted values.
35- pattern = re .compile (
36- r'(?:^|,\s*)(?P<name>[A-Za-z][A-Za-z0-9_-]*)=(?:"(?P<quoted>[^"]+)"|(?P<unquoted>[^,\s]+))'
37- )
80+ pattern = re .compile (r'(?:^|,\s*)(?P<name>[A-Za-z][A-Za-z0-9_-]*)=(?:"(?P<quoted>[^"]+)"|(?P<unquoted>[^,\s]+))' )
3881 for match in pattern .finditer (auth_params ):
3982 if match .group ("name" ) == field_name :
4083 # Return quoted value if present, otherwise unquoted value
0 commit comments