Skip to main content
Version: 1.12.0

Authenticate to an MCP server with more than a bearer token

Many MCP servers do not take Authorization: Bearer <token>. One wants X-API-Key. Another wants Authorization: Token <key>, or a user name and password. A vendor's server may also want a tenant header next to the key, or a header that says which end user is calling so it can apply its own limits.

From 1.9.0, each MCP server in DVARA has an Upstream Authentication setting. It says where the credential goes, which other headers go with it, and which of the caller's own headers are passed on. It works the same on every HTTP transport. A STDIO server is a local process, so it gets no headers.

When DVARA reads the server's tool list, no caller is behind the request. So DVARA sends the credential and the fixed and secret headers, but no header filled from a placeholder and no forwarded header.

Where the credential goes​

The credential is still the one Credential Reference names: a credential on the Credentials page, named by its secret key. Read The secret key a reference names first: today that key can only be a provider slot. Choose how the credential is sent:

PlacementWhat the server receives
Bearer (default)Authorization: Bearer <credential>
HeaderThe header you name, such as X-API-Key: <credential>. Add a scheme to get Authorization: Token <credential>.
BasicAuthorization: Basic ..., built from a credential that holds user:password.

A server you registered before 1.9.0 keeps sending what it sent before. For most servers that is a bearer token. A REST_BRIDGE server that names its own auth header keeps sending the raw credential in that header, with no scheme.

Extra headers​

Add one header per line, as Name: value. A value can be one of three kinds:

You writeIt sends
X-Region: eu-westThe text as written. Use this only for values that are not secret.
X-Vendor-Key: secret:provider.cohere.api-keyThe credential with that secret key, from the Credentials page. The key can only be a provider slot; see The secret key a reference names. The value is never stored on the server, shown on the page, written to a record or put in an export.
X-User: {{user.id}}A value filled from the caller, so the server can scope the call to that user.

The placeholders are {{user.id}}, {{workspace.id}}, {{key.id}}, {{auth.issuer}}, {{client.id}} and, for callers who sign in with OAuth, {{claim.<name>}} for a claim in their token.

DVARA does not guess. If a secret cannot be found, or the caller has no value for a placeholder, the call is refused with MCP_UPSTREAM_AUTH_REFUSED and nothing is sent to the server.

The secret key a reference names​

A reference names a credential by its secret key, not by its name. That holds for Credential Reference, for a secret: header, and for a Client Secret Reference. DVARA looks for the key only among the credentials of the workspace that owns the server or agent.

Today the Credentials page does not let you type a secret key, and no page shows it. The page sets it from the provider you pick:

  • provider.<provider>.api-key for every provider but AWS Bedrock, such as provider.openai.api-key or provider.cohere.api-key.
  • provider.bedrock.access-key or provider.bedrock.secret-key for AWS Bedrock, from its AWS key field.

So a reference can only name one of these provider slots. That has a cost:

  • It replaces that provider's key. A credential in a provider slot is also the workspace's key for that LLM provider. Store an MCP server's key as provider.openai.api-key, and the workspace's OpenAI calls send it too. Pick the slot of a provider the workspace never calls.
  • One active credential per key. A workspace holds one active credential for each secret key. If it already has an OpenAI key, a second credential for provider.openai.api-key is refused.
  • No other way in. A GitOps import does not create credentials.

Passing on the caller's headers​

Nothing the caller sends is passed on by default. To pass a header on, list it under Forward Client Headers, for example X-Tenant-Id. Only the headers you list reach the server. A listed header the caller did not send is simply not sent.

What cannot be set​

Some headers decide how the request is read, or carry the caller's identity. They can never be set or passed on: Authorization (except as the credential), cookies, Host, Content-Length and the other framing headers, connection headers, the MCP protocol's own headers (Mcp-*), trace headers, and DVARA's own (X-Dvara-*). A value with a line break is refused, so one header can never be turned into two. These rules apply when you save the server, when a configuration file is imported, and again on every call.

What the records show​

Records name headers, never their values:

  • Each tool call records how DVARA authenticated (bearer, header or basic) and the names of the headers it sent.
  • Saving a server records the placement and each header's name and kind.
  • A refused call records the reason and the header's name.
  • Pointing a secret header at another credential, or rotating the credential it names, is recorded with a fingerprint of the old and new value, as for the server's main credential.

An export writes each secret header's reference as ***. Importing the file back keeps the reference you had.

Where to set it​

Open the MCP server's page in Flightdeck and use the Upstream Authentication section. Platform administrators have it, and so do workspace admins and developers. A secret header must name a credential that belongs to the server's workspace.