Skip to content

v0.1.50

Latest

Choose a tag to compare

@anandnalya anandnalya released this 20 Aug 05:09
cf470bc

Published as @automattic/mcp-remote@0.1.50.

Changes

Fix hourly browser re-auth against rotating refresh-token servers (#6): silent token renewal always fell back to a browser re-authorization against servers that issue single-use refresh tokens, such as WordPress.com's oauth2-1. Three independent causes, each fixed here.

  • OAuth errors were unparseable under a proxy. With --socks-proxy / --enable-proxy we replaced global.fetch with npm undici's fetch, but the SDK checks responses with instanceof Response against the built-in class. Every OAuth error — invalid_grant included — parsed as garbage and was silently swallowed before falling through to a browser flow. Headers, Request and Response are now aliased together with fetch.
  • Concurrent refreshes inside one process raced each other. The MCP SDK lets concurrent sends enter authorization independently, all sharing one provider, so two flows would read the same single-use refresh token and one would lose a race with no other process involved. The provider now supplies the fetch the transports use, which the SDK threads into its token request; refresh grants queue behind each other, each is retargeted at whatever token is current on disk, and the rotated pair is persisted before the queue is released.
  • Concurrent processes deleted each other's credentials. Where several mcp-remote processes share one tokens.json, the first refresh wins the rotation and the rest fail with invalid_grant; the SDK then deleted the winner's fresh tokens and opened a browser, orphaning a live grant. Those tokens are now kept when the pair on disk was rotated by another party, and the SDK's own retry picks them up.

Also in this release: config files are written atomically (temp file plus rename), since a torn read of tokens.json surfaced as "no tokens saved" and made the rotation guard delete live credentials in exactly the window it exists to protect; an invalid_grant that escapes the SDK's single auth retry reconnects once rather than failing the connection; a failed forward answers the client with a JSON-RPC error instead of leaving the request hanging until its own timeout; and debugLog resolves function-valued arguments only after checking DEBUG, so hot-path callers stop paying for stack captures and JSON.stringify that get discarded.

Known limitations

Refreshes are still not serialized across processes, and the remaining gaps follow from that: the rotation guard's read and delete are not atomic, and recovery is bounded at roughly four attempts before the connection fails rather than degrading to a re-authorization. Both are documented at invalidateTokens in src/lib/node-oauth-client-provider.ts. Closing them is a single change — a lock around read, refresh, write and conditional delete — which would retire the rotation guard, the reconnect and the duplicate-save bookkeeping together.

Install: npx @automattic/mcp-remote@0.1.50 https://remote.mcp.server/sse