Главная / Статьи

MCP для агентов LangGraph: пошагово — серверы, механизмы передачи данных и мост-адаптер

MCP для агентов LangGraph, пошагово: роли хоста, клиента и сервера, сервер FastMCP, способы передачи данных stdio против HTTP, адаптеры langchain-mcp и распространённые ошибки.

Издатель: REACTAPP.TOP17 мин чтения3867 слов

Источники: MCP for LangGraph Developers: From Basics to Production

Предварительные требования минимальны: необходимо знакомство с структурой проекта LangGraph и с концепцией функции, декорированной атрибутом @tool. Model Context Protocol представляет собой новый элемент инфраструктуры, а не новый подход к работе с графами; поэтому объяснение начинается с основ MCP, а с LangGraph связывается только после того, как концепция становится ясной.

Проблема масштабирования с обычными инструментами

Инструмент в LangGraph обычно создается следующим образом:

@tool
def search_web(query: str) -> str:
    """Search the web for current information."""
    return f"Search results for: {query}"

Всё это нормально, пока не возникает необходимость масштабирования. Предположим, пять агентов в пяти проектах все нуждаются в инструменте «поиск в корпоративной базе данных». Согласно описанному выше подходу, один и тот же инструмент будет написан пять раз, в пяти кодовых базах, возможно, даже на пяти разных языках. Изменение схемы требует пяти правок. Попытка поделиться им с коллегой, разрабатывающим другой тип приложения на основе ИИ, возможно, даже не использующим LangGraph, проваливается полностью, поскольку функция @tool принадлежит к миру Python в LangChain.

Эту проблему называют проблемой интеграции N×M. N инструментов (базы данных, API, файловые системы) должны подключаться к M приложениям ИИ (агент LangGraph, пользовательский агент коллеги, Claude Desktop, помощник в IDE). В отсутствие общего стандарта возникают N×M индивидуальных решений интеграции.

Протокол контекста модели (MCP) представляет собой открытый универсальный стандарт для подключения ИИ-приложений к инструментам и данным. Инструмент, созданный один раз в качестве сервера MCP, может использоваться любым приложением, совместимым с MCP — будь то агент LangGraph, Claude Desktop, Cursor или пользовательский агент — без необходимости написания специального кода для интеграции. Часто его сравнивают с разъемом USB-C: один стандарт разъема, любое совместимое устройство с любой стороны.

Путь от вопроса «что такое MCP» до рабочего сервера, подключенного к реальному агенту LangGraph, проходит через пять уровней, на каждом из которых добавляется новая идея.

Уровень 1: что такое MCP

Начните с изображения перед любым кодом. Консьерж отеля лично не знает, как забронировать столик в ресторане, вызвать такси или купить билеты в театр. Консьерж ведет список надежных местных услуг, каждая из которых представляет собой специалиста. Когда гость хочет забронировать ужин, консьерж использует специальную линию связи с сервисом бронирования, формулирует запрос в формате, понятном обеим сторонам, и передает ответ обратно.

MCP — это стандартная линия связи и стандартный формат запроса. Приложение на основе ИИ выполняет роль консьержа. Сервер MCP — это специализированный сервис, такой как система бронирования ресторанов, таксопарк или билетная касса. Сам MCP представляет собой общий язык и схему взаимодействия, благодаря чему любой консьерж может общаться с любым сервисом, не нуждаясь в знании того, как каждый из них управляет собственной системой связи.

Три роли

