Skip to content

Commit 93b7315

Browse files
committed
fix: include transport path in Protected Resource Metadata resource URL
The resource field in /.well-known/oauth-protected-resource was set to the base resource_server_url (e.g. http://localhost:8000/) instead of the actual protected endpoint URL (e.g. http://localhost:8000/mcp). Per RFC 9728, the resource identifier must match the URL that clients use to access the protected resource. Append the transport path (streamable_http_path or sse_path) to the resource_server_url in both lowlevel/server.py and mcpserver/server.py.
1 parent 62575ed commit 93b7315

2 files changed

Lines changed: 17 additions & 4 deletions

File tree

src/mcp/server/lowlevel/server.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ async def main():
4646

4747
import anyio
4848
from anyio.streams.memory import MemoryObjectReceiveStream, MemoryObjectSendStream
49+
from pydantic import AnyHttpUrl
4950
from starlette.applications import Starlette
5051
from starlette.middleware import Middleware
5152
from starlette.middleware.authentication import AuthenticationMiddleware
@@ -595,8 +596,11 @@ def streamable_http_app(
595596
# Determine resource metadata URL
596597
resource_metadata_url = None
597598
if auth and auth.resource_server_url:
599+
# The protected resource URL must include the transport path
600+
# (e.g. http://localhost:8000/mcp) per RFC 9728
601+
actual_resource_url = AnyHttpUrl(str(auth.resource_server_url).rstrip("/") + streamable_http_path)
598602
# Build compliant metadata URL for WWW-Authenticate header
599-
resource_metadata_url = build_resource_metadata_url(auth.resource_server_url)
603+
resource_metadata_url = build_resource_metadata_url(actual_resource_url)
600604

601605
routes.append(
602606
Route(
@@ -615,9 +619,10 @@ def streamable_http_app(
615619

616620
# Add protected resource metadata endpoint if configured as RS
617621
if auth and auth.resource_server_url: # pragma: no cover
622+
actual_resource_url = AnyHttpUrl(str(auth.resource_server_url).rstrip("/") + streamable_http_path)
618623
routes.extend(
619624
create_protected_resource_routes(
620-
resource_url=auth.resource_server_url,
625+
resource_url=actual_resource_url,
621626
authorization_servers=[auth.issuer_url],
622627
scopes_supported=auth.required_scopes,
623628
)

src/mcp/server/mcpserver/server.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -982,10 +982,15 @@ async def handle_sse(scope: Scope, receive: Receive, send: Send): # pragma: no
982982
# Determine resource metadata URL
983983
resource_metadata_url = None
984984
if self.settings.auth and self.settings.auth.resource_server_url:
985+
from pydantic import AnyHttpUrl
986+
985987
from mcp.server.auth.routes import build_resource_metadata_url
986988

989+
# The protected resource URL must include the transport path
990+
# (e.g. http://localhost:8000/sse) per RFC 9728
991+
actual_resource_url = AnyHttpUrl(str(self.settings.auth.resource_server_url).rstrip("/") + sse_path)
987992
# Build compliant metadata URL for WWW-Authenticate header
988-
resource_metadata_url = build_resource_metadata_url(self.settings.auth.resource_server_url)
993+
resource_metadata_url = build_resource_metadata_url(actual_resource_url)
989994

990995
# Auth is enabled, wrap the endpoints with RequireAuthMiddleware
991996
routes.append(
@@ -1023,11 +1028,14 @@ async def sse_endpoint(request: Request) -> Response: # pragma: no cover
10231028
)
10241029
# Add protected resource metadata endpoint if configured as RS
10251030
if self.settings.auth and self.settings.auth.resource_server_url: # pragma: no cover
1031+
from pydantic import AnyHttpUrl
1032+
10261033
from mcp.server.auth.routes import create_protected_resource_routes
10271034

1035+
actual_resource_url = AnyHttpUrl(str(self.settings.auth.resource_server_url).rstrip("/") + sse_path)
10281036
routes.extend(
10291037
create_protected_resource_routes(
1030-
resource_url=self.settings.auth.resource_server_url,
1038+
resource_url=actual_resource_url,
10311039
authorization_servers=[self.settings.auth.issuer_url],
10321040
scopes_supported=self.settings.auth.required_scopes,
10331041
)

0 commit comments

Comments
 (0)