fix: serialize Pydantic AnyUrl fields when persisting MCP OAuth state

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
This commit is contained in:
Amanuel Tilahun Bogale 2026-04-06 20:46:08 -04:00 committed by Teknium
parent 4ac731c841
commit 5fa2f4258a

View file

@ -233,7 +233,7 @@ class HermesTokenStorage:
return None
async def set_tokens(self, tokens: "OAuthToken") -> None:
payload = tokens.model_dump(exclude_none=True)
payload = tokens.model_dump(mode="json", exclude_none=True)
# Persist an absolute ``expires_at`` so a process restart can
# reconstruct the correct remaining TTL. Without this the MCP SDK's
# ``_initialize`` reloads a relative ``expires_in`` which has no
@ -265,7 +265,7 @@ class HermesTokenStorage:
return None
async def set_client_info(self, client_info: "OAuthClientInformationFull") -> None:
_write_json(self._client_info_path(), client_info.model_dump(exclude_none=True))
_write_json(self._client_info_path(), client_info.model_dump(mode="json", exclude_none=True))
logger.debug("OAuth client info saved for %s", self._server_name)
# -- cleanup -----------------------------------------------------------
@ -508,7 +508,7 @@ def _maybe_preregister_client(
info_dict["scope"] = cfg["scope"]
client_info = OAuthClientInformationFull.model_validate(info_dict)
_write_json(storage._client_info_path(), client_info.model_dump(exclude_none=True))
_write_json(storage._client_info_path(), client_info.model_dump(mode="json", exclude_none=True))
logger.debug("Pre-registered client_id=%s for '%s'", client_id, storage._server_name)