В каждой системе MCP участвуют ровно три компонента, и все остальное строится на их основе.

  • Хост. Приложение ИИ, которое фактически использует конечный пользователь: здесь это агент LangGraph, а в других случаях — Claude Desktop, Cursor или VS Code с Copilot. Он управляет диалогом, определяет, когда требуется инструмент, и отображает результаты.
  • Клиент. Он находится внутри хоста, причем каждый клиент поддерживает отдельное один-к-одному соединение именно с одним сервером. Хост, подключенный к трём серверам, внутри себя запускает три клиента. Такое один-к-одному соответствие является преднамеренной мерой безопасности, чтобы клиент, предназначенный для сервера файловой системы, не мог случайно утечь данные на сервер базы данных.
  • Сервер. Небольшая специализированная программа, предоставляющая определённые возможности. Она может обернуть базу данных, файловую систему, API веб-поиска или внутреннюю систему управления отношениями с клиентами. Примечательно, что сервер не знает и не интересуется тем, какой хост к нему обращается, поэтому один и тот же сервер может обслуживать агента LangGraph сегодня и другое приложение завтра без каких-либо изменений.
  • Формат передачи данных: JSON-RPC 2.0

    Сообщения между клиентом и сервером передаются в формате JSON-RPC 2.0 — простом и хорошо устоявшемся формате с тремя типами сообщений.

    Запрос содержит просьбу о выполнении какой-либо операции и включает уникальный id, чтобы можно было отследить ответ:

    {"jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": {"name": "search_db", "arguments": {"query": "Q3 revenue"}}}
    

    Ответ — это реакция на запрос. Он содержит либо результат в случае успеха, либо ошибка в случае неудачи, причем имеет тот же идентификатор, что и запрос:

    {"jsonrpc": "2.0", "id": 1, "result": {"content": [{"type": "text", "text": "Q3 revenue was $4.2M"}]}}
    

    Уведомление — это однонаправленное сообщение, не требующее ответа, например, для информирования о том, что изменился список доступных инструментов.

    В редких случаях JSON-RPC пишут вручную, поскольку этим занимаются SDK. Тем не менее понимание его основ помогает разобраться во многих аспектах, аналогично тому, как знание HTTP делает человека лучшим разработчиком REST, даже если он никогда не пишет HTTP в чистом виде.

    Уровень 2: три примитива

    Сервер предоставляет свои возможности с помощью ровно трех видов примитивов, и практически каждое решение при проектировании сервера сводится к выбору между ними.

    Инструменты — это действия, которые может выполнять модель. Инструмент представляет собой функцию, которую LLM может решить вызвать в процессе рассуждений, подобно украшенной функции в обычном LangGraph. Разница заключается в том, где она находится: внутри сервера MCP, а не в кодовой базе LangGraph, и она обнаруживается и вызывается через протокол. Обращайтесь к инструменту каждый раз, когда необходимо что-то сделать: выполнить вычисления, отправить запрос в базу данных, отправить электронное письмо или отредактировать файл.

    Ресурсы предоставляют только для чтения контекст. Приложение может загрузить ресурс, чтобы передать модели вспомогательные материалы, без необходимости для модели самостоятельно решать вызвать его, как это делается с инструментом. Ресурсы адресуются по URI, так же как веб-страницы — по URL. Используйте их для материалов, доступных только для чтения, таких как файл конфигурации, документ или список источников данных, о которых модель может захотеть узнать перед тем, как определить, что искать.

    Подсказки — это повторно используемые шаблоны. Подсказка представляет собой заранее написанную структуру, которая запускает определённый рабочий процесс для пользователя или хоста. В отличие от инструментов, подсказки обычно вызываются пользователем, а не моделью, поэтому они похожи на команды с слэшем. Они подходят для распространённых, повторяющихся задач, таких как «подготовь краткое резюме этого документа» или «проверь этот код на наличие проблем с безопасностью», где чёткие, хорошо спроектированные инструкции лучше, чем оставление формулировок на усмотрение пользователя.

    Если вы не уверены, что использовать, спросите, изменяет ли данная операция что-либо или просто предоставляет информацию. Если она создаёт, обновляет, удаляет, отправляет или выполняет действия, это инструмент. Если это только читаемые данные, которые модель может использовать в качестве фона, это ресурс. Если это шаблон инструкции, который пользователь явно запускает, это подсказка.

    Уровень 3: первый сервер с FastMCP

    FastMCP — это доминирующая Python-фреймворк для создания серверов MCP. Он преобразует сложные механизмы протокола (обработка запросов, генерация схем, управление жизненным циклом) в несколько декораторов, аналогично декоратору @tool для функций LangChain. Установка:

    pip install fastmcp
    

    Полноценный сервер с одним инструментом помещается в небольшом файле:

    # ── math_server.py ───────────────────────────────────────────
    from fastmcp import FastMCP
    
    # Create the server - this object is the container for everything below
    mcp = FastMCP(name="Math Server")
    @mcp.tool
    def add(a: int, b: int) -> int:
        """Add two numbers together."""
        return a + b
    @mcp.tool
    def multiply(a: int, b: int) -> int:
        """Multiply two numbers together."""
        return a * b
    if __name__ == "__main__":
        mcp.run()  # Defaults to stdio transport
    

    Это действительно рабочий сервер MCP. FastMCP считывает аннотации типов функции для генерации схемы входных данных и анализирует документацию, чтобы сформировать описание, которое видит большая языковая модель. Применяется тот же принцип, что и для обычных инструментов, только здесь риски выше: нечеткая документация заставляет модель сомневаться, когда вызывать инструмент, и теперь эта неопределенность влияет на каждое приложение, подключающееся к серверу, а не только на одного агента.

    Чтобы добавить ресурс, необходимо использовать декоратор с указанным URI:

    # ── Adding to math_server.py ─────────────────────────────────
    
    @mcp.resource("config://server-info")
    def server_info() -> dict:
        """Provides metadata about this server's capabilities."""
        return {"version": "1.0", "operations": ["add", "multiply"]}
    

    Когда клиент запрашивает config://server-info, FastMCP вызывает соответствующую функцию и возвращает результат. Она выполняется только по запросу, что является ленивой оценкой, поэтому не вычисляется ничего, что модель никогда не использует.

    Иногда ресурс должен зависеть от аргумента, например, от конкретной записи, а не от фиксированного набора параметров конфигурации:

    @mcp.resource("history://{operation_id}")
    def get_calculation(operation_id: str) -> dict:
        """Retrieve a past calculation by its ID."""
        # In a real server, this would look up a database record
        return {"id": operation_id, "result": "..."}
    

    Заместитель {operation_id} в URI делает его шаблоном ресурса. Запрос к history://abc123 заставляет FastMCP извлечь abc123 и автоматически передать его функции.

    Подсказка определяется аналогичным образом:

    @mcp.prompt
    def explain_calculation(operation: str, result: str) -> str:
        """Generate a request to explain a calculation in plain English."""
        return f"Explain how the operation '{operation}' produced the result '{result}', in simple terms a beginner could follow."
    

    Чтобы запустить сервер:

    python math_server.py
    

    Прежде чем подключать реальное приложение ИИ, проверьте его с помощью MCP Inspector — инструмента отладки в браузере, входящего в состав экосистемы. Он перечисляет инструменты, вызывает их вручную и анализирует ресурсы без участия LLM:

    fastmcp dev math_server.py
    

    Это открывает локальный веб-интерфейс, обычно по адресу http://127.0.0.1:6274, где можно переключаться между инструментами, вводить тестовые аргументы и наблюдать за сообщениями JSON-RPC, передаваемыми туда-обратно. Сначала протестируйте здесь. Ошибки в инструментах гораздо сложнее отловить через поведение вызовов инструментов ИИ, чем непосредственно в инспекторе.

    Уровень 4: способы передачи данных

    До сих пор сервер работал с использованием стандартного способа передачи данных. Выбор имеет значение, поскольку он определяет, как будет подключаться агент LangGraph.

    Рассматривайте способ передачи данных как физический кабель, а JSON-RPC — как язык, передаваемый по этому кабелю. Английский язык может передаваться как по телефону, так и по радио: один язык, два кабеля. Серверы MCP используют один и тот же формат JSON-RPC 2.0 независимо от способа передачи данных, но байты передаются по-разному.

    stdio — для локальных инструментов

    Это стандартный вариант, который используется функцией mcp.run(), когда она вызывается без аргументов:

    if __name__ == "__main__":
        mcp.run()  # stdio is the default
    

    С использованием stdio (стандартного ввода и вывода) хост запускает сервер в качестве подпроцесса и взаимодействует с ним, записывая данные в его stdin и считывая их из stdout. Сеть не задействуется: это обмен данными между процессами на одной машине. Такой подход подходит для серверов, работающих рядом с хостом, таких как инструменты файловой системы, запускатор локальных скриптов или личные утилиты; это самая простая и наиболее распространённая конфигурация для разработки.

    Одно ограничение имеет огромное значение. При использовании stdio поле stdout сервера зарезервировано исключительно для сообщений протокола, поэтому любая случайная строка отладки с использованием print() портит поток данных. Логирование должно происходить в stderr.

    Streamable HTTP для удалённых инструментов

    Для сетевого сервера необходимо явно указать способ передачи данных:

    if __name__ == "__main__":
        mcp.run(transport="streamable-http", host="0.0.0.0", port=8000)
    

    Здесь сервер работает как автономный веб-сервис. Клиенты подключаются к нему по сети с помощью запросов HTTP POST, при необходимости с использованием Server-Sent Events для потоковой передачи ответов. Благодаря этому сервер действительно является удаленным: он может находиться на другом устройстве, в облаке или за балансировщиком нагрузки, и одновременно обслуживать несколько приложений. Его следует использовать тогда, когда сервер необходимо делиться между командой, развертывать централизованно или обеспечивать доступ к нему с других устройств, включая агент LangGraph, работающий на сервере и взаимодействующий с сервером MCP для доступа к базе данных.

    Ориентиром может служить следующее: stdio — для локальных инструментов с одним пользователем и простой настройкой, характерных для разработки и личного использования; Streamable HTTP — для общедоступных инструментов с большим количеством пользователей или приложений, при необходимости производственного развертывания и аутентификации. Именно такой выбор необходимо указать для каждого сервера в конфигурации LangGraph.

    Уровень 5: подключение к LangGraph

    Этот «мост» представляет собой пакет с названием langchain-mcp-adapters, поддерживаемый командой LangChain для обеспечения возможности использования инструментов MCP внутри агентов LangGraph. Он выполняет для MCP ту же функцию, что декоратор @tool для обычных функций: он преобразует внешний инструмент MCP в объект BaseTool, который можно сразу использовать в узле ToolNode LangGraph без каких-либо особых настроек в графе. После преобразования агент не знает и не интересуется тем, пришел ли инструмент с сервера MCP или был написан непосредственно в процессе.

    Установите его с помощью:

    pip install langchain-mcp-adapters langgraph "langchain[openai]"
    

    Центральным объектом является MultiServerMCPClient, который может одновременно подключаться к нескольким серверам MCP и свободно комбинировать способы передачи данных:

    # ── MODULE 1 (extended): MCP CLIENT CONFIGURATION ───────────
    from langchain_mcp_adapters.client import MultiServerMCPClient
    
    client = MultiServerMCPClient({
        # A local server, launched as a subprocess via stdio
        "math": {
            "command": "python",
            "args": ["/absolute/path/to/math_server.py"],
            "transport": "stdio",
        },
        # A remote server, already running, connected over HTTP
        "company_data": {
            "url": "http://localhost:8000/mcp",
            "transport": "http",
        },
    })
    

    Каждая запись в словаре соответствует одному серверу. Ключ ("math" или "company_data") — это лишь метка, которая помогает внутренне организовать инструменты с разных серверов. Структура записи соответствует способу передачи данных: серверы stdio принимают command и args, а серверы HTTP — url.

    Загрузка инструментов осуществляется одним вызовом:

    # This single call discovers every tool, on every configured server,
    # and converts each one into a LangChain-compatible BaseTool
    tools = await client.get_tools()
    
    print([t.name for t in tools])
    # ['add', 'multiply', 'search_company_db', ...]
    

    Вот и вся процедура интеграции. client.get_tools() отправляет запрос MCP tools/list на каждый настроенный сервер, берет возвращенные схемы и оборачивает каждую из них в объект инструмента, который с точки зрения графа неотличим от вручную написанной функции @tool.

    Остальная часть настройки выглядит так же, как и в любом агенте LangGraph. MCP меняет источник инструментов, но не влияет на способ построения графа. Полный шаблон:

    # ============================================================
    # LANGGRAPH + MCP AGENT — COMPLETE TEMPLATE
    # Extends: Part 1 (core structure)
    # ============================================================
    
    # ── MODULE 1: IMPORTS & CONFIGURATION ───────────────────────
    import asyncio
    from langchain_mcp_adapters.client import MultiServerMCPClient
    from langchain.chat_models import init_chat_model
    from langchain_core.messages import HumanMessage
    from langgraph.graph import StateGraph, MessagesState, START, END
    from langgraph.prebuilt import ToolNode, tools_condition
    from langgraph.checkpoint.memory import MemorySaver
    llm = init_chat_model("openai:gpt-4o")
    client = MultiServerMCPClient({
        "math": {
            "command": "python",
            "args": ["./math_server.py"],
            "transport": "stdio",
        },
        "company_data": {
            "url": "http://localhost:8000/mcp",
            "transport": "http",
        },
    })
    
    # ── MODULE 2: STATE ──────────────────────────────────────────
    class State(MessagesState):
        pass
    
    # ── MODULE 4: NODES ──────────────────────────────────────────
    # (Module 3, Tools, is now sourced from MCP rather than defined here)
    def make_agent_node(llm_with_tools):
        """Factory pattern: tools are loaded asynchronously, so the node
        closure is built after the async tool-loading step completes."""
        def agent_node(state: State) -> dict:
            response = llm_with_tools.invoke(state["messages"])
            return {"messages": [response]}
        return agent_node
    
    # ── MODULE 6: GRAPH ASSEMBLY (inside an async function) ──────
    async def build_graph():
        tools = await client.get_tools()
        llm_with_tools = llm.bind_tools(tools)
    
        graph_builder = StateGraph(State)
        graph_builder.add_node("agent", make_agent_node(llm_with_tools))
        graph_builder.add_node("tools", ToolNode(tools))
    
        graph_builder.add_edge(START, "agent")
        graph_builder.add_conditional_edges("agent", tools_condition)
        graph_builder.add_edge("tools", "agent")
    
        return graph_builder.compile(checkpointer=MemorySaver())
    
    # ── MODULE 7: ENTRYPOINT ──────────────────────────────────────
    async def main():
        graph = await build_graph()
        config = {"configurable": {"thread_id": "session-001"}}
    
        response = await graph.ainvoke(
            {"messages": [HumanMessage(content="What's (3 + 5) times 12?")]},
            config=config
        )
        print(response["messages"][-1].content)
    if __name__ == "__main__":
        asyncio.run(main())
    

    Всё становится асинхронным

    MCP вносит лишь одно существенное изменение. Коммуникация по своей природе является асинхронной, поскольку каждый вызов инструмента представляет собой двустороннюю передачу данных по сети или внутри подпроцесса, даже при использовании стандартных ввода-вывода. Поэтому вызов client.get_tools() необходимо дожидаться, построение графа обычно выполняется внутри функции async def, а скомпилированный граф запускается с помощью ainvoke, а не invoke. Все остальные элементы — StateGraph, MessagesState, tools_condition и MemorySaver — остаются без изменений.

    Снова готовый маршрутизатор

    В этом шаблоне механизм маршрутизации практически отсутствует. Вместо пользовательского маршрутизатора используется готовый tools_condition: если в последнем сообщении есть вызовы инструментов, переходят в раздел "tools", в противном случае процесс завершается. Маршрутизатор не может отличить инструменты MCP от ручно написанных, поскольку к моменту их обработки графом оба они представляют собой объекты типа BaseTool.

    Уровень 6: вопросы, связанные с производственной эксплуатацией

    Несколько факторов отличают рабочую демонстрацию от системы, готовой к развертыванию, и именно они чаще всего возникают в реальных реализациях MCP и LangGraph.

    Поддерживайте активное соединение с клиентом. MultiServerMCPClient по умолчанию является безсостоянийским: каждый вызов инструмента открывает новое соединение, выполняет задачу и закрывает его. Это подходит для одного запроса. Однако в приложении, обслуживающем множество клиентов, открытие подпроцесса или HTTP-соединения при каждом вызове приводит к значительной задержке. В производственных условиях следует открыть клиент один раз при запуске процесса и использовать его на протяжении всего срока работы приложения:

    # Hold the connection open across the application's lifetime,
    # rather than opening/closing per request
    async with MultiServerMCPClient({...}) as client:
        tools = await client.get_tools()
        graph = await build_graph_with(tools)
        # ... serve many requests using this same graph ...
    

    Избегайте использования stdio на веб-сервере. Stdio был разработан для локальных сценариев с одним пользователем на одном компьютере, например, когда приложение на рабочем столе запускает вспомогательный процесс. Когда агент LangGraph развертывается в виде веб-сервиса для множества пользователей, серверы stdio становятся проблемой: по каждому запросу создаются подпроцессы, и нет естественного способа обмена состоянием или масштабирования. Для любого развертывания на стороне сервера предпочтительнее использовать Streamable HTTP, и честно оцените, действительно ли требуется отдельный процесс MCP. Бывают случаи, когда простая функция @tool, которая напрямую вызывает внутреннюю библиотеку, превосходит по простоте и скорости дополнительную обработку через протокол.

    Добавьте человеческое утверждение для чувствительных инструментов. Инструменты MCP становятся обычными инструментами после того, как попадают в граф, поэтому к ним применяются все существующие правила. Если сервер предоставляет доступ к чему-то чувствительному, такому как отправка электронных писем, изменение базы данных или осуществление платежей, необходимо обернуть эту операцию тем же шагом проверки с использованием interrupt(), что и для любого другого вызова инструмента. MCP обеспечивает возможность обнаружения и стандартизации, но по умолчанию не гарантирует безопасность. Эта задача остается на разработчике.

    Серверы не могут видеть состояние графа. Серверы MCP работают как отдельные процессы. Они не могут получить доступ к state LangGraph, к чекпоинтеру или к любым объектам Python в памяти. Когда необходимо адаптировать запрос, например с учётом сохранённых предпочтений пользователя, значение должно быть явно передано в качестве аргумента инструмента или предоставлено через интерцепторы — продвинутые механизмы, предлагаемые библиотекой langchain-mcp-adapters, которые позволяют проверять и изменять запрос до его отправки с использованием контекста выполнения графа. Передача значений в качестве аргументов достаточна для большинства агентов и гораздо проще.

    Уровень 7: MCP в многоагентной системе

    MCP интегрируется с паттерном supervisor. Несколько специализированных агентов получают свои инструменты с собственных отдельных серверов:

    # ── Specialist agents, each pulling tools from a DIFFERENT MCP server ──
    
    async def build_multi_agent_system():
        client = MultiServerMCPClient({
            "research": {"url": "http://localhost:8001/mcp", "transport": "http"},
            "code":     {"url": "http://localhost:8002/mcp", "transport": "http"},
        })
    
        research_tools = await client.get_tools(server_name="research")
        code_tools     = await client.get_tools(server_name="code")
    
        researcher_llm = llm.bind_tools(research_tools)
        coder_llm      = llm.bind_tools(code_tools)
    
        # From here, wire researcher_node, coder_node, and a supervisor_node
        # exactly as shown in Part 4 - the rest of the supervisor pattern
        # is completely unchanged.
        ...
    

    MCP здесь не вводит новую конкурирующую архитектуру. Специалист, работающий с помощью сервера MCP, по своей структуре идентичен тому, кто использует ручные инструменты: супервайзер направляет запросы так же, как и раньше, а специалисты передают отчеты аналогичным образом. MCP меняет лишь местоположение определений инструментов и количество приложений, которые могут их повторно использовать.

    Краткий обзор

    • Архитектура. Хост — это приложение ИИ, с которым взаимодействует пользователь (здесь это агент LangGraph). Клиент находится в хосте, по одному на каждый подключенный сервер, и управляет один-на-один сеансом. Сервер — это автономная программа, предоставляющая инструменты, ресурсы и промпты, не знающая, к какому хосту происходит подключение. JSON-RPC 2.0 — это формат сообщений для всех обменов: запросов, ответов и уведомлений.
    • Примитивы. Инструмент — это выполняемое действие, которое модель выбирает для вызова и которое создается с помощью @mcp.tool. Ресурс — это только для чтения данные, доступ к которым осуществляется по URI; они контролируются приложением или пользователем и создаются с помощью @mcp.resource("uri://..."). Запрос — это шаблон инструкции, который можно использовать повторно и который вызывается пользователем; он создается с помощью @mcp.prompt.
    • FastMCP. FastMCP(name="...") создаёт сервер, контейнер для всего. @mcp.tool обеспечивает доступ к функции, считывая указания типов для схемы и документацию для описания. @mcp.resource("scheme://{param}") объявляет только для чтения данные, причём {param} используется для создания шаблона. @mcp.prompt объявляет шаблон. mcp.run() запускает сервер; по умолчанию через стандартный ввод-вывод, либо с transport="streamable-http" для сетевого использования. fastmcp dev server.py открывает инспектор для тестирования без использования LLM.
    • Транспортные механизмы. stdio основан на подпроцессах и работает локально: сервер запускается на хост-машине, и вывод для отладки никогда не должен направляться в stdout. streamable-http работает через сеть, поддерживает множество одновременных хостов и является стандартным решением для производственных сред на общедоступных серверах.
    • Интеграция с LangGraph. MultiServerMCPClient({...}) из модуля langchain_mcp_adapters.client подключается к одному или нескольким серверам с использованием различных транспортных механизмов в одном словаре. Метод await client.get_tools() находит все инструменты и преобразует их в объекты типа BaseTool. tools_condition представляет собой заранее созданный маршрутизатор, который работает одинаково как с инструментами, написанными вручную, так и с инструментами, полученными через MCP. Все операции асинхронны: для get_tools(), построения графа и ainvoke требуется использование оператора await.

    Необходим ли здесь MCP?

    • Один инструмент, один агент, один кодовый базис. MCP не требуется. Простая функция @tool проще в использовании и не создаёт дополнительной нагрузки от протокола.
    • Инструмент, который используется в разных агентах или проектах, или делится с коллегами в других фреймворках. Создайте его в виде сервера MCP. В этом и заключается основная ценность.
    • Желание использовать сотни существующих серверов сообщества (GitHub, Slack, Postgres, Google Drive, Stripe и др.) вместо ручно написанного кода интеграции. Подключайтесь через MultiServerMCPClient и избавьтесь от необходимости писать код интеграции, что часто является главной экономией времени, которую предлагает MCP.
    • Инструмент, находящийся на другом устройстве, чем агент, или используемый одновременно несколькими хостами. Используйте Streamable HTTP в качестве отдельного сервиса.
  • Инструмент, который работает только локально вместе с одним агентом для целей разработки или личного использования. Для этого достаточно стандартных механизмов ввода-вывода, и их проще настроить.
  • Стандарт, а не замена

    Изучение нового протокола может вызвать опасения, что он заменит уже известные решения. MCP этого не делает — он оставляет инструменты, узлы и графы LangGraph без изменений. Изменяется лишь источник инструментов и количество приложений, которые могут ими пользоваться. После того как инструмент MCP достигает уровня ToolNode, он ведет себя как любой ручно написанный инструмент, проходит ту же проверку с помощью шаблонов interrupt() и соответствует тем же архитектурам управления.

    Прогресс происходил поэтапно: концепции и роли, три примитива, рабочий сервер, выбор способа передачи данных, мост LangGraph, усиление надежности в производственных условиях и композиция с многопроцессными системами. Каждый уровень добавлял новую идею к уже существующей стабильной основе. В сочетании с канонической структурой графа, управлением памятью, механизмами безопасности с участием человека, оркестрацией и извлечением данных многопроцессными системами это покрывает большинство потребностей серьезного производственного приложения на базе LangGraph, причем MCP позволяет инструментам расширяться за пределы одной кодовой базы.

    Связанные материалы

  • LangGraph Human-in-the-Loop: interrupt(), State Edits and Time Travel — Четыре паттерна LangGraph для человеческого контроля: утверждение вызовов инструментов с использованием функции interrupt(), механизмы обратной связи, ручные изменения состояния и возможность «путешествия во времени», вместе с необходимыми ключевыми словами.
  • Практические заметки: Cost-Engineered Agentic Coding: Создание решения промышленного уровня — Подробное руководство по практическим заметкам: Cost-Engineered Agentic Coding: Создание решения промышленного уровня: контракты, проверки и готовые блоки кода для команд, внедряющих этот паттерн.
  • Как MCP меняет способ подключения ИИ-агентов к бизнес-программам — Как протокол Model Context Protocol связывает агентов с CRM, ERP и внутренними API, что необходимо защитить, и как компании стоит начинать с малого.
  • LlamaIndex Plus LangGraph: стандартизированный подход для агентов RAG — Как создать базу знаний с помощью LlamaIndex и сделать её доступной для агента LangGraph в качестве инструмента, с пояснениями по функциям сохранения данных, Chroma и режиму работы только с поисковиком.
  • Подключение ИИ-агентов к GeoServer 2.28 с использованием расширения MCP — Установите JAR-файл расширения GeoServer MCP, убедитесь, что он загружен, вызовите конечную точку с помощью curl, подключите Claude Desktop или LangChain, а также ограничьте доступ и создайте инструменты для работы.