MCP для агентаў LangGraph узровень за ўзроўнем: серверы, транспарты і адаптар
MCP для агентаў LangGraph па ўзроўнях: ролі хоста, кліента і сервера, сервер на FastMCP, транспарты stdio і HTTP, langchain-mcp-adapters і тыповыя пасткі.
Крыніцы: 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}"
Гэта нормальна, пакуль не патрабуецца масштабаванне. Падумаймо, што пяць агентаў у пяці праектах усім патрэбна адзінка „пашук у базе дадзеных компаніі“. За вышэўшым патэрнам тая ж самая адзінка пішаецца пяць разоў, у пяці кодбазах, можа, нават у пяці мовах. Змена схемы значыць пяць правакаў. Аддача яе колеге, які стварае іншага роду прыстаўку AI, можа, нават не на LangGraph, выклікае аблік, таму што функцыя @tool належыць да света Python у LangChain.
Назва гэтай проблемы — проблема інтэграцыі N×M. N адзінак (базы дадзеных, API, сістэмы файлаў) павінны быць падключаныя да M прыстаўак AI (агент LangGraph, спецыяльны агент колегі, Claude Desktop, асістэнт IDE). Без спяльнага стандарта выходзяць індывідуальныя інтэграцыі тыпу N×M.
Model Context Protocol (MCP) — гэта адаптаваны, універсальны стандарт для з’яеднання прыкладнікаў AI з інструментамі і дадзеннямі. Інструмент, створаны як сервер MCP, можа быць выкарыстоўваны будзь-якім прыкладнікам, які падтрымлівае MCP, чы то агент LangGraph, Claude Desktop, Cursor чы спецыяльны агент, без неабяжнага коду для інтэграціі. Звычайнае паўпораўнанне — цэе порт USB-C: адні стандарты канектараў, будзь-якія сумесныя прыстроі з кожнай стороны.
Шлях ад „што такое MCP“ да сервера высокага рангу, падключанага да рэальнага агента LangGraph, праходзіць праз пяць рэвэў, кожны з якіх даўае новую інфармацыю.
Рэвэ 1: што такое MCP
Пачатакніце з атракцыяў пры любым кодзе. Кансьерж гатэля лячыць сам не як заброніраваць столік у рэстаране, вызваць таксі чы адкупіць квіткі на тэатр. Кансьерж ведае спіс надзеяных местных служб, кожная з якіх ёсць спецыялістам. Калі гасць хочаць заброніраваць вечараю, кансьерж падключаецца да спецыяльнай лініі да службы броніравання, складае запіт у фармаце, які разумеюць обе стороны, і перадае адпаведную адпаведзь.
MCP — гэта стандартная лінія і стандартны фармат запіта. Програма на AI выступае як кансьерж. Сервер MCP — гэта спецыялізаваная служба, такая як сістэма броніравання рэстаранаў, компанія таксі чы каса з квіткамі. Сам MCP — гэта спакойны язык і схема з’яўлення, таму любы кансьерж можа спілкувацца з любай службай без патрэбы вучыцца, як кожная з іх працюе.
Тры ролі
Кожная сістэма MCP складаецца з роўна трох учаснікаў, а усё інша будуе на іхніх асновах.
- Хост. Аплікацыя AI, яюй насправды выкарыстоўвае канечны корыстнік: тут — агент LangGraph, а ў іншых случаях — Claude Desktop, Cursor або VS Code з copilotам. Ён керуе размовай, выявляе, калі патрэбна інструмент, і паказвае рэзультаты.
- Кліент. Ён знаходзіцца ўнутрь хоста, і кожны кліент падтрымлівае спецыяльны одназначны звязак толькі з аднім серверам. Хост, які падключэны да трох сервераў, у сабе керуе трыма кліентамі. Такая одназначная прыналежнасць ўтварае намераваную межу безпекі, таму кліент для сервера файловай сістэмы не можа віпадкова прасочыць даныя на сервер базы дадзеных.
Фармат канектавання: 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"}}}
Адказ — гэта адказ на запыт. У яго ёсць або рэзультат для успеху, або памылка для няудачы, пры чым id застаецца тым самым, як і у запыту:
{"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 чытае падсказкі пра тып функцыі, каб стварыць схему вхідных дадзеных, і чытае докстрынг, каб стварыць апісацыю, якую бачыць LLM. Праўіллі, якія дыяюць для звычных інструментаў, застосовуюцца і тут, толькі з большымі наследкамі: нечысты докстрынг заставляе мадэль не ведаць, калі вызваць інструмент, і гэта нечыстае апісаванне вплывае на кожную аплікацыю, якая з’яўляецца на зв’язку, а не толькі на аднаго агента.
Для дадання рэсурса трэба выкарыстоўваць дэкаратар з выбраным 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
Перш чым пад'яжыць рэальны прыкладкі AI, пераканайцеся ў яе працэсе за дапамою MCP Inspector — інструмента для дыягнастыкі, які функцыонуе ў браузеры і ўключаецца ў экасістэму. Ён паказвае наявныя інструменты, дазволяе ўручну ўвядзаць каліянты і пераглядаць рэсурсы без удзеле LLM:
fastmcp dev math_server.py
Гэта ачыяе локальны веб-інтэрфейс, зазвычай пад http://127.0.0.1:6274, дзе можна пераходзіць між засобамі, вводзіць параметры тэстаў і спазірваць паведамленні JSON-RPC, якія пераходзяць туды-сюды. Спачатку працаваць трэба тут. Зламаны засоб лёгкая адладзіць праз прыемы вызыва засобаў ад LLM, чым безпосерэдна ў інспектары.
Рэгламент 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 прыносіць адзін сэрьёзны змяненні. Комунікацыя ў сваій характар ёсць асінхронной, адколі кожны вызов інструмента ёсць раунд-трыпам у сеткі чыстаць падпроцес, нават праз stdio. Таму 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, у checkpointer чы ў будзь-якім об’екце Python у памяці. Калі неабходна персоналізацыя вызову, напрыклад, з ужываннем зберажаных праганаў корыстніка, значэнне павінна быць явна перадана як аргумент інструмента або задана праз інтэрцэптары — адавансаваныя хукі, якія пропонуе langchain-mcp-adapters і якія могу аналізаваць і меняць вызов прычыму ўжывання кантэкста выканання графа. Перадача значэнняў як аргументаў дастатня для большасці агентаў і ўсё гэта значна простае.
Рэгламент 7: MCP у сістэме з калькама агентаў
MCP сумавочваецца з патэранам супервізора. Калькі спецыялістаў-агентаў кожны атрымваюць своі інструменты з аднароднага для іх сервера:
# ── 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 змінівае толькі месца размешчэння адзінакоў інструментоў і колькасць прыкладненняў, якія можа ўзяць іх у спільнае вжыцце.
Короткая інфармацыя
- Архітэктура. Host — гэта прыкладненне AI, з якім працуе корыстнік (тут агент LangGraph). Client знаходзіцца ў host-е, по аднаму на кожны падключаны сервер, і керуе адно-до-аднаго сэсіяй. Server — гэта самастоятэльная програма, якая выкладзець інструменты, рэсурсы і запіты, не ведаючы, з якога host-а ведуцца звязкі. JSON-RPC 2.0 — гэта фармат паведамленняў у всіх абмянках: запітах, адпаведзях і паведамленнях.
- Прымітывы. Tool — гэта выполняемая дзеяннё, якую модэль выбірае вызваць, створаная з
@mcp.tool. Resource — гэта толькі для чытання даныя, якія адрэсуюцца па URI, кантролююцца прыкладненнем або выкарыстоўвальнікам, створаныя з@mcp.resource("uri://..."). Prompt — гэта шаблон інструкцыі, які можна перыяўтваць і які выкарыстоўвальнік вызывае, створаныя з@mcp.prompt. - FastMCP.
FastMCP(name="...")стварае сервер, які ўтрымвае ўсё.@mcp.toolадкрывае функцыю, якая чытае падсказкі пра тыпы для схемы і докстрынг для апісання.@mcp.resource("scheme://{param}")прызначае толькі для чытання даныя, пры чым{param}стварае шаблон.@mcp.promptпрызначае шаблон.mcp.run()запускае сервер, за замовчаннем праз stdio, або з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 дазволяе інструментам часткова расшырвацца за межы адной базы коду.
Супаўзеўныя матэрыялы
- Практычныя прытамулы: Чаму ніхто не говорыць пра LangChain, LangGraph чы AutoAgent — Паследовыя інструкцыі па вікорыстоўванню Практычных прытамулов: Чаму ніхто не говорыць пра LangChain, LangGraph чы AutoAgent: контракты, перакананні і шаблоны коду для команд, якія впрыменяюць гэты падход.
- ReAct у LangGraph: Ад ручна пабудаванага цыклу да ToolNode і StateGraph — Створыце агента ReAct два разы: спачатку як ручны асінхронны цыкл, а потым з ToolNode, tools_condition і StateGraph з LangGraph, якія автаматызуюць аб’еднаныя вызовы інструментаў.