Skip to content

MCP in LangChain: Stateful and Stateless Deployments

MCP in LangChain connecting stateful and stateless agents to tools, context, and elicitation workflows.

MCP gives LangChain agents a standard way to discover and call external tools. The integration is straightforward. Production architecture is not. If an MCP server keeps workflow state in memory, a restart or load-balancer decision can break an active agent run. An application-level stateless deployment architecture moves durable progress elsewhere, making replicas easier to replace when the selected transport and implementation support that model. This guide separates MCP connection state, agent state, and persistent application state. It also covers elicitation, retries, and recovery without making a live connection the system of record.

What MCP in LangChain Does—and Why Statelessness Matters

The LangChain MCP documentation defines Model Context Protocol as an open protocol that standardizes how applications provide tools and context to language models.

In LangChain, MCPAdapter discovers tools exposed by an MCP server and adapts them into LangChain tools. You can then pass those tools to create_agent.

That integration creates several distinct state layers:

  • MCP connection state: transport details, authentication context, and active client connections.
  • Agent state: messages, planned actions, tool results, and workflow position.
  • Application state: operation IDs, approvals, generated artifacts, and business records.
  • External durable state: checkpoints or records stored outside the running process.

Do not merge these layers into a single in-memory session.

For example, consider an agent that prepares a periodic competitor report. The MCP server may expose tools for reading approved sources and storing a report. The LangChain agent decides which tools to call. A durable store records which report is being generated and whether each write completed.

If the MCP server disappears, you should lose a connection. You should not lose the report’s progress.

“Stateless” here describes an application and deployment architecture: each server request contains enough information to execute the operation or locate its durable state. It does not describe an evolution from a stateful MCP protocol to a stateless one.

What the docs guarantee vs. what you must design

The LangChain documentation establishes how MCPAdapter discovers MCP tools, which connection forms it accepts, how its async context is used, and that FastMCP handles transport inference, protocol negotiation, connection management, and supported authentication mechanisms.

Your application architecture must define where durable workflow state lives, whether requests can move between replicas, whether connection affinity is required, how operation IDs and side effects are made idempotent, and how an interrupted LangGraph workflow is recovered. Load balancing, sticky sessions, automatic continuation after elicitation, and checkpoint-based resumption depend on the deployed transport, MCP client and server, LangGraph configuration, and application code; they are not consequences of using MCP alone.

From a Stateful MCP Server to a Stateless Deployment Architecture: What Changes?

A stateful server often relies on process memory:

connection -> in-memory session -> current workflow step -> pending result

That works locally. It becomes fragile when several replicas accept traffic or when a server restarts.

A stateless deployment architecture changes the ownership model:

request + operation ID
        |
        v
replaceable MCP replica
        |
        v
shared durable state

The server can still use temporary memory while handling a request. It should not be the only place that knows whether an operation completed.

For each tool call, persist enough data to answer these questions:

  • What agent run initiated the operation?
  • Has this logical operation already completed?
  • Is user input or approval pending?
  • Can the call be retried safely?
  • Where is the result stored?
  • Which error is terminal, and which is retryable?

Use stable operation IDs. A retry must reuse the original ID instead of generating a new one. Tools with side effects should check that ID before repeating work.

Here is a runnable SQLite foundation:

import json
import sqlite3
from dataclasses import dataclass


@dataclass
class Operation:
    operation_id: str
    status: str
    payload: dict
    result: dict | None = None


db = sqlite3.connect("agent_state.db")
db.execute("""
CREATE TABLE IF NOT EXISTS operations (
    operation_id TEXT PRIMARY KEY,
    status TEXT NOT NULL,
    payload TEXT NOT NULL,
    result TEXT
)
""")
db.commit()


def begin(operation_id: str, payload: dict) -> Operation:
    db.execute(
        """
        INSERT OR IGNORE INTO operations(operation_id, status, payload)
        VALUES (?, 'started', ?)
        """,
        (operation_id, json.dumps(payload)),
    )
    db.commit()

    row = db.execute(
        """
        SELECT operation_id, status, payload, result
        FROM operations
        WHERE operation_id = ?
        """,
        (operation_id,),
    ).fetchone()

    return Operation(
        operation_id=row[0],
        status=row[1],
        payload=json.loads(row[2]),
        result=json.loads(row[3]) if row[3] else None,
    )


