@modelcontextprotocol/client API
Purpose and Scope
The @modelcontextprotocol/client package is the high-level SDK surface for building MCP clients in TypeScript. A client owns one connection to one MCP server, negotiates the protocol during connect(), and then exposes convenience methods for the capabilities the server advertised. Use this package when your application needs to discover tools, call tools, read resources, fetch prompts, authenticate to protected MCP endpoints, wrap HTTP requests, or cache server responses. The companion @modelcontextprotocol/client/stdio subpath covers local child-process servers that communicate over standard input and output.
Sources: docs/clients/connect.md, docs/clients/calling.md
The public API is intentionally centered on a small set of primitives. Client represents the session and capability-aware request surface. A transport, such as StreamableHTTPClientTransport, SSEClientTransport, or StdioClientTransport, provides the wire connection. Authentication providers attach credentials to HTTP transports. Middleware wraps the transport fetch function. The response cache sits behind cacheable client methods and is configured through Client options. These pieces compose: construct a Client, construct a transport with any auth, middleware, or custom fetch behavior, call connect(), then call tools, resources, prompts, or other verbs.
Sources: docs/clients/connect.md, docs/clients/oauth.md, docs/clients/machine-auth.md, docs/clients/middleware.md, docs/clients/caching.md
Relevant Source Files
docs/clients/connect.md- Defines the core connection workflow,Clientconstruction, HTTP and stdio transports, SSE fallback, handshake introspection, protocol negotiation option, and clean disconnect behavior.docs/clients/calling.md- Documents the main post-connect request methods: listing and calling tools, automatic pagination, structured output validation, resource reads, prompt retrieval, and completion-oriented calls.docs/clients/oauth.md- Describes user OAuth throughOAuthClientProvider,UnauthorizedError, callback completion, discovery state, issuer binding, dynamic client registration, PKCE, and resource indicators.docs/clients/machine-auth.md- Covers machine-to-machine auth helpers includingClientCredentialsProvider, bearer-tokenAuthProvider,PrivateKeyJwtProvider,CrossAppAccessProvider, and token exchange behavior.docs/clients/middleware.md- DocumentscreateMiddleware,applyMiddlewares,withLogging,withOAuth, middleware ordering, and the distinction between client middleware and server framework adapters.docs/clients/caching.md- Documents response caching,cacheMode,responseCacheStore,InMemoryResponseCacheStore,ResponseCacheStore, cache partitions, cache hints, and cacheable verbs.
Core Construction and Transports
Create a client with a name and version, then connect it to a transport. For HTTP MCP endpoints, the documented transport is StreamableHTTPClientTransport, constructed with the server MCP endpoint URL. client.connect(transport) runs the initialize handshake and resolves only after negotiation completes. After that point, the client records the negotiated protocol version, the server capabilities, and any instructions the server provided. Until connection succeeds, introspection helpers such as getServerVersion(), getServerCapabilities(), and getInstructions() return no server data.
Sources: docs/clients/connect.md
import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const client = new Client({ name: 'my-client', version: '1.0.0' });
const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp'));
await client.connect(transport);For a local process, import StdioClientTransport from @modelcontextprotocol/client/stdio. That transport spawns a command, speaks JSON-RPC over the child process stdin and stdout, and participates in the same Client API once connected. The docs also identify InMemoryTransport.createLinkedPair() as the in-process option for tests or embedded server/client pairs, and SSEClientTransport as the fallback for older SSE-only servers. The recommended fallback pattern creates a fresh Client for the SSE retry, so failed HTTP negotiation state does not leak into the second attempt.
Sources: docs/clients/connect.md
Disconnecting is transport-aware. With Streamable HTTP, terminate the server-side session through the transport, then close the client. With stdio, close() shuts down the child process in order by closing stdin, then escalating to SIGTERM, then SIGKILL if needed. Treat the transport as the owner of wire-level lifetime and the Client as the owner of MCP request state. The ClientOptions.versionNegotiation setting controls which protocol revision connect() negotiates, while the rest of the client method surface remains transport-independent after connection.
Sources: docs/clients/connect.md
Request API Components
The main request methods operate on a connected Client. listTools() returns the tools a server advertises, and callTool({ name, arguments }) invokes a named tool. Tool results return their content array unchanged. A failed tool invocation is still represented as a tool result, so callers should inspect isError before trusting returned content. Protocol-level failures, such as an unknown tool or timeout, throw instead. When a tool declares an outputSchema, structured results appear as structuredContent; the docs recommend treating it as unknown and narrowing before use.
Sources: docs/clients/calling.md
const { tools } = await client.listTools();
const result = await client.callTool({
name: 'lookup-order',
arguments: { id: 'A-1041' }
});List methods hide normal pagination by default. listTools(), listPrompts(), listResources(), and listResourceTemplates() follow nextCursor page by page and return one aggregated result with no final cursor. If the application passes an explicit cursor, the SDK returns exactly that page without aggregation. ClientOptions.listMaxPages caps automatic walks, with a default of 64 pages; setting it to 0 removes the cap. If a server never terminates pagination, the SDK rejects with an SdkError whose code is LIST_PAGINATION_EXCEEDED.
Sources: docs/clients/calling.md
Resources and prompts follow the same connected-client pattern. listResources() names server resources, and readResource({ uri }) returns contents entries with the resource uri, a mimeType, and either text or base64 blob data. Parameterized resources are discovered through listResourceTemplates() and then read by expanding a URI template yourself. Prompt APIs let clients discover prompts and retrieve prompt messages with arguments. Completion support lets clients request autocomplete-style values for prompt or resource arguments when the server exposes that capability.
Sources: docs/clients/calling.md
Authentication Helpers
HTTP transports accept an authProvider option. For end-user login, implement OAuthClientProvider and pass it to StreamableHTTPClientTransport. When a protected server challenges the client and no token is available, the SDK performs discovery, registers or looks up the OAuth client, calls redirectToAuthorization(url), and causes connect() to throw UnauthorizedError while the user completes authorization out of band. The callback handler later resumes the flow by completing authorization with the provider's stored PKCE verifier, state, tokens, and discovery data.
Sources: docs/clients/oauth.md
An OAuthClientProvider is both storage and browser hand-off surface. The docs show provider methods for client information, saved tokens, PKCE verifier state, generated CSRF state, discovery state, and redirect URL metadata. Client credentials should be keyed by issuer, so a client_id registered with one authorization server is never reused against another. With protocol negotiation, an authorization failure during connect can also appear as an SdkError whose data carries the UnauthorizedError cause, so robust clients should handle both shapes.
Sources: docs/clients/oauth.md
For machine clients, ClientCredentialsProvider runs the OAuth client_credentials grant from clientId and clientSecret. PrivateKeyJwtProvider runs the same grant but authenticates the token request with a signed JWT assertion instead of a shared secret. A minimal bearer-token provider can implement AuthProvider with token(), and optionally onUnauthorized(ctx) to refresh credentials after a 401 and retry once. CrossAppAccessProvider supports enterprise cross-app access by exchanging an assertion for an MCP access token.
Sources: docs/clients/machine-auth.md
Middleware and Fetch Customization
Client middleware is not the same as Express, Hono, or Node server middleware. In this package, middleware wraps the fetch used by an HTTP client transport, so it sees SDK-generated requests such as initialize as well as application-triggered calls. createMiddleware builds a middleware from a function that receives the next fetch handler plus the request input and init. applyMiddlewares composes one or more middleware layers and returns a fetch-compatible function that can be passed into StreamableHTTPClientTransport through its fetch option.
Sources: docs/clients/middleware.md
import { applyMiddlewares, createMiddleware, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
const tagRequests = createMiddleware(async (next, input, init) => {
const headers = new Headers(init?.headers);
headers.set('X-Request-Source', 'reports-cli');
return next(input, { ...init, headers });
});
const transport = new StreamableHTTPClientTransport(new URL('http://localhost:3000/mcp'), {
fetch: applyMiddlewares(tagRequests)(fetch)
});Middleware order is explicit. applyMiddlewares accepts multiple middleware values; the last one passed is outermost and sees the request first and response last, while the first sits closest to the network. The docs recommend putting retry behavior close to the network so higher layers observe one settled response. Built-in withLogging() logs outgoing HTTP activity and supports options such as statusLevel, includeRequestHeaders, includeResponseHeaders, and a custom logger. In stdio-owning processes, use a logger that avoids stdout to keep the JSON-RPC stream clean.
Sources: docs/clients/middleware.md
Response Cache Reference
Every Client has a response cache. Cacheable verbs check it before sending a request: listTools(), listPrompts(), listResources(), listResourceTemplates(), and readResource(). With the default cacheMode: 'use', a fresh cached entry is served locally; otherwise the request is sent and the result may be stored. cacheMode: 'refresh' always refetches and stores the new result. cacheMode: 'bypass' fetches without reading or writing the cache, leaving existing entries untouched.
Sources: docs/clients/caching.md
Server hints control whether a response is reusable. Without a freshness hint, the SDK emits ttlMs: 0, so clients never serve the result from cache. The docs describe server cacheHints and per-resource cacheHint values, including ttlMs and cacheScope. Client behavior still matters: Client caps cache TTLs at 24 hours, and the default backing store is a fresh InMemoryResponseCacheStore per client holding up to 512 resources/read entries. A custom responseCacheStore can replace that backing store.
Sources: docs/clients/caching.md
Shared stores should be partitioned by authorization context. When one backing store serves multiple users or principals, pass cachePartition to the Client options using a stable identity such as the authenticated subject. Entries are keyed by connected-server identity, so different servers do not collide in one store, but private results for different principals still need partitioning. The ResponseCacheStore interface allows asynchronous methods, making Redis-style or database-backed implementations viable for gateways and long-running applications.
Sources: docs/clients/caching.md
Compact API Reference
| Area | Public names and options demonstrated by the docs | Behavior |
|---|---|---|
| Client construction | Client({ name, version }, options?) | Creates one MCP client session object for one server connection. |
| HTTP transport | StreamableHTTPClientTransport(url, options?) | Connects to a Streamable HTTP MCP endpoint; accepts authProvider and custom fetch. |
| Stdio subpath | @modelcontextprotocol/client/stdio, StdioClientTransport({ command, args }) | Spawns a local server process and communicates over stdin/stdout. |
| Legacy HTTP fallback | SSEClientTransport(url) | Connects to older SSE-only servers after Streamable HTTP fails. |
| Introspection | getServerVersion(), getServerCapabilities(), getInstructions() | Returns handshake data after connect() resolves. |
| Calls | listTools, callTool, listResources, readResource, listPrompts, listResourceTemplates | Discovers and invokes server capabilities; list methods aggregate pages unless passed a cursor. |
| OAuth | OAuthClientProvider, UnauthorizedError | Drives browser-based authorization-code login and callback completion. |
| Machine auth | ClientCredentialsProvider, PrivateKeyJwtProvider, CrossAppAccessProvider, AuthProvider | Supplies bearer tokens or obtains them through OAuth-style machine flows. |
| Middleware | createMiddleware, applyMiddlewares, withLogging, withOAuth | Wraps transport fetch for headers, tracing, logging, auth, retries, and response inspection. |
| Caching | cacheMode, responseCacheStore, cachePartition, InMemoryResponseCacheStore, ResponseCacheStore | Controls local reuse of cacheable responses according to server freshness hints. |
Next Steps
Start with docs/clients/connect.md if you need to wire a transport, then move to docs/clients/calling.md for the request surface. Add docs/clients/oauth.md for interactive users or docs/clients/machine-auth.md for jobs and services. Use docs/clients/middleware.md when you need request instrumentation or custom HTTP behavior, and docs/clients/caching.md when repeated discovery or resource reads should be served locally. For package selection and migration details, continue to the installation and upgrade pages in this wiki.