Machine Authentication

Purpose and Scope

Machine authentication is the client-side path for MCP integrations that run without an interactive end user. Use it for scheduled jobs, backend services, service accounts, gateways, and other workloads that must connect to a protected MCP server without opening a browser. The repository documentation separates this from two adjacent tasks: server operators should require authorization on the serving side, and user-facing clients should use the OAuth authorization-code flow. This page focuses on the no-user case and explains how credentials, bearer tokens, private-key assertions, and cross-app access all plug into the same transport option.

Sources: docs/clients/machine-auth.md, docs/clients/oauth.md, docs/serving/authorization.md

The common shape is intentionally simple: construct a client, construct a Streamable HTTP transport, and pass an authentication provider as the transport auth provider. Once connected, normal MCP client methods such as listing tools, calling tools, reading resources, and fetching prompts continue to behave like they do for any connected client. Authentication therefore belongs at the connection and HTTP-request layer, not inside every tool call. That boundary matters for maintainability because application code can choose credentials once and keep domain logic focused on MCP operations.

Sources: docs/clients/machine-auth.md, docs/clients/calling.md

Relevant Source Files

  • docs/clients/machine-auth.md - Primary how-to for client credentials, bearer-token providers, private-key JWT authentication, and cross-app access for non-interactive clients.
  • docs/clients/oauth.md - Defines the neighboring user OAuth flow and the shared transport auth provider concept that machine flows also use.
  • docs/serving/authorization.md - Explains how protected MCP servers validate bearer tokens, publish protected-resource metadata, and return OAuth challenges.
  • docs/serving/sessions-state-scaling.md - Describes HTTP session behavior and stateless serving patterns that affect long-running authenticated clients.
  • docs/clients/caching.md - Documents response caching, cache scopes, and per-user partitioning considerations for authenticated clients.
  • docs/clients/calling.md - Shows the connected-client operations that machine-authenticated clients typically perform after authentication succeeds.

Core Primitives

The main primitive for a shared-secret workload is ClientCredentialsProvider. It runs the OAuth client credentials grant from a client identifier and client secret, discovers the server authorization configuration during connect, posts to the token endpoint, and attaches the resulting access token to requests. The provider also handles a common operational edge case: when the server returns unauthorized, it refreshes the token and the transport retries once. For production systems, pin the issuer with the expected issuer option so a credential registered for one authorization server is not sent to another.

Sources: docs/clients/machine-auth.md

When another platform already owns the token, use the lower-level AuthProvider shape instead of asking the SDK to perform a grant. The minimal implementation supplies a token function, which the transport calls before each request to populate the authorization header. This is the right fit for API keys wrapped as bearer credentials, secrets injected by a gateway, or tokens retrieved from a cloud secret store. If the token can expire, add an unauthorized callback that refreshes or replaces it; without that callback, an unauthorized response becomes an UnauthorizedError rather than a transparent retry.

Sources: docs/clients/machine-auth.md

PrivateKeyJwtProvider covers the same client credentials use case but replaces the shared secret with a signed JWT assertion. This is useful when policy prefers asymmetric keys or when secrets must not be copied into multiple deployments. The provider accepts a PEM string, bytes, or a JWK object as the private key, signs a fresh assertion for each token request, and supports algorithm selection. The documentation calls out a default assertion lifetime of three hundred seconds, with options for a different lifetime and extra claims when an authorization server requires them.

Sources: docs/clients/machine-auth.md

Cross-App Access Flow

Cross-app access addresses a different enterprise problem: a service needs to reach an MCP server for a user who has already authenticated with an enterprise identity provider, without forcing a second consent screen. The documented flow names this Enterprise Managed Authorization and describes two exchanges. First, the identity provider token becomes a JWT authorization grant. Second, CrossAppAccessProvider exchanges that grant for an MCP access token. The provider receives an assertion callback, so application code can obtain or refresh the grant while the SDK owns the MCP-side token exchange.

Sources: docs/clients/machine-auth.md

This flow is still machine authentication because the MCP client is not driving an interactive browser login. It is also not the same as blindly reusing an enterprise identity token as an MCP bearer token. The MCP server remains a protected resource that expects an access token issued for that resource, while the identity provider token is only an input to the exchange. That separation helps preserve audience, issuer, and resource boundaries, and it matches the serving-side model where a resource server verifies tokens rather than issuing them itself.

