If someone steals an MCP access token, the server sees a legitimate request. The authorization specification asks for secure token storage, short lived access tokens, rotating refresh tokens for public clients, and tokens kept out of URLs. These limit how long a stolen token is useful and how easy it is to find.
What the specification says
The authorization specification describes token theft in one sentence: attackers who obtain tokens stored by the client, or tokens cached or logged on the server, can access protected resources with requests that look legitimate to resource servers.
It then sets out the expected behavior. Clients and servers must implement secure token storage and follow OAuth best practices. Authorization servers should issue short lived access tokens to reduce the impact of leaks. For public clients, authorization servers must rotate refresh tokens. Access tokens must not appear in the URI query string, and the Authorization header must be sent on every request.
Where tokens leak
Think about every place a token is written.
- Client config files and keychains. A plaintext file in a project directory can end up in a repository.
- Shell history and environment variables, where tokens pasted for convenience linger.
- Server logs. A request logger that prints headers prints the token. A URL logger prints it if someone put it in a query string.
- Error reports and traces sent to third parties.
- Caches and queues on the server side.
The specification calls out tokens cached or logged on the server by name, so audit your logging first.
Why short lifetimes help
A token valid for five minutes is worth much less than one valid for a month. A short lifetime shrinks the window in which a leaked token works, and forces the attacker to also steal the refresh token to keep access.
Refresh tokens are the more valuable target, which is why the specification requires rotation for public clients. With rotation, each use of a refresh token gives back a new one and the old one stops working. A replayed old token is then a signal that something is wrong.
What to do about it
- Store tokens in the platform's credential store, not in files in a project.
- Redact the Authorization header in all logs and traces.
- Never put tokens in query strings, and reject requests that try.
- Use short lifetimes for access tokens and rotate refresh tokens.
- Bind tokens to the intended server using the resource parameter, so a token taken from one server fails at another.
- Have a revocation path and practice it. Revoke by user, by client and by token.
Add detection
Log token issuance and refresh events with the client and user. Alert on a refresh token reused after rotation, a token used from two distant places, and a burst of calls from one token. These are cheap signals that catch a theft in progress.
Where Safeguard fits
Safeguard includes agent identity for tracking which agent holds which access, and a free scan at https://gold.safeguard.sh/scan for your dependencies. Neither replaces the storage and logging habits above.
Quick check
Is a long lived token acceptable if it has narrow scope?
Narrow scope helps, but the specification still prefers short lived access tokens. A narrow token that lives for months is still a standing credential.
Sources
Last reviewed: 19 October 2026.