Migrate from @langchain/mcp-adapters 1.x to 2.0.
@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).
Breaking changes
- Tool names are prefixed with the server name by default.
MCPAdapter, including the deprecatedMultiServerMCPClient, names tools{server}_{tool}(for exampleweather_get_forecast), even with a single server, unless you setprefixToolNameWithServerName; 1.x defaulted it tofalse. SetprefixToolNameWithServerName: falseto keep 1.x names.loadMcpToolsstill defaults tofalse. Update code, prompts, and saved examples that refer to tool names. UpdateinterruptOnapproval rules to the prefixed names; a rule fordelete_repono longer matchesgithub_delete_repo. The adapter does not validate server names, and longer names can exceed a model provider’s tool-name limit; see Multiple servers. - Duplicate tool names throw. With
prefixToolNameWithServerName: false,listTools()andgetTools()throwMCPClientErrorwhen 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 fromlistToolsets(). - Elicitation pauses runs by default. When a modern server asks for input during a tool call, the adapter raises a LangGraph
interruptand the run stops until you resume it withcreateMCPElicitationResume. A checkpointer is needed only when a tool elicits. Setelicitation: falseon a server to keep the 1.x behavior. See Elicitation. - Tool content is always standard content blocks. 1.x defaulted
useStandardContentBlockstofalse. 2.0 removes the option, rejects it, and always returns standard blocks, so images carrydataandmimeTypeinstead ofimage_urldata URLs, and audio usesmimeTypeinstead ofmime_type. See Tool results. - Configuration is strict. Unknown keys and removed options throw when the adapter is constructed. See Removed options.
- Server-reported tool errors return error messages. A result with
isErrorcomes back as aToolMessagewithstatus: "error"for an agent’s tool call. Direct invocation with plain arguments still throws. See Tool results. - The model no longer sees
structuredContentor_metanext 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’smcp_structured_contentandmcp_metaentries, where 1.x also put them. See Tool results.
Install
Upgrade the adapter and its peer dependencies:- Peer dependencies: The adapter requires
@langchain/core1.2.6 or later (was 1.0.0) and@langchain/langgraph1.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/sdkimports 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. - 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. UseonConnectionErrorand the per-server notification callbacks instead.
Renamed APIs
Before:
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.serversinstead ofadapter.config.mcpServers. This is a snapshot; changing it does not reconfigure the adapter. SSEConnectionaccepts only legacy SSE. UseStreamableHTTPConnectionfor HTTP, orConnectionfor any transport.ToolExceptionandMCPClientErrorare now exported. Recognize them withToolException.isInstance(error)andMCPClientError.isInstance(error), which check a brand rather than the error’sname.setLoggingLevel()is legacy-only. It throws if any server it targets negotiated the modern protocol, and then sets no levels. SetlogLevelon each modern server instead. See Protocol eras. Modern servers also rejectresources/subscribe, so list the resource URIs to watch in the server’sresourceSubscriptionsoption and handle updates inonResourcesUpdated, instead of callingsubscribeResource()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:
Configuration
Move callbacks onto servers
Notification and progress callbacks move from the top level into the server that should receive them. This applies toonMessage, onProgress, onInitialized, onPromptsListChanged, onResourcesListChanged, onResourcesUpdated, and onToolsListChanged.
Before:
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 amode of "auto" (the default), "modern", or "legacy", and negotiates independently. For what each mode does, see 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:
onInitializedautomaticSSEFallback- HTTP/SSE
reconnect onElicitation
automaticSSEFallback or reconnect now fails validation until you add mode: "legacy":
"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
serversandmcpServers. Restart and reconnectmaxAttemptsmust be a non-negative integer, anddelayMsmust not be negative. - Hooks: In
beforeToolCallandafterToolCall,stateis typedunknown, 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 aToolExceptionbefore anything is sent to the server.
Authentication
- Two provider shapes:
authProvideraccepts anAuthProvider({ token, onUnauthorized? }) as well as anOAuthClientProvider. 1.x accepted only OAuth providers. - Header precedence: Once a provider has a token, it takes precedence over a configured
Authorizationheader. 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 nofinishAuth. - Errors: Walk an authentication failure’s
causechain forUnauthorizedError, which the adapter now exports, or an HTTP 401 error. Discovery wraps it inMCPClientError, twice when legacy mode falls back to SSE; tool calls wrap it inToolException. - 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
authProviderreplaces the configured one, and method-levelheadersare 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.
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 LangGraphinterrupt, 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 passcreateMCPElicitationResume(interrupt, responses)as theresumevalue in a LangGraphCommand. - 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: falseon an individual modern server, or in theloadMcpToolsoptions, to keep the 1.x behavior. - Legacy servers: Set an
onElicitationhandler on a server withmode: "legacy". This handler is also new in 2.0.
Sampling and roots
Only elicitation is answered through these interrupts. Requests for sampling or roots fail the tool call with aToolException, even when they arrive alongside an elicitation.
Tool results
- Standard content blocks: Tool content is always standard LangChain content blocks. Images and audio expose
dataandmimeType. By default, 1.x producedimage_urlblocks with data URLs, and audio blocks withmime_type. - Artifacts: Blocks routed to the artifact keep their MCP format, including in
afterToolCall, which receives the full artifact list, including themcp_structured_content,mcp_meta, andmcp_contententries. Original resource blocks and content metadata are retained inmcp_contententries 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_linkblock becomes afileblock withurl,mimeType, and resource metadata. Update consumers of the 1.xsource_typeandmime_typefields. - Tool errors: When a server returns a result with
isError, the adapter returns aToolMessagewithstatus: "error"for an agent’s tool call. Direct invocation with plain arguments still throws aToolException, with the MCP response inerror.result. Because these results are returned rather than thrown, they no longer trigger exception-based handling such astoolRetryMiddlewareor aToolNodehandleToolErrorsfunction. CheckToolMessage.status(for example inwrapToolCall) to retry them. The server’s error text is always sent to the model, even whenoutputHandlingroutes text to the artifact. - Other failures: Connection and validation failures still throw from the tool. Invoked directly, the tool raises the exception; in a
createAgentagent, the default tool error handling turns it into aToolMessagewithstatus: "error". Read the exception’smessagefor details;causeis not always set. - Hook results: Hooks preserve returned
ToolMessageand LangGraphCommandobjects instead of flattening or rejecting them.afterToolCallreceives successful results only. - Resource reads:
readResource()preserves SDK content metadata. Narrow each item with"text" in contentor"blob" in content. - Structured content: A result with a single text block becomes a string
content, even when it carriesstructuredContentor_meta. 1.x serialized the block with both into the content, so the model saw them. Read them from themcp_structured_contentandmcp_metaartifact entries. - Tool schemas: Tool input schemas reach the model as the server declares them. 1.x inlined
$refdefinitions and simplified composite schemas: it mergedallOf, flattenedanyOfandoneOf, and removedif/then/else,not,$schema, andunevaluatedProperties. Check tools from servers with complex schemas against your model provider.
Lifecycle
- Grouped discovery:
listToolsets()returns a map from server name to tools, andlistTools()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()andlistResourceTemplates()now throw a server’s error, where 1.x returned[]for a failing server and logged the error only underDEBUG. A server without resource templates still lists them as[]. - Reconnect failures: Exhausted background stdio restart attempts now report through an
onConnectionErrorcallback.
See also
Connect these docs to your agent of choice via MCP for real-time answers.

