Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions README.v2.md
Original file line number Diff line number Diff line change
Expand Up @@ -1021,10 +1021,14 @@ mcp = MCPServer(
"Weather Service",
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
# Auth settings for RFC 9728 Protected Resource Metadata
# Auth settings for RFC 9728 Protected Resource Metadata.
# `resource_server_url` MUST be the full public URL of the MCP endpoint, including
# the transport path (e.g. `/mcp` for streamable-http, `/sse` for sse). RFC 9728
# section 3.3 requires strict equality between the client's resource identifier and
# the `resource` value advertised in the protected resource metadata.
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL
resource_server_url=AnyHttpUrl("http://localhost:3001"), # This server's URL
resource_server_url=AnyHttpUrl("http://localhost:3001/mcp"), # Public MCP endpoint URL
required_scopes=["user"],
),
)
Expand Down
7 changes: 5 additions & 2 deletions examples/servers/simple-auth/mcp_simple_auth/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,9 +126,12 @@ def main(port: int, auth_server: str, transport: Literal["sse", "streamable-http
# Parse auth server URL
auth_server_url = AnyHttpUrl(auth_server)

# Create settings
# Create settings. server_url is the public URL of the MCP endpoint and must
# include the transport path so it matches the URL the client used to reach
# the server (RFC 9728 section 3.3 strict equality).
host = "localhost"
server_url = f"http://{host}:{port}/mcp"
transport_path = "/sse" if transport == "sse" else "/mcp"
server_url = f"http://{host}:{port}{transport_path}"
settings = ResourceServerSettings(
host=host,
port=port,
Expand Down
8 changes: 6 additions & 2 deletions examples/snippets/servers/oauth_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,14 @@ async def verify_token(self, token: str) -> AccessToken | None:
"Weather Service",
# Token verifier for authentication
token_verifier=SimpleTokenVerifier(),
# Auth settings for RFC 9728 Protected Resource Metadata
# Auth settings for RFC 9728 Protected Resource Metadata.
# `resource_server_url` MUST be the full public URL of the MCP endpoint, including
# the transport path (e.g. `/mcp` for streamable-http, `/sse` for sse). RFC 9728
# section 3.3 requires strict equality between the client's resource identifier and
# the `resource` value advertised in the protected resource metadata.
auth=AuthSettings(
issuer_url=AnyHttpUrl("https://auth.example.com"), # Authorization Server URL
resource_server_url=AnyHttpUrl("http://localhost:3001"), # This server's URL
resource_server_url=AnyHttpUrl("http://localhost:3001/mcp"), # Public MCP endpoint URL
required_scopes=["user"],
),
)
Expand Down
11 changes: 9 additions & 2 deletions src/mcp/server/auth/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class AuthSettings(BaseModel):
# Resource Server settings (when operating as RS only)
resource_server_url: AnyHttpUrl | None = Field(
...,
description="The URL of the MCP server to be used as the resource identifier "
"and base route to look up OAuth Protected Resource Metadata.",
description=(
"The full public URL of this MCP server, used as the resource identifier "
"and base route to look up OAuth Protected Resource Metadata (RFC 9728). "
"Must include the transport path (e.g. https://example.com/mcp for "
"streamable-http, https://example.com/sse for sse) so that the value "
"advertised in protected resource metadata exactly matches the URL the "
"client used to reach the server. RFC 9728 section 3.3 requires strict "
"equality between the client's resource identifier and this value."
),
)
Loading