Authentication
Configure API key, bearer, basic and OAuth2 client-credentials auth for generated MCP servers using environment variables and wrangler secrets.
By Harsha VardhanUpdated
The generated server authenticates to your upstream API using the security schemes declared in your OpenAPI spec. Credentials are read at runtime, never baked into the generated source.
Supported schemes#
| Auth type | Environment variables |
|---|---|
| API key | API_KEY_<SCHEME_NAME> |
| Bearer | BEARER_TOKEN_<SCHEME_NAME> |
| Basic | BASIC_USERNAME_<SCHEME_NAME>, BASIC_PASSWORD_<SCHEME_NAME> |
| OAuth2, any flow | OAUTH_TOKEN_<SCHEME_NAME>, a token you already obtained |
| OAuth2 client credentials | OAUTH_CLIENT_ID_<SCHEME_NAME>, OAUTH_CLIENT_SECRET_<SCHEME_NAME> and optional OAUTH_SCOPES_<SCHEME_NAME>. The server fetches the token and caches it until shortly before it expires. |
| OpenID Connect | OPENID_TOKEN_<SCHEME_NAME> |
Authorization code, implicit and password flows need OAUTH_TOKEN_<SCHEME_NAME>. The server only fetches tokens itself with the client credentials grant.
Each variable is the prefix plus the security scheme name from your spec's components.securitySchemes, upper-cased, with every character that is not a letter or digit replaced by _. For example, a scheme called petstore-auth uses API_KEY_PETSTORE_AUTH. The generated .env.example lists the exact names for your spec.
Details:
- API keys can be sent in a header, query parameter or cookie, as the spec declares.
- HTTP basic works with an empty password. Only a username is required.
- HTTP scheme names are matched case-insensitively, so
BasicandBearerwork. - OAuth2 client credentials are sent in a Basic
Authorizationheader by default. Use--oauth-creds-in-bodyto send them in the token request body instead. Tokens are requested with the operation's scopes unlessOAUTH_SCOPES_<SCHEME_NAME>overrides them.
Missing credentials fail closed#
An operation's security list holds alternatives: the first requirement whose schemes are all configured is used, and every scheme inside one requirement is applied together. A header forwarded with --header-passthrough counts as configured.
If no requirement can be satisfied and the operation does not allow anonymous access with an empty {} requirement, the tool does not call your API. It returns an error naming what to set, for example:
Missing credentials for 'getPet': set API_KEY_PETSTORE_AUTH.Set MCP_ALLOW_MISSING_CREDENTIALS=true (a vars entry for Workers) to send such requests without credentials instead.
Local servers: .env#
Node-based transports (stdio, web, streamable-http) read credentials from the environment. The generated project includes .env.example:
cp .env.example .envAPI_KEY_PETSTORE_AUTH=your-key-here
# API_BASE_URL=https://staging.example.comAPI_BASE_URL overrides the server URL from your spec, so leave it unset unless you need another environment. The .env.example generated by 5.0.0 sets it to the placeholder your_api_base_url_here; delete or comment out that line after copying. The next release ships it commented out.
Keep .env out of version control.
Cloudflare Workers: wrangler secrets#
For --transport=cloudflare-worker, secrets are set with Wrangler and read from the Worker's env binding. They are never committed:
npx wrangler secret put <SCHEME>_API_KEYWorker secret names put the scheme name first (upper-cased, with every character that is not a letter or digit replaced by _):
| Auth type | Wrangler secrets |
|---|---|
| API key | <SCHEME>_API_KEY |
| Bearer and other HTTP schemes | <SCHEME>_TOKEN |
| Basic | <SCHEME>_USERNAME, <SCHEME>_PASSWORD |
| OAuth2 client credentials | <SCHEME>_CLIENT_ID, <SCHEME>_CLIENT_SECRET, plus <SCHEME>_TOKEN_URL when the spec has no token URL |
Generic fallbacks are also read: API_KEY, API_TOKEN, API_USERNAME, API_PASSWORD, OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET and OAUTH_TOKEN_URL. The generated .dev.vars.example lists the exact names for your spec.
OpenID Connect schemes read <SCHEME>_TOKEN. Non-secret configuration such as API_BASE_URL lives under vars in wrangler.jsonc. For local development, copy .dev.vars.example to .dev.vars and fill in values. The generated .gitignore excludes .dev.vars.
Per-user credentials#
By default every caller of the MCP server shares the credentials you configure. For web, streamable-http and cloudflare-worker, --header-passthrough forwards selected inbound headers to the upstream API so each MCP client can send its own key and the server stores no shared secret:
openapi-mcp-generator -i ./openapi.json -o ./my-mcp --transport=streamable-http --header-passthrough X-API-KeyA forwarded header satisfies the scheme whose credential travels in it; other schemes of the same requirement still come from server configuration. Authorization cannot be forwarded while --inbound-auth bearer is on, because that header carries the MCP token.
Protecting the MCP endpoint#
Callers of your MCP server authenticate separately, with --inbound-auth bearer and MCP_AUTH_TOKEN. See Security model.
Custom auth#
--custom-auth generates an editable src/auth.ts hook, applyCustomAuth, that runs before built-in auth. Return true to skip the built-in handling. This flag does not apply to the Cloudflare Worker target.