Sources: docs/clients/machine-auth.md, docs/serving/authorization.md

Server Authorization Boundary

A machine-authenticated client only succeeds when the server side is configured as an OAuth resource server. The serving guide describes requireBearerAuth as the Express gate that validates bearer tokens before requests reach the MCP route. The verifier returns AuthInfo after local JWT verification, token introspection, or an identity-provider call. Missing, malformed, expired, or rejected tokens become unauthorized responses with bearer challenges, while valid tokens missing required scopes become forbidden responses. Those challenges are also how capable clients discover authorization metadata and begin the appropriate authentication flow.

Sources: docs/serving/authorization.md

Keep this boundary in mind when debugging. If the client credentials provider cannot discover the expected authorization server, fix protected-resource metadata and issuer configuration before changing client code. If the server rejects a token, inspect the verifier result, expiration, client identifier, and scopes. The serving documentation warns that an unset expiration can make a token invalid, so token verification should populate expiry from the JWT or introspection response. Machine authentication is therefore a contract between client provider configuration, authorization server metadata, and the server resource verifier.

Sources: docs/serving/authorization.md, docs/clients/machine-auth.md

Execution Flow

A practical setup starts by choosing the credential source. Use client credentials for a service account with a shared secret, private-key JWT for asymmetric client authentication, a custom bearer-token provider for externally managed credentials, and cross-app access when acting for an enterprise user through an approved token exchange. After constructing the provider, create a Streamable HTTP client transport for the MCP endpoint and pass the provider as authProvider. Then create the Client, connect it, and run normal MCP operations such as listTools, callTool, readResource, or prompt retrieval.

Sources: docs/clients/machine-auth.md, docs/clients/calling.md

import { Client, ClientCredentialsProvider, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
 
const authProvider = new ClientCredentialsProvider({
    clientId: 'reporting-job',
    clientSecret: 'reporting-job-secret'
});
 
const client = new Client({ name: 'reporting-job', version: '1.0.0' });
const transport = new StreamableHTTPClientTransport(new URL('https://api.example.com/mcp'), { authProvider });
 
await client.connect(transport);
const { tools } = await client.listTools();

Operational Considerations

Authenticated clients often run as shared infrastructure, so cache and session choices should preserve authorization boundaries. The caching guide says cacheable results depend on server hints and warns that public cache scope should only be used when a result is identical for every caller; anything derived from authorization context should remain private. If a shared response cache backs several principals, configure a partition based on the stable identity of the authorization context. This is especially important for gateways and cross-app access, where one process may act for many users or tenants.

Sources: docs/clients/caching.md, docs/clients/machine-auth.md

For HTTP serving, v2 handlers are stateless by default because the handler factory builds a fresh server instance for each request. Sessionful 2025-era deployments are different: they pin a client to a transport instance and require clients to send the session identifier on later requests. The SDK client transport returns that identifier automatically after initialization, but operators still need to understand how unknown sessions, missing headers, and shutdown cleanup behave. Machine clients that run for a long time should treat reconnects, token refresh, and session loss as normal recoverable events.

Sources: docs/serving/sessions-state-scaling.md, docs/clients/machine-auth.md

Compact Reference

  • ClientCredentialsProvider: uses client credentials with a client identifier and shared secret, discovers authorization metadata, obtains tokens, refreshes after unauthorized responses, and supports issuer pinning.
  • AuthProvider with token: supplies an externally managed bearer credential before each request; add an unauthorized handler when the credential can be refreshed.
  • PrivateKeyJwtProvider: performs client credentials with a signed JWT assertion, using a PEM string, bytes, or JWK private key plus algorithm, lifetime, and optional extra claims.
  • CrossAppAccessProvider: exchanges an application-supplied assertion grant for an MCP access token in enterprise cross-app access scenarios.
  • StreamableHTTPClientTransport authProvider option: the shared integration point for all machine authentication strategies described here.

Next Steps

After authentication is working, validate the whole workflow by calling a simple operation such as listing tools, then add the specific tool, resource, and prompt calls your workload needs. If you operate the server, read the authorization guide next so bearer challenges, scopes, protected-resource metadata, and token verification match the client configuration. If the workload acts for multiple users or tenants, review caching and sessions before deploying a shared gateway, because those pages explain the state and partitioning rules that keep authenticated results isolated.