Skip to content

fix: serialize Pydantic AnyUrl fields when persisting MCP OAuth state - #5677

Closed
amanuel2 wants to merge 1 commit into
NousResearch:mainfrom
amanuel2:fix/mcp-oauth-anyurl-serialization
Closed

fix: serialize Pydantic AnyUrl fields when persisting MCP OAuth state#5677
amanuel2 wants to merge 1 commit into
NousResearch:mainfrom
amanuel2:fix/mcp-oauth-anyurl-serialization

Conversation

@amanuel2

@amanuel2 amanuel2 commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Fix TypeError: Object of type AnyUrl is not JSON serializable crash when persisting OAuth state for MCP servers
  • Three call sites in tools/mcp_oauth.py use model_dump(exclude_none=True) which leaves Pydantic AnyUrl objects in the returned dict, breaking the subsequent json.dumps

Reproduction

Configure any OAuth-based MCP server (e.g. alphaxiv) and start hermes:

hermes
OAuth flow error
Traceback (most recent call last):
  File ".../mcp/client/auth/oauth2.py", line 583, in async_auth_flow
    await self.context.storage.set_client_info(client_information)
  File ".../tools/mcp_oauth.py", line 222, in set_client_info
    _write_json(self._client_info_path(), client_info.model_dump(exclude_none=True))
  File ".../tools/mcp_oauth.py", line 117, in _write_json
    path.write_text(json.dumps(data, indent=2), encoding="utf-8")
  ...
TypeError: Object of type AnyUrl is not JSON serializable
Failed to connect to MCP server 'alphaxiv': Object of type AnyUrl is not JSON serializable

The MCP server fails registration and is marked as failed in the MCP servers list.

Root Cause

OAuthClientInformationFull and OAuthToken from the MCP SDK contain Pydantic fields typed as AnyUrl (e.g. client_uri, redirect_uris, jwks_uri). Pydantic's default model_dump() preserves these as native AnyUrl instances rather than converting them to strings. The standard library json.dumps then has no way to serialize them.

Fix

Use model_dump(mode="json", ...) instead. The mode="json" flag tells Pydantic to convert all fields to JSON-compatible primitives (AnyUrlstr, datetime → ISO string, etc.) before returning the dict, so the existing _write_json helper works without further changes.

Three call sites fixed:

  • HermesTokenStorage.set_tokens (line 206)
  • HermesTokenStorage.set_client_info (line 222)
  • build_oauth_auth pre-registration write (line 465)

Test plan

  • Configure an OAuth-based MCP server (alphaxiv, GitHub MCP, etc.)
  • Start hermes — verify no OAuth flow error traceback
  • Verify MCP server registers successfully (not in failed list)
  • Verify the persisted client info / token JSON files on disk are valid JSON
  • Verify subsequent reads via get_client_info / get_tokens round-trip correctly through model_validate

Discovered while running hermes with the alphaxiv MCP server configured.

OAuth client information and token responses from the MCP SDK contain
Pydantic AnyUrl fields (client_uri, redirect_uris, etc.). The previous
model_dump() call returned a dict with these AnyUrl objects still as
their native Python type, which then crashed json.dumps with:

  TypeError: Object of type AnyUrl is not JSON serializable

This caused any OAuth-based MCP server (e.g. alphaxiv) to fail
registration with an "OAuth flow error" traceback during startup.

Adding mode="json" tells Pydantic to serialize all fields to
JSON-compatible primitives (AnyUrl -> str, datetime -> ISO string, etc.)
before returning the dict, so the standard json.dumps can handle it.

Three call sites fixed:
- HermesTokenStorage.set_tokens
- HermesTokenStorage.set_client_info
- build_oauth_auth pre-registration write
@teknium1

Copy link
Copy Markdown
Contributor

Thanks for this fix, @amanuel2! The change has already been merged to main.

  • Commit 5fa2f425 landed your exact three-line change (mode="json" at all three model_dump call sites in tools/mcp_oauth.py).
  • All three sites are confirmed on current main: lines 236, 268, and 518.

Closing as implemented. Automated hermes-sweeper review.

@teknium1 teknium1 closed this Apr 27, 2026
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth area/auth Authentication, OAuth, credential pools duplicate This issue or pull request already exists labels Apr 30, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #15125 — same root cause (Pydantic AnyUrl serialization in MCP OAuth). #15125 already merged with the model_dump(mode="json") fix across all three call sites.

@alt-glitch

Copy link
Copy Markdown
Collaborator

Likely duplicate of #15125 — same root cause (Pydantic AnyUrl serialization in MCP OAuth). #15125 already merged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/auth Authentication, OAuth, credential pools duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists tool/mcp MCP client and OAuth type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants