> ## Documentation Index
> Fetch the complete documentation index at: https://langchain-5e9cc07a-preview-change-1791323909-75c753a.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Migrate to @langchain/mcp-adapters 2.0

> Upgrade from @langchain/mcp-adapters 1.x to 2.0, covering renamed APIs, stricter configuration, authentication, elicitation, and tool result changes.

<Prompt description="Migrate from @langchain/mcp-adapters 1.x to 2.0." icon="arrow-right" actions={["copy"]}>
  Migrate this codebase from `@langchain/mcp-adapters` 1.x to 2.0 and update its peer dependencies.

  Fetch and read the full migration guide at [https://docs.langchain.com/oss/javascript/migrate/langchain-mcp-adapters.md](https://docs.langchain.com/oss/javascript/migrate/langchain-mcp-adapters.md) as the source of truth. Search this codebase and apply all relevant migration changes, including dependency and test updates. Run the relevant checks, then summarize the changes and flag anything that requires a manual decision or could not be verified. If you cannot access the guide, ask for its contents before proceeding.
</Prompt>

`@langchain/mcp-adapters` 2.0 rebuilds the adapter on the MCP TypeScript SDK 2 client. It negotiates the MCP protocol era for each server and answers modern MCP elicitation with LangGraph interrupts. This guide covers the changes that affect 1.x code. For the feature documentation, see [Model Context Protocol (MCP)](/oss/javascript/langchain/mcp).

## Breaking changes

* **Tool names are prefixed with the server name by default.** `MCPAdapter`, including the deprecated `MultiServerMCPClient`, names tools `{server}__{tool}` (for example `weather__get_forecast`), even with a single server, unless you set `prefixToolNameWithServerName`; 1.x defaulted it to `false`. Set `prefixToolNameWithServerName: false` to keep 1.x names. `loadMcpTools` still defaults to `false`. Update code, prompts, and saved examples that refer to tool names. Update `interruptOn` approval rules to the prefixed names; a rule for `delete_repo` no longer matches `github__delete_repo`. The adapter does not validate server names, and longer names can exceed a model provider's tool-name limit; see [Multiple servers](/oss/javascript/langchain/mcp/connections#multiple-servers).
* **Duplicate tool names throw.** With `prefixToolNameWithServerName: false`, `listTools()` and `getTools()` throw `MCPClientError` when two servers expose the same tool name, or when one server lists a name twice. 1.x returned every tool. Keep the prefix, or pick tools per server from `listToolsets()`.
* **Elicitation pauses runs by default.** When a modern server asks for input during a tool call, the adapter raises a LangGraph [`interrupt`](https://reference.langchain.com/javascript/langchain-langgraph/index/interrupt) and the run stops until you resume it with `createMCPElicitationResume`. A checkpointer is needed only when a tool elicits. Set `elicitation: false` on a server to keep the 1.x behavior. See [Elicitation](#elicitation).
* **Tool content is always standard content blocks.** 1.x defaulted `useStandardContentBlocks` to `false`. 2.0 removes the option, rejects it, and always returns standard blocks, so images carry `data` and `mimeType` instead of `image_url` data URLs, and audio uses `mimeType` instead of `mime_type`. See [Tool results](#tool-results).
* **Configuration is strict.** Unknown keys and removed options throw when the adapter is constructed. See [Removed options](#removed-options).
* **Server-reported tool errors return error messages.** A result with `isError` comes back as a `ToolMessage` with `status: "error"` for an agent's tool call. Direct invocation with plain arguments still throws. See [Tool results](#tool-results).
* **The model no longer sees `structuredContent` or `_meta` next to a single text block.** 1.x also copied them onto the text block, so they were serialized into the content; 2.0 sends only the text. Read them from the artifact's `mcp_structured_content` and `mcp_meta` entries, where 1.x also put them. See [Tool results](#tool-results).

## Install

Upgrade the adapter and its peer dependencies:

<CodeGroup>
  ```bash npm theme={null}
  npm install @langchain/mcp-adapters@^2.0.0 @langchain/core @langchain/langgraph
  ```

  ```bash pnpm theme={null}
  pnpm add @langchain/mcp-adapters@^2.0.0 @langchain/core @langchain/langgraph
  ```

  ```bash yarn theme={null}
  yarn add @langchain/mcp-adapters@^2.0.0 @langchain/core @langchain/langgraph
  ```

  ```bash bun theme={null}
  bun add @langchain/mcp-adapters@^2.0.0 @langchain/core @langchain/langgraph
  ```
</CodeGroup>

* **Peer dependencies**: The adapter requires `@langchain/core` 1.2.6 or later (was 1.0.0) and `@langchain/langgraph` 1.4.13 or later (was 1.4.10).
* **MCP SDK**: The adapter includes the MCP SDK 2 client. If your code creates an SDK client for `loadMcpTools`, replace `@modelcontextprotocol/sdk` imports with `@modelcontextprotocol/client`. Import the stdio transport from `@modelcontextprotocol/client/stdio`. Add the SDK as a direct dependency if your code imports it, including to [complete an OAuth redirect](/oss/javascript/langchain/mcp/auth#complete-the-redirect).
* **Zod 4**: The adapter validates configuration with an internal Zod 4 dependency, so configuration errors are Zod 4 errors.
* **Debug logging**: `DEBUG=@langchain/mcp-adapters:*` no longer emits logs. Use `onConnectionError` and the per-server notification callbacks instead.

## Renamed APIs

Before:

```typescript theme={null}
import { MultiServerMCPClient } from "@langchain/mcp-adapters";

const client = new MultiServerMCPClient({
  mcpServers: {
    math: { command: "node", args: ["./math-server.js"] },
  },
});
const tools = await client.getTools();
```

After:

```typescript theme={null}
import { MCPAdapter } from "@langchain/mcp-adapters";

const adapter = new MCPAdapter({
  servers: {
    math: { command: "node", args: ["./math-server.js"] },
  },
});
const tools = await adapter.listTools();
```

| 1.x API | Recommended 2.0 API |
| - | - |
| `MultiServerMCPClient` | `MCPAdapter` |
| `mcpServers` or a flat server map | `servers` |
| `getTools(...)` | `listTools(...)`, a flat list of executable tools |
| `initializeConnections()` | `listToolsets()`, tools grouped by server |
| `ClientConfig` type | `MCPAdapterConfig` |

The older APIs in this table still work but are deprecated and may be removed in future.

Other API changes:

* Read configuration from `adapter.config.servers` instead of `adapter.config.mcpServers`. This is a snapshot; changing it does not reconfigure the adapter.
* `SSEConnection` accepts only legacy SSE. Use `StreamableHTTPConnection` for HTTP, or `Connection` for any transport.
* `ToolException` and `MCPClientError` are now exported. Recognize them with `ToolException.isInstance(error)` and `MCPClientError.isInstance(error)`, which check a brand rather than the error's `name`.
* `setLoggingLevel()` is legacy-only. It throws if any server it targets negotiated the modern protocol, and then sets no levels. Set `logLevel` on each modern server instead. See [Protocol eras](/oss/javascript/langchain/mcp/connections#protocol-eras). Modern servers also reject `resources/subscribe`, so list the resource URIs to watch in the server's `resourceSubscriptions` option and handle updates in `onResourcesUpdated`, instead of calling `subscribeResource()` on the client.

`getClient()` now returns the SDK 2 `Client` from `@modelcontextprotocol/client`. `loadMcpTools(serverName, client)` converts tools from an SDK client you build yourself. An SDK `Client` negotiates the legacy protocol by default, so create it with `versionNegotiation: { mode: "auto" }` if its tools should elicit through interrupts. To connect it to an in-process server over `InMemoryTransport`, serve that server with `serveStdio(factory, { transport: serverSide })`; `server.connect()` serves only the legacy protocol.

## Removed options

A configuration that sets any of these options now fails validation. `loadMcpTools` validates its options the same way:

| Option | Replacement |
| - | - |
| `useStandardContentBlocks` | None. Tool content is always standard LangChain content blocks. Delete the option. |
| `onRootsListChanged` | None. Delete the option. |
| `onCancelled` | None. Delete the option. |
| Stdio `encoding` | None. Delete the option. |
| Top-level notification callbacks | Set them on each server. See [Move callbacks onto servers](#move-callbacks-onto-servers). |

## Configuration

### Move callbacks onto servers

Notification and progress callbacks move from the top level into the server that should receive them. This applies to `onMessage`, `onProgress`, `onInitialized`, `onPromptsListChanged`, `onResourcesListChanged`, `onResourcesUpdated`, and `onToolsListChanged`.

Before:

```typescript theme={null}
const client = new MultiServerMCPClient({
  mcpServers: {
    everything: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-everything"],
    },
  },
  onProgress: (progress, source) => {
    console.log(source.type, progress.progress, progress.total);
  },
});
```

After:

```typescript theme={null}
const adapter = new MCPAdapter({
  servers: {
    everything: {
      command: "npx",
      args: ["-y", "@modelcontextprotocol/server-everything"],
      onProgress: (progress, source) => {
        console.log(source.type, progress.progress, progress.total);
      },
    },
  },
});
```

Tool hooks (`beforeToolCall`, `afterToolCall`) and `onConnectionError` stay top-level adapter options. Errors thrown or rejected by an `onProgress` callback are now ignored; in 1.x, a rejected promise went unhandled.

### Set a protocol mode

Each server now takes a `mode` of `"auto"` (the default), `"modern"`, or `"legacy"`, and negotiates independently. For what each mode does, see [Protocol eras](/oss/javascript/langchain/mcp/connections#protocol-eras).

Omit `mode` to negotiate automatically. Set `mode: "modern"` to require the modern protocol, or `mode: "legacy"` to skip probing a known legacy server.

These options require `mode: "legacy"` on the server that sets them:

* `onInitialized`
* `automaticSSEFallback`
* HTTP/SSE `reconnect`
* `onElicitation`

A 1.x server that sets `automaticSSEFallback` or `reconnect` now fails validation until you add `mode: "legacy"`:

```typescript theme={null}
const adapter = new MCPAdapter({
  servers: {
    legacy: {
      url: "https://legacy.example.com/sse",
      transport: "sse",
      mode: "legacy", // [!code ++]
      reconnect: { enabled: true, maxAttempts: 3, delayMs: 1000 },
    },
  },
});
```

HTTP connections in `"auto"` or `"modern"` mode no longer resume a dropped response stream. Use `mode: "legacy"` if you depend on stream resumption.

SSE remains a legacy transport, so an SSE server rejects `mode: "modern"`, `elicitation`, and `logLevel`. Automatic HTTP-to-SSE fallback in `"auto"` mode is limited to HTTP 404 and 405.

### Expect stricter validation

* **Configuration**: Zod 4 validation rejects unknown adapter and server options, options that do not apply to a server's mode or transport, conflicting transport settings, empty server maps, and setting both `servers` and `mcpServers`. Restart and reconnect `maxAttempts` must be a non-negative integer, and `delayMs` must not be negative.
* **Hooks**: In `beforeToolCall` and `afterToolCall`, `state` is typed `unknown`, so narrow it before use. Argument overrides must be objects. The merged arguments are validated against the tool's input schema, so an override that adds a property the schema does not allow fails the call with a `ToolException` before anything is sent to the server.

## Authentication

* **Two provider shapes**: `authProvider` accepts an `AuthProvider` (`{ token, onUnauthorized? }`) as well as an `OAuthClientProvider`. 1.x accepted only OAuth providers.
* **Header precedence**: Once a provider has a token, it takes precedence over a configured `Authorization` header. Until then, the configured header is sent.
* **OAuth callback**: Complete a redirect with the SDK's `transport.finishAuth(params)`, using a provider with the same storage. The adapter has no `finishAuth`.
* **Errors**: Walk an authentication failure's `cause` chain for `UnauthorizedError`, which the adapter now exports, or an HTTP 401 error. Discovery wraps it in `MCPClientError`, twice when legacy mode falls back to SSE; tool calls wrap it in `ToolException`.
* **Retries**: Discovery retries an authentication failure on the next call, even with `onConnectionError: "ignore"`.
* **Overrides**: Tool catalogs are separate for different headers and provider objects. Recreate the adapter when the account behind a provider object changes. A method-level `authProvider` replaces the configured one, and method-level `headers` are added to each server's configured headers, where a configured header with the same name wins. Both apply to every HTTP/SSE server, even when you select tools from only one server.

For the full guide, see [Authentication](/oss/javascript/langchain/mcp/auth).

## Elicitation

Elicitation is new in 2.0: 1.x had no elicitation support. When a server negotiates the modern protocol, the adapter by default raises each round of requested input as one LangGraph [`interrupt`](https://reference.langchain.com/javascript/langchain-langgraph/index/interrupt), whose `requests` holds every question. A tool that requests input now pauses the run.

* **Checkpointer**: A tool needs a checkpointer only when it asks for input. Otherwise, direct invocation still works.
* **Resume**: Answer every key in `requests`, then pass `createMCPElicitationResume(interrupt, responses)` as the `resume` value in a LangGraph `Command`.
* **Replays**: Resuming runs the tool again from the beginning, including `beforeToolCall`. Make sure repeating that work does not duplicate side effects.
* **Opt out**: Set `elicitation: false` on an individual modern server, or in the `loadMcpTools` options, to keep the 1.x behavior.
* **Legacy servers**: Set an `onElicitation` handler on a server with `mode: "legacy"`. This handler is also new in 2.0.

For the interrupt payload, answer actions, and a full example, see [Elicitation](/oss/javascript/langchain/mcp/tools#elicitation).

### Sampling and roots

Only elicitation is answered through these interrupts. Requests for [sampling](https://modelcontextprotocol.io/specification/2025-06-18/client/sampling) or [roots](https://modelcontextprotocol.io/specification/2025-06-18/client/roots) fail the tool call with a `ToolException`, even when they arrive alongside an elicitation.

## Tool results

* **Standard content blocks**: Tool content is always standard LangChain content blocks. Images and audio expose `data` and `mimeType`. By default, 1.x produced `image_url` blocks with data URLs, and audio blocks with `mime_type`.
* **Artifacts**: Blocks routed to the artifact keep their MCP format, including in `afterToolCall`, which receives the full artifact list, including the `mcp_structured_content`, `mcp_meta`, and `mcp_content` entries. Original resource blocks and content metadata are retained in `mcp_content` entries when conversion would otherwise lose them.
* **Embedded resources**: Converting a result no longer fetches resource URIs. Call `readResource()` explicitly when you need to fetch a resource. When routed to model content, embedded text resources become text blocks. Embedded binary resources become image, audio, or file blocks according to their MIME type.
* **Resource links**: A `resource_link` block becomes a `file` block with `url`, `mimeType`, and resource metadata. Update consumers of the 1.x `source_type` and `mime_type` fields.
* **Tool errors**: When a server returns a result with `isError`, the adapter returns a `ToolMessage` with `status: "error"` for an agent's tool call. Direct invocation with plain arguments still throws a `ToolException`, with the MCP response in `error.result`. Because these results are returned rather than thrown, they no longer trigger exception-based handling such as `toolRetryMiddleware` or a `ToolNode` `handleToolErrors` function. Check `ToolMessage.status` (for example in `wrapToolCall`) to retry them. The server's error text is always sent to the model, even when `outputHandling` routes text to the artifact.
* **Other failures**: Connection and validation failures still throw from the tool. Invoked directly, the tool raises the exception; in a `createAgent` agent, the default tool error handling turns it into a `ToolMessage` with `status: "error"`. Read the exception's `message` for details; `cause` is not always set.
* **Hook results**: Hooks preserve returned `ToolMessage` and LangGraph `Command` objects instead of flattening or rejecting them. `afterToolCall` receives successful results only.
* **Resource reads**: `readResource()` preserves SDK content metadata. Narrow each item with `"text" in content` or `"blob" in content`.
* **Structured content**: A result with a single text block becomes a string `content`, even when it carries `structuredContent` or `_meta`. 1.x serialized the block with both into the content, so the model saw them. Read them from the `mcp_structured_content` and `mcp_meta` artifact entries.
* **Tool schemas**: Tool input schemas reach the model as the server declares them. 1.x inlined `$ref` definitions and simplified composite schemas: it merged `allOf`, flattened `anyOf` and `oneOf`, and removed `if`/`then`/`else`, `not`, `$schema`, and `unevaluatedProperties`. Check tools from servers with complex schemas against your model provider.

## Lifecycle

* **Grouped discovery**: `listToolsets()` returns a map from server name to tools, and `listTools()` flattens it.
* **Reusable close**: Keep the adapter open while using its tools, then await `close()`. Closing stops active discovery and pending reconnects and clears connections and caches. Discover fresh tools to reuse the adapter afterwards.
* **Discovery cache**: `listTools([], { cacheMode: "refresh" })` refreshes discovery; `cacheMode: "bypass"` skips the cache. A failed refresh keeps previously returned tools usable.
* **Resource listing**: `listResources()` and `listResourceTemplates()` now throw a server's error, where 1.x returned `[]` for a failing server and logged the error only under `DEBUG`. A server without resource templates still lists them as `[]`.
* **Reconnect failures**: Exhausted background stdio restart attempts now report through an `onConnectionError` callback.

## See also

* [Model Context Protocol (MCP)](/oss/javascript/langchain/mcp)
* [Connections](/oss/javascript/langchain/mcp/connections)
* [Authentication](/oss/javascript/langchain/mcp/auth)
* [Tools](/oss/javascript/langchain/mcp/tools)

***

<div className="source-links">
  <Callout icon="terminal-2">
    [Connect these docs](/use-these-docs) to your agent of choice via MCP for real-time answers.
  </Callout>

  <Callout icon="edit">
    [Edit this page on GitHub](https://github.com/langchain-ai/docs/edit/main/src/oss/javascript/migrate/langchain-mcp-adapters.mdx) or [file an issue](https://github.com/langchain-ai/docs/issues/new/choose).
  </Callout>
</div>
