VAT
Your cart

Your cart is empty.

MCP authentication: API key or OAuth

MCP authentication in mcp-core works with one token per connection. Every request to /mcp or /sse must carry the token of a connection on your license; the server looks it up and applies that connection’s tools and modes. The AUTH_STRATEGY variable sets how a client proves who it is: API key (the default) or OAuth.

How does MCP authentication work in mcp-core?

Every request passes through one authentication step before it reaches a tool. mcp-core reads the token, compares it with the connections it received in the last license check, and attaches the matching connection to the request. That connection decides which tools are registered and in which mode. Tokens are compared in constant time.

There is no license-wide fallback credential. A license without connections authenticates nobody: every request gets 401 Unauthorized. When you download your bundle (see Install MCP Core), a first connection called “Default install” is created for you, so a fresh install works out of the box.

A refused request returns this response, with a WWW-Authenticate: Bearer realm="MCP Core" header:

HTTP/1.1 401 Unauthorized
{"error":"Unauthorized"}

Where does the client put the token?

For MCP authentication, the standard place is the Authorization header with the Bearer scheme:

Authorization: Bearer YOUR_CONNECTION_TOKEN

Some connector screens only offer a fixed list of header names. For those, mcp-core also accepts the raw token (no Bearer prefix) in X-Api-Key, Api-Key, ApiKey, Api-Token, X-Auth-Token or X-Access-Token. Which header you use has no effect on what the connection can do.

What does the API key strategy do?

API key is the default for MCP authentication and the value your bundle ships with:

AUTH_STRATEGY=apikey

Each connection’s token is its API key. You copy it from My Account → Licenses, on the Connections tab of your license. This fits the standard setup: one self-hosted install per customer, behind your own firewall or reverse proxy.

Some clients, Claude Desktop’s custom connector among them, insist on an OAuth-style handshake during setup even when a static token is all that is needed. mcp-core answers that handshake on /oauth/authorize and /oauth/token without a real login:

  • The Connect AI link (/mcp/<token>) carries the token in the address. Most clients then need no handshake at all; when one starts it anyway, it passes that address and mcp-core completes the handshake for that connection.
  • If the client sends your connection token as the Client ID, mcp-core completes the handshake for that connection directly.
  • The code it hands out is single-use, expires after 10 minutes and is bound to the client’s PKCE challenge, which is required. The token is only handed over in the final /oauth/token exchange.

A request without a connection token gets a page titled “Seat link required” and no code. Versions before 2.3.1 showed a connection picker there, without a password; update with ./mcp-update.sh if you still run one. See secure your self-hosted MCP server.

When does the OAuth strategy apply?

The OAuth strategy adds a real login page, with username and password:

AUTH_STRATEGY=oauth

It is meant for a server that several people reach remotely, each with their own login. The user accounts are a local list on that installation, set in OAUTH_USERS; they are not your WordPress or AddoCore accounts. A login only works when the username is linked to a connection on the license. For a standard self-hosted install, keep apikey.

A login only sends its code to Claude’s own callback or a local address, unless you list other addresses in OAUTH_REDIRECT_URIS. PKCE is required, and after 10 wrong passwords from one address or for one username, logins wait 15 minutes.

Which endpoints skip MCP authentication?

A few routes are reachable without a token, because clients need them before they can authenticate:

  • /health: status and license state. Which tools are active is only shown to a connection, through mcp_status.
  • /.well-known/oauth-authorization-server and /.well-known/oauth-protected-resource: discovery metadata that some clients read first. The addresses in it come from SERVER_URL.
  • /oauth/authorize and /oauth/token: the handshake described above.

Everything else, including /mcp, /sse and /message, needs a valid token. The bundled compose file binds port 3200 to 127.0.0.1, so by default none of these routes are reachable from outside the host.

How do you rotate or revoke a token?

Use the Actions column on the Connections tab. Regenerate token issues a new token for that connection; Revoke removes the connection. Other connections keep working. The running server learns about the change at its next license check, so apply it right away with:

docker exec mcp-core npm run refresh-license

After a regenerate, update the token everywhere that connection is used. For “Default install” that includes BEARER_TOKEN in .env and claude-plugin/.mcp.json.

How do you keep MCP authentication safe on a network?

Keep the default 127.0.0.1 binding unless you need remote access. If you do, put a reverse proxy with HTTPS in front of the container, so tokens never travel in plain text, and set SERVER_URL to the public address. The server allows cross-origin requests from any origin, so the token is the only thing that stands between a caller and your tools. Treat it like a password: one per person or device, never shared in chat or committed to git.

The full list of what to check is in secure your self-hosted MCP server.

Which MCP authentication mistakes are common?

  • Using a token from another license, or one that was regenerated. The log shows Token rejected.
  • Sending Bearer in front of the token in an X-Api-Key header. Only Authorization uses the prefix.
  • Expecting a revoke to work before the next check. Run the refresh command.

With MCP authentication set up per connection, every person gets their own revocable token. Continue with MCP connections to create them, or connect Claude to the server. For how a token maps to tools, see entitlements vs tool modes.

Ready to connect your AI to real tools?

Start free trial