This is the documentation for v2 — looking for the v1 documentation?
Skip to content

MCP TypeScript SDK (V2) / @modelcontextprotocol/client / client/middleware

client/middleware ​

Type Aliases ​

DpopSessionSource ​

DpopSessionSource = DpopSession | (() => DpopSession | undefined | Promise<DpopSession | undefined>)

Defined in: packages/client/src/client/middleware.ts:123

A DpopSession, or a function resolving to one (or to undefined to leave the request untouched). The function form lets the session be created lazily or come from OAuthClientProvider.dpop. See withDpop.


DpopTokenSource ​

DpopTokenSource = () => string | undefined | Promise<string | undefined>

Defined in: packages/client/src/client/middleware.ts:116

A function returning the current access token, or undefined if none is available yet. See withDpop.

Returns ​

string | undefined | Promise<string | undefined>


LoggingOptions ​

LoggingOptions = object

Defined in: packages/client/src/client/middleware.ts:236

Configuration options for the logging middleware

Properties ​

includeRequestHeaders? ​

optional includeRequestHeaders?: boolean

Defined in: packages/client/src/client/middleware.ts:246

Whether to include request headers in logs

Default ​
ts
false
includeResponseHeaders? ​

optional includeResponseHeaders?: boolean

Defined in: packages/client/src/client/middleware.ts:252

Whether to include response headers in logs

Default ​
ts
false
logger? ​

optional logger?: RequestLogger

Defined in: packages/client/src/client/middleware.ts:240

Custom logger function, defaults to console logging

statusLevel? ​

optional statusLevel?: number

Defined in: packages/client/src/client/middleware.ts:259

Status level filter - only log requests with status >= this value Set to 0 to log all requests, 400 to log only errors

Default ​
ts
0

Middleware ​

Middleware = (next) => FetchLike

Defined in: packages/client/src/client/middleware.ts:14

Middleware function that wraps and enhances fetch functionality. Takes a fetch handler and returns an enhanced fetch handler.

Parameters ​

next ​

FetchLike

Returns ​

FetchLike


RequestLogger ​

RequestLogger = (input) => void

Defined in: packages/client/src/client/middleware.ts:222

Logger function type for HTTP requests

Parameters ​

input ​
duration ​

number

error? ​

Error

method ​

string

requestHeaders? ​

Headers

responseHeaders? ​

Headers

status ​

number

statusText ​

string

url ​

string | URL

Returns ​

void

Functions ​

applyMiddlewares() ​

applyMiddlewares(...middleware): Middleware

Defined in: packages/client/src/client/middleware.ts:369

Composes multiple fetch middleware functions into a single middleware pipeline. Middleware are applied in the order they appear, creating a chain of handlers.

Parameters ​

middleware ​

...Middleware[]

Array of fetch middleware to compose into a pipeline

Returns ​

Middleware

A single composed middleware function

Example ​

ts
// Create a middleware pipeline that handles both OAuth and logging
const enhancedFetch = applyMiddlewares(withOAuth(oauthProvider, 'https://api.example.com'), withLogging({ statusLevel: 400 }))(fetch);

// Use the enhanced fetch - it will handle auth and log errors
const response = await enhancedFetch('https://api.example.com/data');

createMiddleware() ​

createMiddleware(handler): Middleware

Defined in: packages/client/src/client/middleware.ts:437

Helper function to create custom fetch middleware with cleaner syntax. Provides the next handler and request details as separate parameters for easier access.

Parameters ​

handler ​

(next, input, init?) => Promise<Response>

Function that receives the next handler and request parameters

Returns ​

Middleware

A fetch middleware function

Example ​

ts
// Create custom authentication middleware
const customAuthMiddleware = createMiddleware(async (next, input, init) => {
    const headers = new Headers(init?.headers);
    headers.set('X-Custom-Auth', 'my-token');

    const response = await next(input, { ...init, headers });

    if (response.status === 401) {
        console.log('Authentication failed');
    }

    return response;
});

// Create conditional middleware
const conditionalMiddleware = createMiddleware(async (next, input, init) => {
    const url = typeof input === 'string' ? input : input.toString();

    // Only add headers for API routes
    if (url.includes('/api/')) {
        const headers = new Headers(init?.headers);
        headers.set('X-API-Version', 'v2');
        return next(input, { ...init, headers });
    }

    // Pass through for non-API routes
    return next(input, init);
});

// Create caching middleware
const cacheMiddleware = createMiddleware(async (next, input, init) => {
    const cacheKey = typeof input === 'string' ? input : input.toString();

    // Check cache first
    const cached = await getFromCache(cacheKey);
    if (cached) {
        return new Response(cached, { status: 200 });
    }

    // Make request and cache result
    const response = await next(input, init);
    if (response.ok) {
        await saveToCache(cacheKey, await response.clone().text());
    }

    return response;
});

withDpop() ​

withDpop(session, getToken): Middleware

Defined in: packages/client/src/client/middleware.ts:150

Creates a fetch wrapper that presents an access token using the DPoP Authorization scheme (RFC 9449 / SEP-1932) instead of Bearer: every request carries Authorization: DPoP <token> plus a fresh DPoP proof bound to that request's method and URL, a resource-server use_dpop_nonce challenge (RFC 9449 §9) is retried once, inline, with the server-supplied nonce, and a DPoP-Nonce delivered on any response is remembered for the next proof (RFC 9449 §8.2).

Because it wraps fetch itself, the proof is always bound to the request actually sent and every response is observed — which is why the MCP transports apply this wrapper internally (via withDpopFromProvider) when their authProvider implements dpop(), rather than threading request context through AuthProvider.

Use this directly when you already manage the access token yourself (a non-OAuth token source, or credentials obtained out-of-band) and only need DPoP's request-signing behavior — e.g. fetch: withDpop(session, getToken)(fetch) alongside a minimal authProvider: { token }.

Parameters ​

session ​

DpopSessionSource

The DPoP signing session (key pair + nonce state), or a function resolving to it. Reuse the same session across requests to the same server so its nonce state persists. When the function resolves to undefined the request passes through unchanged.

getToken ​

DpopTokenSource

Returns the current access token, or undefined if none is available (the request passes through unchanged — any Authorization header already on it is left as is).

Returns ​

Middleware

A fetch middleware function


withDpopFromProvider() ​

withDpopFromProvider(provider): Middleware

Defined in: packages/client/src/client/middleware.ts:199

withDpop driven by an OAuthClientProvider: the session comes from provider.dpop() and the token from provider.tokens() — presented with the DPoP scheme only when the AS actually issued token_type: "DPoP" (RFC 9449 §7.1); a Bearer token passes through untouched.

This is what the MCP transports and withOAuth compose internally when the provider implements dpop(). Use it directly only when building your own fetch pipeline around an OAuthClientProvider (e.g. a custom re-authorization middleware) — place it innermost, below whatever sets Authorization: Bearer and handles 401 re-authentication.

Parameters ​

provider ​

OAuthClientProvider

Returns ​

Middleware


withLogging() ​

withLogging(options?): Middleware

Defined in: packages/client/src/client/middleware.ts:278

Creates a fetch middleware that logs HTTP requests and responses.

When called without arguments withLogging(), it uses the default logger that:

  • Logs successful requests (2xx) to console.log
  • Logs error responses (4xx/5xx) and network errors to console.error
  • Logs all requests regardless of status (statusLevel: 0)
  • Does not include request or response headers in logs
  • Measures and displays request duration in milliseconds

Important: the default logger uses both console.log and console.error so it should not be used with stdio transports and applications.

Parameters ​

options? ​

LoggingOptions = {}

Logging configuration options

Returns ​

Middleware

A fetch middleware function


withOAuth() ​

withOAuth(provider, baseUrl?): Middleware

Defined in: packages/client/src/client/middleware.ts:47

Creates a fetch wrapper that handles OAuth authentication automatically.

This wrapper will:

  • Add Authorization headers with access tokens
  • Handle 401 responses by attempting re-authentication
  • Retry the original request after successful auth
  • Handle OAuth errors appropriately (OAuthErrorCode.InvalidClient, etc.)
  • When provider.dpop() is implemented, present DPoP-bound tokens with the DPoP scheme plus a per-request proof (RFC 9449 / SEP-1932) by composing withDpopFromProvider underneath — so a use_dpop_nonce challenge is retried inline on every attempt, independently of the single re-authentication retry here

The baseUrl parameter is optional and defaults to using the domain from the request URL. However, you should explicitly provide baseUrl when:

  • Making requests to multiple subdomains (e.g., api.example.com, cdn.example.com)
  • Using API paths that differ from OAuth discovery paths (e.g., requesting /api/v1/data but OAuth is at /)
  • The OAuth server is on a different domain than your API requests
  • You want to ensure consistent OAuth behavior regardless of request URLs

For MCP transports, set baseUrl to the same URL you pass to the transport constructor.

Note: This wrapper is designed for general-purpose fetch operations. MCP transports (SSE and StreamableHTTP) already have built-in OAuth handling and should not need this wrapper.

Parameters ​

provider ​

OAuthClientProvider

OAuth client provider for authentication

baseUrl? ​

string | URL

Base URL for OAuth server discovery (defaults to request URL domain)

Returns ​

Middleware

A fetch middleware function