Skip to content

Commit 08797d1

Browse files
committed
Fix /.well-known/oauth-authorization-server dropping path
1 parent e10ab3d commit 08797d1

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

src/mcp/client/auth.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,11 +200,19 @@ async def _handle_protected_resource_response(self, response: httpx.Response) ->
200200
async def _discover_oauth_metadata(self) -> httpx.Request:
201201
"""Build OAuth metadata discovery request."""
202202
if self.context.auth_server_url:
203-
base_url = self.context.get_authorization_base_url(self.context.auth_server_url)
203+
auth_server_url = self.context.auth_server_url
204204
else:
205-
base_url = self.context.get_authorization_base_url(self.context.server_url)
205+
auth_server_url = self.context.server_url
206206

207-
url = urljoin(base_url, "/.well-known/oauth-authorization-server")
207+
# Per RFC 8414, preserve the path component when constructing discovery URL
208+
parsed = urlparse(auth_server_url)
209+
well_known_path = f"/.well-known/oauth-authorization-server{parsed.path}"
210+
if parsed.path.endswith("/"):
211+
# Strip trailing slash from pathname
212+
well_known_path = well_known_path[:-1]
213+
214+
base_url = f"{parsed.scheme}://{parsed.netloc}"
215+
url = urljoin(base_url, well_known_path)
208216
return httpx.Request("GET", url, headers={MCP_PROTOCOL_VERSION: LATEST_PROTOCOL_VERSION})
209217

210218
async def _handle_oauth_metadata_response(self, response: httpx.Response) -> None:

tests/client/test_auth.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,10 +208,58 @@ async def test_discover_oauth_metadata_request(self, oauth_provider):
208208
"""Test OAuth metadata discovery request building."""
209209
request = await oauth_provider._discover_oauth_metadata()
210210

211+
assert request.method == "GET"
212+
assert str(request.url) == "https://api.example.com/.well-known/oauth-authorization-server/v1/mcp"
213+
assert "mcp-protocol-version" in request.headers
214+
215+
@pytest.mark.anyio
216+
async def test_discover_oauth_metadata_request_no_path(self, client_metadata, mock_storage):
217+
"""Test OAuth metadata discovery request building when server has no path."""
218+
219+
async def redirect_handler(url: str) -> None:
220+
pass
221+
222+
async def callback_handler() -> tuple[str, str | None]:
223+
return "test_auth_code", "test_state"
224+
225+
provider = OAuthClientProvider(
226+
server_url="https://api.example.com",
227+
client_metadata=client_metadata,
228+
storage=mock_storage,
229+
redirect_handler=redirect_handler,
230+
callback_handler=callback_handler,
231+
)
232+
233+
request = await provider._discover_oauth_metadata()
234+
211235
assert request.method == "GET"
212236
assert str(request.url) == "https://api.example.com/.well-known/oauth-authorization-server"
213237
assert "mcp-protocol-version" in request.headers
214238

239+
@pytest.mark.anyio
240+
async def test_discover_oauth_metadata_request_trailing_slash(self, client_metadata, mock_storage):
241+
"""Test OAuth metadata discovery request building when server path has trailing slash."""
242+
243+
async def redirect_handler(url: str) -> None:
244+
pass
245+
246+
async def callback_handler() -> tuple[str, str | None]:
247+
return "test_auth_code", "test_state"
248+
249+
provider = OAuthClientProvider(
250+
server_url="https://api.example.com/v1/mcp/",
251+
client_metadata=client_metadata,
252+
storage=mock_storage,
253+
redirect_handler=redirect_handler,
254+
callback_handler=callback_handler,
255+
)
256+
257+
request = await provider._discover_oauth_metadata()
258+
259+
assert request.method == "GET"
260+
assert str(request.url) == "https://api.example.com/.well-known/oauth-authorization-server/v1/mcp"
261+
assert "mcp-protocol-version" in request.headers
262+
215263
@pytest.mark.anyio
216264
async def test_register_client_request(self, oauth_provider):
217265
"""Test client registration request building."""

0 commit comments

Comments
 (0)