Fix
MCP OAuth says
“connection expired”? Here is the fix.
A remote MCP server that uses OAuth works for a while, then your client says the connection expired and you sign in again. Often the refresh step failed, and sometimes no software can fix that. Here is how to tell which, and what MCPProxy changes.
Quick fix
If a server behind MCPProxy needs a fresh sign-in, run:
mcpproxy auth status
mcpproxy auth login --server=SERVER_NAME
Replace SERVER_NAME with the name of your server in MCPProxy. auth status shows which servers have a working token. auth login opens your browser to sign in again and stores the new tokens. In the Web UI, the server’s page has a Sign in or Log in again button that does the same thing. If MCPProxy runs on a remote machine, HEADLESS=true prints the sign-in URL, but the provider’s callback still has to reach MCPProxy. Use an SSH forward for the loopback callback, or an HTTPS callback set with oauth.callback_base_url. The OAuth docs cover both.
Why “connection expired” happens
An OAuth login gives the client two things: a short-lived access token and a longer-lived refresh token. The client quietly swaps the refresh token for a new access token before the old one runs out. That swap fails for a handful of reasons:
- The refresh token itself expired. Providers set their own limits. Some expire refresh tokens after a period of not being used.
- The grant was revoked. You removed the app in your account settings, or an admin policy ended the session.
- Refresh token reuse. Some providers issue a new refresh token on each refresh and reject the old one. Rotation is normal, but if two things use the same old token, the provider may revoke the whole grant.
- The OAuth client changed. The client ID was deleted or rotated, or the redirect URL registered with the provider no longer matches.
- The provider had a bad moment. A 5xx error or a rate limit is temporary and should be retried, not treated as a sign-out.
If the refresh token has expired or the grant was revoked, nothing can renew it silently and a person has to sign in again.
What MCPProxy does about it
- One token store, one refresher. MCPProxy holds the OAuth tokens for the servers behind it, in your operating system keyring, and refreshes them before they expire. Your clients do not each keep their own copy and race to refresh it.
- One refresh request at a time per server. Refreshes are serialized. Everything waiting at that moment gets the same new token. This matters for providers that rotate refresh tokens.
- Error-aware retries. Temporary provider and network failures are retried with a growing delay (10 seconds up to 5 minutes). Known terminal errors, such as an invalid grant, stop retrying and tell you to sign in again. Other errors are retried up to a limit.
- A clear state. The Web UI shows an amber “Sign-in required” for a first login, and an error state for a session that expired or was revoked, with a button to sign in again.
- Named errors. Common failures have a code with causes and a fix:
MCPX_OAUTH_REFRESH_EXPIRED,MCPX_OAUTH_REFRESH_403,MCPX_OAUTH_REAUTH_REQUIRED.
If it keeps happening
- Run
mcpproxy auth login --server=SERVER_NAME --log-level=debugand read what the provider returns. - If re-login also fails with a 403 or
invalid_grant, check that theclient_idandclient_secretstill exist at the provider and that the redirect URL matches. SeeMCPX_OAUTH_REFRESH_403. - Check your provider’s sign-in or audit log. It usually says whether the grant was revoked or a policy ended it.
- Keep MCPProxy running. A machine that was off for longer than the provider’s refresh window will need a fresh sign-in. Also check that your system clock is correct.
- If the redirect port keeps changing, pin it with
oauth.redirect_uriso the URL registered with the provider stays valid.
What this does not fix
- A provider that expires refresh tokens on a schedule will still ask you to sign in again on that schedule.
- If a client connects to the remote server directly instead of through MCPProxy, that client’s own login handling applies. Put the server behind MCPProxy and connect the client to MCPProxy to get the single token holder.