def complete(operation_id: str, result: dict) -> None:
    db.execute(
        """
        UPDATE operations
        SET status = 'completed', result = ?
        WHERE operation_id = ?
        """,
        (json.dumps(result), operation_id),
    )
    db.commit()


op = begin("report:2026-09", {"account": "example"})
if op.status != "completed":
    complete(op.operation_id, {"artifact": "reports/2026-09.json"})

For a production database, make the transition from “not started” to “started” atomic. Add ownership or lease fields if concurrent workers can claim the same operation.

A practical migration checklist is:

  • Inventory every value currently held in server memory.
  • Classify it as connection-only, temporary interaction context, agent state, or durable application state.
  • Move recoverable progress and side-effect records to shared storage.
  • Add stable operation IDs to tool requests.
  • Define expiration for temporary sessions and pending input.
  • Test retries against every side-effecting tool.
  • Review checkpoint, retry, and idempotency boundaries using the patterns in the LangGraph production deployment guide.
  • Run requests against interchangeable replicas where the selected transport and server permit it.
  • Kill a connection and a server process during execution.
  • Verify that the agent either resumes through the configured application path or stops with an actionable status.

Elicitation in MCP: The Agent–Server–User Flow

For deployments whose MCP protocol version, client, and server support elicitation, it can be used to obtain additional user input or approval. A recovery-oriented application flow is:

  1. A LangChain agent calls an MCP tool.
  2. The server or surrounding application determines that required information or authorization is missing.
  3. An elicitation request is surfaced through the interfaces supported by the deployed MCP client and server.
  4. Your application presents the request to the user.
  5. The response is validated and associated with the pending operation.
  6. Your application continues or reconstructs the operation from durable state through its configured continuation path.

For example, a reporting agent may prepare an artifact but require approval before publishing it. The pending approval should not exist only inside the MCP server process.

Persist a record such as:

{
  "operation_id": "publish:report:2026-09",
  "status": "waiting_for_input",
  "request_type": "approval",
  "checkpoint_id": "agent-run-42"
}

This application record separates a pending interaction from the connection that originally carried it. Your handler needs clear rules:

  • Validate the response before continuing or reconstructing the operation.
  • Bind the response to the correct user and operation.
  • Reject responses for expired or cancelled operations.
  • Make duplicate responses harmless.
  • Record approval separately from execution.
  • Recheck authorization before execution continues.

Temporary interaction context is not necessarily a durable agent checkpoint. The interaction record says, “This operation is waiting for an answer,” while the checkpoint identifies a saved workflow position that the configured agent runtime may use. You often need both.

How LangChain Connects to MCP Servers and Tools

The documented Python integration requires:

python -m pip install "langchain[mcp]>=1.4.0"

For the executable OpenAI-backed example below, also install the model provider integration and set OPENAI_API_KEY:

python -m pip install langchain-openai
export OPENAI_API_KEY="your-api-key"

The langchain.mcp namespace is marked as beta. Importing it emits a LangChainBetaWarning once per process.

The documented startup sequence is:

open MCPAdapter in an async context
    -> call list_tools()
    -> build the agent with the discovered tools

The following program connects to the public LangChain documentation MCP server, discovers its tools with list_tools(), creates an agent, and invokes it:

import asyncio

from langchain.agents import create_agent
from langchain.mcp import MCPAdapter


async def main() -> None:
    async with MCPAdapter("https://docs.langchain.com/mcp") as adapter:
        tools = await adapter.list_tools()

        agent = create_agent(
            model="openai:gpt-4.1-mini",
            tools=tools,
            system_prompt=(
                "Use the available documentation tools to answer questions "
                "about LangChain accurately."
            ),
        )

        result = await agent.ainvoke(
            {
                "messages": [
                    {
                        "role": "user",
                        "content": (
                            "How does LangChain connect to an MCP server "
                            "over Streamable HTTP?"
                        ),
                    }
                ]
            }
        )

        print(result["messages"][-1].content)


if __name__ == "__main__":
    asyncio.run(main())

Build the agent while the adapter context is open. According to the LangChain documentation, discovered tools retain the client, so the agent can remain usable after the adapter context exits. Invoking it inside the context, as above, also keeps resource ownership explicit.

MCPAdapter relies on FastMCP for transport inference, protocol negotiation, connection management, and authentication support. Your tools still need application-level authorization.

It supports several connection forms:

  • An in-memory FastMCP server.
  • A local script launched through stdio.
  • An HTTP or HTTPS URL using Streamable HTTP.
  • A preconfigured transport object.
  • An MCPConfig containing multiple servers.
  • A prebuilt fastmcp.Client.

