Add authentication to your MCP server
API keys, OAuth 2.1, or payment-as-access with x402 — three different answers to three different questions. Pick by what you actually need to know about the caller.
Authentication on an MCP server answers one of three questions: do I recognize this caller (API keys), did a user authorize this access to their data (OAuth), or has this call been paid for (x402)? Most guides treat these as interchangeable. They aren't — they verify different things, and choosing wrong creates either friction nobody needs or holes you'll regret.
This guide lays out what each mechanism actually establishes, where it fits a remote MCP server, and how they compose when you need more than one.
API keys: recognition, with a distribution problem
A static key in a header tells you a request comes from someone you've issued a key to. For a private server used by your own team or a handful of known partners, that's sufficient and easy: check the header, reject the rest.
The model breaks for autonomous agents at large. Keys must be issued by a human signup flow before the first call, which means an agent that just discovered your server in an index cannot use it. Keys also leak, get committed to repos, and carry no per-call cost signal — a leaked key is unlimited free usage until you notice.
OAuth 2.1: user-delegated access to private data
The MCP authorization spec standardizes on OAuth 2.1 for remote servers. The flow exists for one job: letting an end user grant an MCP client scoped access to that user's data on your service — their repos, their calendar, their documents. The client discovers your authorization server via protected-resource metadata, runs the consent flow, and presents a token bound to your server as the audience.
Use OAuth when the resource being protected is per-user and the human is in the loop at setup time. It is the wrong tool for anonymous, machine-to-machine calls — there's no user to consent, and standing up an authorization server to protect a public utility tool is heavy ceremony for no gain.
x402: payment as access control
x402 inverts the question. Instead of who are you, it asks: is this call paid for? The server returns HTTP 402 with a price, the agent pays in USDC, a facilitator verifies, and the handler runs only after settlement. No accounts, no key issuance, no consent screen — the payment itself is the credential, and it arrives before your code executes.
This fits public, per-call services consumed by agents you'll never meet. It also solves the abuse economics that keys can't: every call costs the caller at least $0.01, so scraping your tool at volume is self-defeating rather than free.
Composing them: identity for whose data, payment for who pays
The mechanisms answer different questions, so they stack cleanly. A common pattern: free, unauthenticated tools/list so agents can discover the server; x402 gating on general-purpose paid tools; OAuth only on tools that touch a specific user's private data. One server, three access answers.
import { requirePayment } from "@loomal/sdk";
const routeByTool = (name: string) => {
if (name === "search_public_docs")
return requirePayment({ price: "$0.01" }); // anonymous, paid
if (name === "read_user_vault")
return requireOAuth({ scope: "vault:read" }); // identity, free
return null; // free and open
};A decision rule that holds up
Known callers, private deployment: API keys. Per-user data with a human at setup: OAuth 2.1. Public tools sold per call to anonymous agents: x402. If you're monetizing, note that x402 quietly replaces the entire key-issuance and billing apparatus — Loomal lists your server with its price attached, and the only fee is 5% on settled transactions, currently waived.
FAQ
Can x402 really replace authentication entirely?
For public per-call tools, yes — payment establishes everything you need (the call is funded, abuse is priced out). It cannot replace OAuth where the tool acts on a specific user's private data, because money proves payment, not permission to read someone's inbox.
Do I need OAuth to list a paid MCP server?
No. A paid public server needs only the x402 gate; agents discover it, get the 402 quote, and pay per call without any account. OAuth enters only when individual tools need user-scoped authorization on top.
What about stdio servers running locally?
Local stdio servers inherit the user's own machine and credentials, so they typically need no auth layer of their own — they hold the user's API keys for upstream services in their environment. Authentication becomes a design question the moment you host the server remotely.
Is a leaked x402 wallet as bad as a leaked API key?
It's a different failure. A leaked key grants unlimited free access to your server at your expense. A compromised agent wallet spends the agent operator's funds, and the damage is bounded by that wallet's balance and budget caps — your server still gets paid for every call it executes.
See how live servers handle access.
Browse the index — every listing shows its transport, tools, and price.