Connect a Client
Purpose and Scope
Use this page when you need to turn an MCP endpoint into a connected SDK Client. In this SDK, a client represents one connection to one server. The shape is intentionally simple: construct Client with your client name and version, choose a transport that matches where the server runs, and call connect(). The connection step runs the MCP initialize handshake, after which the client has the negotiated protocol revision, the server capabilities, and any server instructions that should guide downstream model behavior.
Sources: docs/clients/connect.md
Most application code should be transport-independent after connection. A server reached through Streamable HTTP, legacy SSE, stdio, or an in-process test transport is still driven through the same high-level client verbs such as listTools(), callTool(), readResource(), and prompt APIs. That separation matters because it lets you start locally with stdio or in-memory testing, then move to hosted HTTP without rewriting the business logic that lists capabilities, calls tools, reads resources, or applies cache and auth policy.
Sources: docs/clients/connect.md, docs/clients/calling.md, docs/clients/caching.md
Relevant Source Files
docs/clients/connect.md- Primary guide for constructingClient, choosing HTTP, stdio, in-memory, or SSE transports, runningconnect(), reading handshake metadata, and closing cleanly.docs/clients/calling.md- Shows the connected-client operations that depend on the server capabilities learned at connection time, including tool calls, resource reads, prompts, autocomplete, and pagination behavior.docs/clients/caching.md- Documents client response-cache behavior that begins after a connection exists, includingresponseCacheStore,cachePartition, and per-callcacheModechoices.docs/clients/middleware.md- Explains HTTP transportfetchmiddleware, including request tagging, logging, ordering, and OAuth middleware alternatives.docs/clients/oauth.md- Documents user OAuth by passing anOAuthClientProvideras an HTTP transportauthProviderand handling connect-time authorization redirects.docs/clients/machine-auth.md- Documents machine authentication providers such asClientCredentialsProvider, bearer-tokenAuthProvider,PrivateKeyJwtProvider, andCrossAppAccessProviderfor HTTP transports.
Core Primitives
The core primitives are Client, transport, and connection handshake. Client takes an identity object such as { name: 'my-client', version: '1.0.0' }. A transport owns the wire mechanics: StreamableHTTPClientTransport talks to an MCP HTTP endpoint URL, StdioClientTransport spawns a local process and exchanges JSON-RPC over stdin and stdout, SSEClientTransport supports older HTTP+SSE servers, and InMemoryTransport.createLinkedPair() links client and server inside one process for tests. connect() binds the client to exactly one of those transports.
Sources: docs/clients/connect.md
The handshake is also where protocol and capability decisions become concrete. connect() resolves only after initialization finishes, and the client then exposes getServerVersion(), getServerCapabilities(), and getInstructions(). Those accessors return undefined before the handshake resolves, so treat them as connected-state APIs rather than constructor-time configuration. The capability object should gate what you call next: for example, do not assume tool, resource, prompt, completion, or subscription behavior until the server has advertised the relevant capability.
Sources: docs/clients/connect.md, docs/clients/calling.md
Connect over Streamable HTTP
Streamable HTTP is the default choice for a server exposed at an MCP endpoint. Import Client and StreamableHTTPClientTransport from @modelcontextprotocol/client, pass the endpoint URL to the transport, then await client.connect(transport). If your HTTP path includes auth, logging, custom headers, or in-process test routing, those concerns belong in transport options rather than in the client call sites. The middleware guide shows that the transport accepts a custom fetch, and auth guides show authProvider on the same transport boundary.
Sources: docs/clients/connect.md, docs/clients/middleware.md, docs/clients/oauth.md, docs/clients/machine-auth.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);A useful mental model is that every HTTP request for the connection flows through the transport. createMiddleware() and applyMiddlewares() wrap the transport fetch, so the requests the SDK sends automatically, including initialize, receive the same headers, logging, retry behavior, or test harness routing as your later tool calls. For protected servers, user OAuth uses an OAuthClientProvider, while machine flows use providers such as ClientCredentialsProvider or bearer-token-style AuthProvider. Both are supplied to the HTTP transport, not to each method call.
Sources: docs/clients/middleware.md, docs/clients/oauth.md, docs/clients/machine-auth.md
Connect to a Local Process over Stdio
Use stdio when the MCP server is a local command that your client should spawn, such as a development server or host-managed tool server. StdioClientTransport is imported from @modelcontextprotocol/client/stdio; it receives a command and arguments, starts that process as a child, and speaks JSON-RPC through the child's stdin and stdout. The rest of the client lifecycle is unchanged: create the client, create the transport, and await connect(). The guide specifically notes that close() shuts the child down in order: close stdin, then SIGTERM, then SIGKILL.
Sources: docs/clients/connect.md
import { Client } from '@modelcontextprotocol/client';
import { StdioClientTransport } from '@modelcontextprotocol/client/stdio';
const client = new Client({ name: 'my-client', version: '1.0.0' });
const transport = new StdioClientTransport({ command: 'node', args: ['server.js'] });
await client.connect(transport);Because stdio uses stdout as part of the protocol stream, avoid writing unrelated logs to that stream in the same process path. The middleware guide gives the same warning for HTTP logging when stdout carries MCP stdio: pass a custom logger instead of the default console logger. That operational detail is easy to miss when moving examples into real hosts, but it is important because non-protocol bytes on a stdio stream can corrupt the JSON-RPC exchange.
Sources: docs/clients/connect.md, docs/clients/middleware.md
Fallbacks, Testing, and Post-Connect Introspection
Some older servers predate Streamable HTTP and only support the legacy HTTP+SSE transport. The documented fallback pattern is to try StreamableHTTPClientTransport first; if that connection fails, create a fresh Client and retry with SSEClientTransport. Reusing the failed client is not the recommended pattern because the client represents one connection attempt and one established server relationship. Once either branch returns, downstream code should not care which transport won; it should operate through the same Client methods.
Sources: docs/clients/connect.md
async function connectWithSseFallback(url: string) {
try {
const client = new Client({ name: 'my-client', version: '1.0.0' });
await client.connect(new StreamableHTTPClientTransport(new URL(url)));
return client;
} catch {
const client = new Client({ name: 'my-client', version: '1.0.0' });
await client.connect(new SSEClientTransport(new URL(url)));
return client;
}
}For tests, the same connection story can avoid ports and sockets entirely. The testing-oriented docs describe serving a handler in process and passing a custom fetch option to StreamableHTTPClientTransport, so requests for a fake URL are handled by the deployed handler code. The connect guide also names InMemoryTransport.createLinkedPair() as a third transport for linking a Client and McpServer in one process. Both approaches keep tests close to production behavior because they still drive a real Client through connect() and subsequent MCP calls.
Sources: docs/clients/connect.md, docs/clients/middleware.md
After connection, inspect what the server declared before making feature-specific calls. getServerVersion() returns the server name and version, getServerCapabilities() returns capability declarations such as tool list-change support, and getInstructions() returns server-provided usage guidance. The connect guide frames instructions as material you can put in a model system prompt. The calling guide then assumes a connected client for listing tools, reading resources, retrieving prompts, requesting completion, and watching pagination limits.
Sources: docs/clients/connect.md, docs/clients/calling.md
Compact API Reference
| Component | Import or option | Use |
|---|---|---|
Client | @modelcontextprotocol/client | Holds one connection to one server and exposes connected MCP operations. |
client.connect(transport) | Client method | Runs initialize; resolves after protocol version, capabilities, and instructions are available. |
StreamableHTTPClientTransport | @modelcontextprotocol/client | Connects to an MCP HTTP endpoint URL; accepts options such as custom fetch and authProvider. |
StdioClientTransport | @modelcontextprotocol/client/stdio | Spawns a local command and communicates over stdin/stdout JSON-RPC. |
SSEClientTransport | @modelcontextprotocol/client | Legacy fallback for SSE-only servers. |
InMemoryTransport.createLinkedPair() | client/server testing primitive | Links a client and server in one process with no network or child process. |
getServerVersion() | Client method | Reads server identity declared during initialization; undefined before connect resolves. |
getServerCapabilities() | Client method | Reads advertised capabilities used to decide which verbs to call. |
getInstructions() | Client method | Reads server usage instructions for host or model prompting. |
transport.terminateSession() | Streamable HTTP transport method | Terminates the server-side HTTP session before final client close. |
client.close() | Client lifecycle method | Closes the client; for stdio, the transport shutdown sequence closes stdin, then escalates signals. |
Connection options compose with later behavior. ClientOptions.versionNegotiation controls which protocol revision connect() negotiates. responseCacheStore and cachePartition configure response-cache storage for cacheable verbs after connection, while per-call cacheMode chooses use, refresh, or bypass. HTTP middleware wraps fetch, which means it observes connect-time initialization and later requests uniformly. Authentication providers also sit at the transport layer, so a 401 during connect() can trigger OAuth redirect, token refresh, or a machine credential flow before ordinary MCP operations proceed.
Sources: docs/clients/connect.md, docs/clients/caching.md, docs/clients/middleware.md, docs/clients/oauth.md, docs/clients/machine-auth.md
Execution Flow and Next Steps
A typical production flow is: build the client identity, construct the transport with URL/process/auth/middleware options, call connect(), inspect version/capabilities/instructions, run capability-gated operations, and close cleanly. For Streamable HTTP, terminate the server-side session before closing the client when the transport supports it. For stdio, let the transport own child-process shutdown instead of sending ad hoc signals. For legacy environments, isolate SSE fallback in one helper so the rest of your application never branches on transport type.
Sources: docs/clients/connect.md
Next, read client-calling for the connected operations that use the capability data from this page. Read client-oauth or machine-auth before connecting to protected HTTP servers. Read client-middleware if you need custom headers, logging, retries, or in-process handler routing, and read client-caching if repeated list or resource calls should use server cache hints rather than always crossing the wire.