Choose the simplest transport that matches your boundary. In-memory mode avoids subprocesses and sockets. A script connection starts a subprocess for each adapter. Streamable HTTP is the natural option when the MCP server is a remote service.

The docs also provide a public MCP server at https://docs.langchain.com/mcp without an API key. Its tools include documentation search, virtual filesystem reading or search, and issue reporting.

Stateless MCP Deployments: Load Balancing, Sessions, and Failover

Transport choice changes the failure model.

Connection mode Useful for Main operational boundary
In-memory Local integration and tightly coupled processes The application process
stdio subprocess Local tools and scripts The adapter and child process
Streamable HTTP Remote services and replicated deployments The network and service replicas

Architecture hypothesis—load balancing: independently executable request handling can support horizontal scaling when the selected Streamable HTTP transport and server implementation permit requests to move between replicas, and when required durable state is shared or supplied with each request. Replica interchangeability must be validated for the deployed stack rather than inferred from MCP alone.

Architecture hypothesis—sticky sessions: connection affinity can be used as a compatibility pattern when an implementation depends on connection-local state. Affinity may reduce immediate migration work, but it does not preserve durable progress if the selected replica or its local state disappears. Applications that require recovery should keep recoverable workflow state in shared storage or another durable system of record.

Plan explicitly for:

  • Retries: retry only errors classified as transient.
  • Idempotency: reuse an operation ID and return the prior result when possible.
  • Timeouts: stop waiting before the surrounding agent runtime expires.
  • Concurrency: prevent two calls from applying the same side effect.
  • Authentication: restore identity without storing sensitive credentials in checkpoints.
  • Observability: log the agent run, operation ID, tool, replica, and outcome.

The LangChain documentation points to Bearer tokens, OAuth 2.1, and per-user server authentication. These connection and identity mechanisms complement rather than replace tool-level authorization.

For concrete queue, workload-isolation, and observability decisions when replicas share agent traffic, see common bottlenecks when scaling AI agents. For credential boundaries and least privilege, use the production security guide for Python agents.

Recovery Playbook: Resuming an Agent After MCP or Network Failure

Suppose an agent calls a publishing tool. The application records that approval is required. Before the user responds, the connection closes and the serving replica restarts.

Architecture hypothesis—LangGraph recovery: the following playbook assumes that the application has configured a compatible LangGraph checkpointer, persisted the required workflow and operation state, and implemented a continuation or replay path. Reconnecting to MCP restores access to tools; the application remains responsible for resuming or reconstructing the interrupted workflow.

The recovery sequence is:

  1. Load the latest durable agent checkpoint.
  2. Read the pending operation record.
  3. Reconstruct the MCP client context.
  4. Allow the adapter and server to establish a new supported connection.
  5. Check whether the operation already completed.
  6. If approval is still valid, invoke the application’s configured continuation or replay path from durable state.
  7. If the pending request expired, create and present a new request.
  8. If completion is uncertain, reconcile external state before retrying the side effect.

MCP reconnection and agent recovery are different procedures. A supported and correctly configured checkpointer gives a LangGraph application persisted workflow state to use in its recovery design. The exact saved fields and continuation behavior depend on the graph definition, checkpointer, deployed LangGraph version, and invocation pattern. The LangGraph production deployment guide covers persistent checkpoints and resumable job patterns in more depth.

Test the migration by forcing failures at meaningful boundaries:

  • Before a tool receives the request.
  • While the tool is executing.
  • After the side effect but before the response.
  • During elicitation.
  • After user input but before application-level continuation.

The difficult case is always an uncertain outcome. If a connection fails after a side effect, a blind retry can duplicate work. An operation record lets a replacement replica look up an existing result or compare durable application state with the external system before deciding whether to retry.

Conclusion

MCP standardizes how LangChain agents access tools and context. It does not remove the need to design state ownership.

Keep connections replaceable where the deployed transport and implementation allow it. Store agent progress through a supported checkpointing configuration. Store approvals, operation IDs, and side-effect results durably. With those application patterns in place, a failed replica can be handled as a reconnection and recovery event instead of becoming the only remaining record of a workflow.

That separation also fits serverless agent hosting architectures: runtimes can start and stop while durable state remains available. When the selected MCP transport, server implementation, and agent runtime support the required lifecycle, the resulting deployment is easier to scale and recover without making a live MCP connection its system of record.