Skip to content

Commit 584ca0f

Browse files
authored
DX-114676: Unable to connect MCP server app (Trailing slash in OAuthMetadata's issuer causes issues with clients) (#85)
* Fix DX-114676: OAuth discovery fails with "does not implement OAuth" error New MCP connections to staging/qa fail with "MCP server does not implement OAuth" error starting around Feb 12, 2026, while existing connections continue to work. Root cause: The MCP SDK's OAuthMetadata model uses AnyHttpUrl for the issuer field, which automatically adds a trailing slash during Pydantic serialization. This violates RFC 8414 Section 3.2, which requires the issuer field in OAuth metadata to exactly match the discovery URL (without trailing slash). Example: - Discovery URL: https://login.dremio.cloud/.well-known/oauth-authorization-server - Issuer returned: https://login.dremio.cloud/ (with trailing slash) - RFC 8414 requirement: Issuer must be https://login.dremio.cloud (no trailing slash) Modern OAuth clients (Claude Desktop after Feb 12, 2026) enforce strict RFC 8414 compliance and reject metadata with mismatched issuer URLs. Create OAuthMetadataRFC8414 class that extends OAuthMetadata and uses Pydantic's @field_serializer decorator to strip the trailing slash from the issuer field during serialization. This is a clean, targeted fix that maintains RFC 8414 compliance without manual dict manipulation. Added test_oauth_discovery_rfc8414_compliance that validates the issuer field does not have a trailing slash, ensuring RFC 8414 compliance. * Simplify test_oauth_discovery_rfc8414_compliance Remove unnecessary settings override that was not needed for the test. The test only needs to verify the OAuth metadata endpoint returns an issuer without a trailing slash.
1 parent f585af5 commit 584ca0f

2 files changed

Lines changed: 51 additions & 2 deletions

File tree

src/dremioai/servers/mcp.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,25 @@
2020
from mcp.cli.claude import get_claude_config_path
2121
from mcp.shared.auth import OAuthMetadata
2222
from mcp.types import ToolAnnotations
23-
from pydantic import AnyHttpUrl
23+
from pydantic import AnyHttpUrl, field_serializer
2424
from pydantic.networks import AnyUrl
2525

2626
from dremioai.metrics.registry import get_metrics_app
2727
from starlette.requests import Request
2828
from starlette.responses import Response
2929

30+
31+
class OAuthMetadataRFC8414(OAuthMetadata):
32+
"""RFC 8414 compliant OAuth metadata that strips trailing slash from issuer URL.
33+
34+
The MCP SDK's OAuthMetadata uses AnyHttpUrl for the issuer field, which adds
35+
a trailing slash during serialization. RFC 8414 Section 3.2 requires the issuer
36+
to exactly match the discovery URL without trailing slash.
37+
"""
38+
@field_serializer('issuer')
39+
def serialize_issuer(self, value: AnyHttpUrl) -> str:
40+
return str(value).rstrip('/')
41+
3042
from dremioai.tools import tools
3143
import os
3244
from typing import List, Union, Annotated, Optional, Tuple, Dict, Any
@@ -180,7 +192,7 @@ def init(
180192
async def authorization_server_metadata(request: Request) -> Response:
181193
if issuer := settings.instance().dremio.auth_issuer_uri:
182194
auth, tok = settings.instance().dremio.auth_endpoints
183-
md = OAuthMetadata(
195+
md = OAuthMetadataRFC8414(
184196
issuer=AnyHttpUrl(issuer),
185197
authorization_endpoint=auth,
186198
token_endpoint=tok,

tests/e2e/test_mcp_e2e.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,43 @@ async def test_healthz(mock_config_dir, logging_server, logging_level):
5050
), f"/healthz failed with {r.text}, {r.status_code}"
5151

5252

53+
@pytest.mark.asyncio
54+
async def test_oauth_discovery_rfc8414_compliance(mock_config_dir, logging_server, logging_level):
55+
"""Test that OAuth discovery fails with trailing slash (reproduces DX-114676).
56+
57+
This test reproduces the issue that started happening around Feb 12, 2026 when
58+
Claude Desktop clients were updated to strictly validate RFC 8414 Section 3.2,
59+
which requires the issuer field in OAuth metadata to exactly match the discovery URL.
60+
61+
The bug: AnyHttpUrl adds a trailing slash to the issuer URL, causing strict clients
62+
to reject the OAuth metadata because the issuer doesn't match the discovery URL.
63+
"""
64+
async with http_streamable_mcp_server(logging_server, logging_level) as sf:
65+
async with AsyncClient() as client:
66+
oauth_url = urlparse(sf.mcp_server.url)._replace(
67+
path="/.well-known/oauth-authorization-server"
68+
).geturl()
69+
70+
r = await client.get(oauth_url)
71+
72+
if r.status_code == 404:
73+
pytest.skip("OAuth not configured for this test environment")
74+
75+
assert r.status_code == 200, f"OAuth metadata endpoint failed: {r.text}"
76+
77+
# Check the raw JSON response (what clients actually receive)
78+
data = r.json()
79+
issuer_from_json = data["issuer"]
80+
81+
if issuer_from_json.endswith('/'):
82+
pytest.fail(
83+
f"RFC 8414 Section 3.2 violation: issuer has trailing slash.\n"
84+
f"Got: {issuer_from_json}\n"
85+
f"This causes OAuth discovery to fail with strict clients (Claude Desktop after Feb 12, 2026).\n"
86+
f"The issuer field MUST exactly match the discovery URL without trailing slash."
87+
)
88+
89+
5390
@pytest.mark.asyncio
5491
@pytest.mark.parametrize(
5592
"engine_name",

0 commit comments

Comments
 (0)