Skip to content

fix: treat resource metadata JSON parse failure as soft error#810

Merged
alexhancock merged 1 commit into
modelcontextprotocol:mainfrom
jh-block:fix/resource-metadata-parse-fallback
Apr 16, 2026
Merged

fix: treat resource metadata JSON parse failure as soft error#810
alexhancock merged 1 commit into
modelcontextprotocol:mainfrom
jh-block:fix/resource-metadata-parse-fallback

Conversation

@jh-block

Copy link
Copy Markdown
Contributor

Summary

fetch_resource_metadata_from_url returns a fatal AuthError::MetadataError when the resource metadata response body cannot be parsed as JSON. This prevents discover_metadata() from falling through to direct .well-known/oauth-authorization-server discovery (Strategy B).

Problem

MCP servers that return HTTP 200 with non-JSON content (e.g. HTML) at their base URL cause the resource metadata probe to "succeed" at the HTTP level (200 = "this is the metadata URL"), but then the JSON deserialization fails fatally. The OAuth flow aborts entirely even though the server has a valid .well-known/oauth-authorization-server endpoint.

Users see "Auth required" with no OAuth browser flow ever opening.

Fix

Treat JSON parse errors as a soft failure — return Ok(None) with a debug! log — consistent with how HTTP errors (non-200 status codes) are already handled in the same function. This allows discover_metadata() to continue and attempt direct authorization server metadata discovery.

Test plan

  • Verified the project compiles with cargo check -p rmcp --features auth
  • Existing tests continue to pass
  • Servers returning valid resource metadata JSON are unaffected (happy path unchanged)
  • Servers returning non-JSON at their base URL now correctly fall through to .well-known/oauth-authorization-server discovery instead of aborting

In fetch_resource_metadata_from_url, a JSON parse failure on the
response body caused a fatal AuthError::MetadataError, preventing
discover_metadata() from falling through to direct
.well-known/oauth-authorization-server discovery (Strategy B).

MCP servers that return HTTP 200 with non-JSON content (e.g. HTML)
at their base URL caused the OAuth flow to abort entirely, even
when the server had a valid .well-known/oauth-authorization-server
endpoint.

Return Ok(None) on parse failure, consistent with how HTTP errors
are already handled in the same function.
@jh-block
jh-block requested a review from a team as a code owner April 16, 2026 09:38
@github-actions github-actions Bot added T-core Core library changes T-transport Transport layer changes labels Apr 16, 2026
@jh-block

jh-block commented Apr 16, 2026

Copy link
Copy Markdown
Contributor Author

Note that an alternative here would be to not try to parse this response as metadata at all, since fetching the MCP server URL itself and treating it as the metadata isn't part of the discovery flow in the spec. But I am assuming this variation from the spec is intentional for some reason (compatibility with non-compliant servers maybe?) so kept this change minimal.

jh-block added a commit to aaif-goose/goose that referenced this pull request Apr 16, 2026
…vers

When a remote MCP server returns HTTP 200 with non-JSON content at its
base URL, rmcp's resource metadata discovery fatally errors instead of
falling through to .well-known/oauth-authorization-server discovery.
This prevents the OAuth browser flow from ever opening.

Add a fallback in oauth_flow that catches the discovery failure and
retries by fetching .well-known/oauth-authorization-server directly.
Also log the actual error when oauth_flow fails instead of silently
swallowing it.

Upstream fix: modelcontextprotocol/rust-sdk#810
@alexhancock
alexhancock merged commit 01a6666 into modelcontextprotocol:main Apr 16, 2026
17 checks passed
@github-actions github-actions Bot mentioned this pull request Apr 16, 2026
88plug added a commit to 88plug/goose-plus that referenced this pull request Jul 5, 2026
…ata bug

OAuthState::start_authorization_with_metadata_url fails fatally for some
remote MCP servers (non-JSON HTTP 200 at the base URL, auth server on a
different host, path-based deployments), silently breaking the OAuth
browser flow. Add a spec-compliant fallback that discovers Protected
Resource Metadata (RFC 9728) and Authorization Server Metadata (RFC 8414)
directly via well-known URLs, then builds the session through rmcp's
public APIs.

Ports jhugo/fix-issue-8453 (upstream commits 1637c3d15, 74c283e2b),
working around modelcontextprotocol/rust-sdk#810.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

T-core Core library changes T-transport Transport layer changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants