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?
optionalincludeRequestHeaders?:boolean
Defined in: packages/client/src/client/middleware.ts:246
Whether to include request headers in logs
Default
falseincludeResponseHeaders?
optionalincludeResponseHeaders?:boolean
Defined in: packages/client/src/client/middleware.ts:252
Whether to include response headers in logs
Default
falselogger?
optionallogger?:RequestLogger
Defined in: packages/client/src/client/middleware.ts:240
Custom logger function, defaults to console logging
statusLevel?
optionalstatusLevel?: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
0Middleware
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
Returns
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
A single composed middleware function
Example
// 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
A fetch middleware function
Example
// 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
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
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
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
Returns
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
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
Authorizationheaders 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 theDPoPscheme plus a per-request proof (RFC 9449 / SEP-1932) by composingwithDpopFromProviderunderneath — so ause_dpop_noncechallenge 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
OAuth client provider for authentication
baseUrl?
string | URL
Base URL for OAuth server discovery (defaults to request URL domain)
Returns
A fetch middleware function