Bug Description
Any OAuth-authenticated MCP server (e.g. Zoho MCP) stops working ~1 hour after
hermes mcp login. The next tool call fails with "MCP OAuth ... no cached
tokens found; run hermes mcp login interactively first". Only a full
re-authorization recovers it. It affects every such server, including idle,
single-process installs — silently breaking remote MCP integrations for all
users.
Steps to Reproduce
hermes mcp login <oauth-server> (e.g. a Zoho MCP server); complete the
browser OAuth.
- Confirm it works:
hermes mcp test <server> → Connected; and
mcp-tokens/<server>.json contains a refresh_token.
- Force the access token to expire — either wait ~1h or edit the token file
and set expires_at to a past timestamp.
- Trigger any tool call (e.g.
hermes mcp test <server>), which forces a
token refresh.
- Re-inspect
mcp-tokens/<server>.json.
Expected Behavior
The refresh_token persists across refreshes; the server keeps refreshing and
working indefinitely.
Actual Behavior
After the first refresh, refresh_token is gone from the token file
(only access_token remains). At the next expiry can_refresh_token() is
False, so no refresh happens and the server dies until a full re-OAuth.
Affected Component
Other
Messaging Platform (if gateway-related)
No response
Debug Report
Report https://paste.rs/hIytr
agent.log https://paste.rs/bi5fy
gateway.log https://paste.rs/K4jV6
gui.log https://paste.rs/0FCUp
Operating System
Ubuntu 24.04.4 LTS
Python Version
3.11.15 (inside the container; host is 3.12.3)
Hermes Version
Hermes Agent v0.18.0 (2026.7.1)
Additional Logs / Traceback (optional)
Root Cause Analysis (optional)
HermesTokenStorage.set_tokens (tools/mcp_oauth.py, ~L310) does
tokens.model_dump(mode="json", exclude_none=True) then overwrites the file.
Per RFC 6749 §6 a refresh response MAY omit refresh_token (= "reuse the
existing one"), which Zoho does; exclude_none=True drops the None
refresh_token, so the write erases the stored one.
Proposed Fix (optional)
Fix — carry it forward:
payload = tokens.model_dump(mode="json", exclude_none=True)
if not payload.get("refresh_token"):
prev = _read_json(self._tokens_path())
if prev and prev.get("refresh_token"):
payload["refresh_token"] = prev["refresh_token"]
Verified: two consecutive forced-expiry refreshes now preserve the token.
Env: hermes-agent 0.18.0, [mcp] extra (mcp SDK 1.26.0), Linux/Docker, Zoho
MCP over Streamable HTTP.
Are you willing to submit a PR for this?
Bug Description
Any OAuth-authenticated MCP server (e.g. Zoho MCP) stops working ~1 hour after
hermes mcp login. The next tool call fails with "MCP OAuth ... no cachedtokens found; run
hermes mcp logininteractively first". Only a fullre-authorization recovers it. It affects every such server, including idle,
single-process installs — silently breaking remote MCP integrations for all
users.
Steps to Reproduce
hermes mcp login <oauth-server>(e.g. a Zoho MCP server); complete thebrowser OAuth.
hermes mcp test <server>→ Connected; andmcp-tokens/<server>.jsoncontains arefresh_token.and set
expires_atto a past timestamp.hermes mcp test <server>), which forces atoken refresh.
mcp-tokens/<server>.json.Expected Behavior
The refresh_token persists across refreshes; the server keeps refreshing and
working indefinitely.
Actual Behavior
After the first refresh,
refresh_tokenis gone from the token file(only
access_tokenremains). At the next expirycan_refresh_token()isFalse, so no refresh happens and the server dies until a full re-OAuth.
Affected Component
Other
Messaging Platform (if gateway-related)
No response
Debug Report
Operating System
Ubuntu 24.04.4 LTS
Python Version
3.11.15 (inside the container; host is 3.12.3)
Hermes Version
Hermes Agent v0.18.0 (2026.7.1)
Additional Logs / Traceback (optional)
Root Cause Analysis (optional)
HermesTokenStorage.set_tokens(tools/mcp_oauth.py, ~L310) doestokens.model_dump(mode="json", exclude_none=True)then overwrites the file.Per RFC 6749 §6 a refresh response MAY omit
refresh_token(= "reuse theexisting one"), which Zoho does;
exclude_none=Truedrops the Nonerefresh_token, so the write erases the stored one.
Proposed Fix (optional)
Fix — carry it forward:
Verified: two consecutive forced-expiry refreshes now preserve the token.
Env: hermes-agent 0.18.0,
[mcp]extra (mcp SDK 1.26.0), Linux/Docker, ZohoMCP over Streamable HTTP.
Are you willing to submit a PR for this?