Skip to main content

Interface: McpAuthOptions

Defined in: index.ts:36

Authentication options for the MCP endpoint. Verification runs through @ttoss/http-server-auth's oauth strategy; supply either a Cognito user pool or a custom verifyToken.

Properties

authorizationServerUrl?

optional authorizationServerUrl?: string

Defined in: index.ts:124

URL of the OAuth Authorization Server that issues tokens for this resource.


cognitoUserPool?

optional cognitoUserPool?: CognitoUserPoolConfig

Defined in: index.ts:38

Amazon Cognito user pool config; a CognitoJwtVerifier is built from it.


publicMethods?

optional publicMethods?: string[]

Defined in: index.ts:82

JSON-RPC methods (read from body.method) that bypass verification.

The lifecycle handshake is public because the MCP authorization spec sanctions it: a client completes it before it can discover the authorization server. That means one entry per protocol era — initialize on 2025, server/discover on 2026-07-28, which removed initialize — so neither era is left unable to negotiate. Nothing else is public, so a server with auth configured serves no tool metadata to an unauthenticated caller.

Opening tools/list is a deliberate choice, not a default. It serves the full tool catalogue — every name, description, and input schema — to anyone who can reach the endpoint, which for an OpenAPI-derived server is a map of the whole underlying API. It buys an OAuth client nothing: the 401 and its RFC 9728 WWW-Authenticate challenge are what start the authorization flow, and a client that lists tools anonymously still cannot call one. Set it only to serve callers that will never authenticate.

Default

['initialize', 'server/discover']

Example

// Restore unauthenticated tool discovery.
publicMethods: ['initialize', 'tools/list'],

// Require a token for the handshake too, so an OAuth client
// self-discovers from its very first request.
publicMethods: [],

requiredScopes?

optional requiredScopes?: string[]

Defined in: index.ts:49

Scopes that must all be present on the token, else 403. verifyToken may return either scope: string (space-separated) or scopes: string[]; both are normalised internally.


resourceIndicator?

optional resourceIndicator?: string | string[]

Defined in: index.ts:140

Expected audience — the resource indicator (RFC 8707) this MCP server identifies as. When set, the verified token's aud claim must include at least one of these values, or the request is rejected with 401. Without this check, a token minted for a different resource but signed by the same authorization server would still be accepted here — the classic confused-deputy risk RFC 8707 exists to close.

Applies uniformly regardless of whether verification is done via cognitoUserPool, a custom verifyToken, or @ttoss/auth-core/oidc's createOidcVerifier (which intentionally leaves audience validation to the caller for this reason).

Example

'https://mcp.example.com'

resourceMetadataUrl?

optional resourceMetadataUrl?: string

Defined in: index.ts:116

URL advertised in WWW-Authenticate: Bearer resource_metadata="…" (RFC 9728) on a 401, so MCP clients can discover the authorization server.

Defaults to the location derived from resourceServerUrl + path — the same location this router serves the document at — so the header cannot drift from the routes. The default applies only when the document is actually served (both resourceServerUrl and authorizationServerUrl set); otherwise the header stays a bare Bearer rather than advertising a location with no route.

Leave it unset when this router serves the document. It exists for the one configuration where that is deliberately not the case: an authorization server in the same deployment (oauthServer({ resource })) already answers /.well-known/oauth-protected-resource, so mounting this router with resourceServerUrl + authorizationServerUrl too would put two routers on one path. Omit both there and set this instead — without it the 401 is a bare Bearer, which never starts a client's discovery.

Derive the value rather than typing it: protectedResourceMetadataUrl from @ttoss/auth-core applies the same RFC 9728 §3.1 rule the serving side does. A hand-written value that names a location nothing serves fails discovery silently.

Example

// Only when oauthServer (not this router) serves the document.
resourceMetadataUrl: protectedResourceMetadataUrl({
resource: 'https://mcp.example.com/mcp',
}),

resourceServerUrl?

optional resourceServerUrl?: string

Defined in: index.ts:122

URL of this MCP server, surfaced in the OAuth Protected Resource Metadata response. Both this and authorizationServerUrl must be set to serve /.well-known/oauth-protected-resource.


verifyToken?

optional verifyToken?: (token) => Promise<unknown>

Defined in: index.ts:43

Custom token verifier for non-Cognito providers (Auth0, Keycloak, your own JWTs, opaque tokens). Resolve with the verified payload, or throw to reject.

Parameters

ParameterType
tokenstring

Returns

Promise<unknown>