Short answer: Refresh your MCP tokens before they expire. Every MCP connection uses OAuth, which gives you an access token and a refresh token, and each provider decides how long those last. An agent running headless or remotely can't click "reconnect," so you either check each token's expiration and refresh it ahead of time, or use a simple heuristic: a cron job that reconnects to every MCP server once a day to get fresh tokens. That second one is what we do at fl0w.
Why MCP servers "randomly" need to reconnect
You may have noticed that some of your MCP servers randomly need to reconnect. It's not actually random. It all comes down to OAuth and refresh tokens.
Every time you authenticate to, say, the PostHog MCP, you get back two tokens:
- an access token, which proves who you are, and
- a refresh token, which gets you a new access token when the old one expires.
The access token might expire in a week, a day, or an hour, depending on the provider's policy. Refresh tokens can expire or be rotated too. Whenever either one goes stale, you have to reconnect.
On your laptop, that's a minor annoyance. You see the prompt, you sign in again, you move on.
OAuth in the age of AI
An unattended agent doesn't get that luxury. When you're running agents headlessly or remotely, on a schedule, or in a sandbox, nobody is there to click through a sign-in page. If a token goes stale between runs, the next run just fails, often at 3am, often silently.
If you're running Claude Code headlessly, the fix is pretty simple: use that MCP connector, or reconnect to its OAuth, before the tokens expire. Every successful connection refreshes the tokens and puts more time on the clock.
There are two ways to do it.
Option 1: Track expirations and refresh just in time
If you want to be precise, track the expiration. When you establish the OAuth connection, the token response includes an expiration (expires_in, in seconds). Store it and refresh your tokens before it runs out.
{
"access_token": "...",
"refresh_token": "...",
"token_type": "Bearer",
"expires_in": 3600
}
This is the right approach for long-running sessions, where a token can expire mid-run. Refresh with the refresh token a few minutes before expires_in runs out and the agent never notices.
Option 2: A daily cron job that reconnects (the lazy heuristic)
If you'd rather use a lazy heuristic, which is what we do at fl0w, run a cron job that reconnects once a day and gets a new access and refresh token. That puts another day on the clock.
# crontab -e: reconnect MCP servers every day at 4am
0 4 * * * /usr/local/bin/refresh-mcp-tokens.sh >> ~/logs/mcp-refresh.log 2>&1
The script only needs to open a connection to each MCP server and save whatever tokens come back. This won't help a token that expires in under a day, but most providers issue refresh tokens that last much longer than that, so a daily touch keeps them alive indefinitely.
Things that still break
- Refresh token rotation across machines. Some providers issue a new refresh token on every refresh and invalidate the old one. If your laptop and your server each hold their own copy, a refresh on one machine leaves the other with a dead token. Keep one copy of the tokens and sync it.
- Revoked access. If a user disconnects the app or an admin revokes it, no refresh will help. Alert on auth failures so a person can sign in again. (fl0w's headless runs emit an
mcp_auth_requiredevent for this and keep going without that server's tools.) - Headless sign-in. The first OAuth flow still needs a browser. Do it on a machine with one, then move the tokens, or forward the callback port. More on this in MCP servers in the cloud.
How fl0w keeps MCP tokens fresh
At fl0w, we try to make you reconnect as rarely as possible, ideally never.
- A daily refresh on your cloud computer. We have a cron job that runs every day on your remote computer to keep all your MCP servers fresh. You get a new refresh token, and your scheduled workflows don't fail on stale auth.
- One set of tokens, synced. Your MCP config and OAuth tokens sync between your laptop and your cloud computer, so a token refreshed in the cloud doesn't leave your laptop with a stale copy. See MCP servers in the cloud.
- Sign in once. Add a server and run OAuth from your terminal with
fl0w mcp addandfl0w reauth. The same tokens work locally, on your cloud computer, and in unattended workflow runs.
fl0w mcp add posthog https://mcp.posthog.com/mcp
fl0w reauth posthog # sign in now instead of on next start
It's pretty easy to do this yourself, even if you're running Claude Code headlessly in a sandbox. fl0w just means you don't have to. See Adding MCP connectors for details.
FAQ
Why do my MCP servers keep disconnecting?
MCP servers use OAuth. Your access token or refresh token expired or was rotated, and the provider's policy decides how often that happens: anywhere from an hour to weeks. Reconnecting gets you new tokens.
How long do MCP OAuth tokens last?
It depends on the provider. Access tokens commonly last from an hour to a day, and the token response tells you exactly via expires_in. Refresh tokens usually last much longer but can be rotated on every use.
How do I keep MCP servers authenticated for a headless Claude Code agent?
Connect to each MCP server before its tokens expire. Either refresh each token ahead of its expires_in, or run a daily cron job that reconnects to every server and saves the new tokens.
What's the difference between an access token and a refresh token?
The access token is the short-lived credential sent with each request. The refresh token is used to get a new access token without signing in again.
Why does refreshing a token on my server log me out on my laptop?
Some providers rotate refresh tokens: each refresh invalidates the previous one. If two machines keep separate copies, the one that didn't refresh is left holding a dead token. Share and sync a single copy instead.