MCP: як це працює — повідомлення JSON-RPC, сервери FastMCP та трасування ReAct
Виконуйте запит модельного протоколу контексту від інструментів/списків до кінцевої відповіді за допомогою серверів FastMCP, агента LangGraph ReAct та трекера, який фіксує кожен крок.
Джерела: How MCP Works: A Deep Dive with Code
Model Context Protocol, або MCP, — це відкритий стандарт від Anthropic, який дозволяє ШІ-моделям, таким як Claude, використовувати зовнішні інструменти, джерела даних та сервіси. Добрим уявним прикладом є універсальний роз’єм: замість того, щоб писати індивідуальну інтеграцію для кожного інструменту, існує стандартний спосіб для моделі взаємодіяти з зовнішніми системами.
Компоненти
Структуру складають три елементи. MCP-хост — це додаток, який фактично використовує користувач, чи то вікно чату, чи IDE, і він містить клієнта, який керує з’єднанням. MCP-протокол — це стандартизований шар комунікації між хостом та серверами. Кожен MCP-сервер підключається до певного типу ресурсу, наприклад бази даних, зовнішнього API чи середовища виконання коду, та виступає як місток до нього.
Що відбувається під час виконання
На високому рівні запит проходить через наступні етапи:
- Користувач надсилає запит до хоста.
- Хост запитує сервери MCP, які інструменти вони пропонують.
- Сервери повертають свої списки інструментів.
- Хост надсилає запит разом із списком інструментів до LLM.
- LLM обирає інструмент та повідомляє про це хоста.
- Хост викликає відповідний сервер MCP для його виконання.
- Сервер виконує інструмент та повертає результат.
- Хост передає цей результат назад до LLM.
- LLM формує остаточну відповідь, яку хост передає користувачеві.
Сервер надає три типи ресурсів. Інструменти – це функції, які модель може викликати, такі як search_web, query_database або send_email. Ресурси – це читабельні дані, які хост може отримати як контекст, наприклад файли, записи бази даних, події календаря та документи; модель може їх читати, але не виконувати. Запити – це заздалегідь написані шаблони, які пропонує сервер. Наприклад, сервер GitHub може надати шаблон „Підсумуй цей PR“, який хост може показати користувачеві.
По суті, MCP – це лише стандартизований спосіб взаємодії хоста з сервером. Він визначає формат повідомлень та правила розмови, і нічого більше. Зокрема, він визначає чотири аспекти.
- Формат повідомлень. Усе відбувається за протоколом JSON-RPC 2.0. Запит містить
id,methodтаparams, а відповідь повторюєidразом ізresultабоerror, тож обидві сторони використовують однаковий формат. - Доступні методи. Протокол визначає фіксований набір операцій, які може виконувати хост: наприклад
tools/listдля пошуку,tools/callдля запуску інструменту,resources/readдля отримання даних таprompts/getдля завантаження шаблону. Сервери зобов’язані їх реалізувати. - Процедура взаємодії. Під час першого підключення обидві сторони обмінюються повідомленнями
initialize, у яких вказується версія протоколу та можливості, щоб кожна знала, що підтримує інша, ще до початку будь-яких інших дій.
Одне викликання інструменту розділяється на чотири повідомлення. Спочатку хост запитує, які інструменти існують:
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list",
"params": {}
}
Сервер відповідає описами своїх інструментів:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"tools": [
{
"name": "search_web",
"description": "Search the web for a given query",
"inputSchema": {
"type": "object",
"properties": {
"query": { "type": "string" }
},
"required": ["query"]
}
}
]
}
}
Потім ведучий кличе одного з них:
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "search_web",
"arguments": {
"query": "latest news on MCP protocol"
}
}
}
І сервер повертає результат:
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"content": [
{
"type": "text",
"text": "Anthropic released MCP in Nov 2024 as an open standard..."
}
]
}
}
Найкраще вивчати, створюючи — тому далі буде розглянуто невеликий сервер MCP, яким користується агент.
Що робить FastMCP
FastMCP — це фреймворк на Python для створення серверів MCP із мінімальною кількістю шаблонного коду. Без нього розробнику довелося б реалізувати цикл обробки повідомлень JSON-RPC, серіалізувати та десеріалізувати кожен запит та відповідь, вручну писати схеми JSON для кожної функції та обробляти протокольні повідомлення на кшталт initialize, tools/list, tools/call, resources/list та prompts/list. За допомогою цього фреймворку достатньо звичайної функції на Python та декоратора, а решту він бере на себе:
from fastmcp import FastMCP
mcp = FastMCP("My Server") # creates the server
@mcp.tool() # registers the function as an MCP tool
def add(a: float, b: float) -> float:
"""Add two numbers.""" # docstring → tool description sent to the LLM
return a + b # type hints → JSON Schema sent to the LLM
mcp.run() # starts the stdio message loop
На основі анотацій типів FastMCP самостійно створює схему JSON, а документація виконує роль опису простою мовою, який модель читає під час вирішення, чи варто викликати певний інструмент. Виклик mcp.run() запускає цикл, який блокується на stdin та stdout під час використання формату MCP wire, і саме до цього циклу під’єднується MultiServerMCPClient.
Три примітиви у прикладних серверах
Кожен сервер у проекті є окремим додатком FastMCP, який надає доступ до трьох типів примітивів.
Спочатку йдуть інструменти: функції, які модель може викликати. Достатньо лише ознакити функцію Python за допомогою @mcp.tool(), і FastMCP перетворює ці анотації та документацію на схему JSON, яка надсилається клієнту під час виклику tools/list. Модель вивчає цю схему, щоб зрозуміти, коли слід використовувати інструмент та які аргументи передати.
# servers/math_server.py
@mcp.tool()
def divide(a: float, b: float) -> float:
"""Divide a by b. Raises an error if b is zero."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
Ресурси — це тільки для читання дані, які знаходяться за URI. Модель не викликає їх автоматично, тому їх необхідно запитувати явно. У цьому проекті вони лише ілюструють ідею, тоді як у продакшн-середовищі їх використання може включати файли конфігурації, знімки бази даних чи документацію для посилань.
# servers/math_server.py
@mcp.resource("math://constants")
def get_math_constants() -> str:
"""Common mathematical constants."""
return f"π = {math.pi}\n e = {math.e}\n ..."
@mcp.resource("math://formulas/{category}")
def get_formulas(category: str) -> str:
"""Retrieve mathematical formulas by category (geometry | algebra | statistics)."""
catalog = {
"geometry": (
"Geometry Formulas:\n"
" Circle area: A = π × r²\n"
" Circle circumference: C = 2π × r\n"
" Rectangle area: A = length × width\n"
" Triangle area: A = (base × height) / 2\n"
" Sphere volume: V = (4/3) × π × r³\n"
),
"algebra": (
"Algebra Formulas:\n"
" Quadratic formula: x = (−b ± √(b²−4ac)) / 2a\n"
" Difference of squares: a²−b² = (a+b)(a−b)\n"
" Perfect square: (a+b)² = a²+2ab+b²\n"
" Sum of arithmetic seq: S = n(a₁+aₙ)/2\n"
),
"statistics": (
"Statistics Formulas:\n"
" Mean: μ = Σx / n\n"
" Variance: σ² = Σ(x−μ)² / n\n"
" Std Dev: σ = √(Σ(x−μ)² / n)\n"
" Z-score: z = (x−μ) / σ\n"
),
}
return catalog.get(
category,
f"Unknown category '{category}'. Available: geometry, algebra, statistics",
)
URI math://formulas/{category} є шаблоном. Його частина {category} є параметром шляху, завдяки чому math://formulas/geometry та math://formulas/algebra є двома окремими ресурсами, які обслуговуються однією й тією самою функцією.
Інструкції є повторно використовуваними шаблонами команд. Інструкція – це параметризоване системне повідомлення, яке клієнт може звернутися за ним, спосіб упакування профілю експерта чи інструкцій до завдання всередині сервера, щоб будь-який підключений клієнт міг їх послідовно використовувати.
# servers/math_server.py
@mcp.prompt()
def math_tutor(difficulty: str = "intermediate") -> str:
return (
f"You are an expert math tutor for {difficulty}-level students. "
"Break every problem into numbered steps..."
)
Як показано у наступних розділах, сервери разом надають 19 інструментів.
Погляд клієнта
Ось що саме відбувається після запуску python main.py із запитом. Шлях запиту від початку до кінця виглядає так:
You type a query
│
▼
main.py ← entry point, parses args, kicks off async loop
│
▼
client/agent.py ← spawns 3 MCP servers, builds the agent, invokes it
│ │
│ ▼
│ utils/tracker.py ← fires on every LLM call, tool call, and result
│
▼
LangGraph ReAct loop ← think → call tool → observe → repeat
│
▼
servers/{math,text,data}_server.py ← each runs as an isolated subprocess
Крок 1: де починається виконання
main.py — це перший файл, який виконує Python. Він завантажує змінні середовища, аналізує аргументи командного рядка, виводить панель вітання та передає контроль асинхронному виконавцю.
async def _run(queries: list) -> None:
from client.agent import run_query # imported here (late) to keep startup fast
for i, q in enumerate(queries):
await run_query(q)
def main() -> None:
...
asyncio.run(_run(queries))
asyncio.run() створює новий цикл подій та блокується доти, доки не завершиться виконання _run(). Запит, який використовувався для демонстрації, був таким:
Generate 8 random numbers between 5 and 50 using seed=42,
then calculate their statistics, and tell me if there are any outliers.
Запустіть з командного рядка ось так:
python3 main.py --query "Generate 8 random numbers between 5 and 50 using seed=42, \
then calculate their statistics, and tell me if there are any outliers."
Панель статичної інформації потім друкується за допомогою _print_header():
╭────────────────────────────── 🔌 MCP Example ───────────────────────────────╮
│ Multi-Server MCP Demo │
│ │
│ Three FastMCP servers, each exposing tools + resources + prompts: │
│ ● Math Server — add, subtract, multiply, divide, power, sqrt, │
│ percentage │
│ ● Text Server — count_words, word_frequency, reverse, transform, │
│ extract_emails │
│ ● Data Server — generate_numbers, calculate_statistics, find_outliers, │
│ normalise │
│ │
│ Stack : FastMCP · LangChain · LangGraph · OpenAI · Rich │
│ Track : live Rich panels + JSONL log files under logs/ │
╰──────────────────────────────────────────────────────────────────────────────╯
Крок 2: створення агента
client/agent.py містить run_query(query) — асинхронну функцію, яка координує всі дії. Спочатку вона створює трекер та файл журналу.
log_file = str(LOGS_DIR / f"run_{int(time.time())}.jsonl")
tracker = MCPTracker(log_file=log_file)
Перш ніж під’єднати будь-який сервер, створюється об’єкт MCPTracker, а також готується файл у форматі JSONL із позначкою часу під каталогом logs/. Відтоді кожна подія записується там у реальному часі.
Далі виводиться запит користувача:
╭──── 💬 USER QUERY ────╮
│ Generate 8 random... │
╰────────────────────────╯
Потім визначаються сервери для створення:
def _server_config() -> Dict[str, Any]:
silent_env = {**os.environ, "FASTMCP_LOG_LEVEL": "ERROR"}
return {
"math_server": {
"command": sys.executable,
"args": ["servers/math_server.py"],
"transport": "stdio",
"env": silent_env,
},
"text_server": { ... },
"data_server": { ... },
}
Кожен запис описує один сервер MCP, який працює як підпроцес. command — це вже запущений інтерпретатор (sys.executable), args вказує назву скрипту сервера, а transport визначає спосіб взаємодії клієнта та сервера; stdio означає стандартні канали введення та виведення. Поле env встановлює середовище підпроцесу, а FASTMCP_LOG_LEVEL=ERROR пригнічує відображення інформації про запуск FastMCP.
Транспорт типу stdio є найпростішим у MCP: клієнт записує повідомлення формату JSON-RPC у stdin сервера та читає відповіді з його stdout, тому не відкривається жоден мережевий порт.
Після цього клієнт під’єднується до кожного сервера та виявляє наявні інструменти:
client = MultiServerMCPClient(_server_config())
tools = await client.get_tools()
MultiServerMCPClient з бібліотеки langchain-mcp-adapters виконує наступні дії щодо кожної запису про сервер одночасно. Він створює дочірній процес, надсилає сигнал ініціалізації MCP initialize через стандартний вхід/вихід, надсилає запит tools/list, отримує список схем інструментів та обгортає кожну схему об’єктом LangChain Tool.
Коли виконання await client.get_tools() завершується, результатом є простий список з 19 об’єктів StructuredTool: сім з сервера з математичними операціями, сім з серверів для обробки тексту та п’ять з серверів даних. Цей список є повним набором дій, доступних для моделі.
Connected to 3 servers (math_server, text_server, data_server) with 19 tools: add, subtract, multiply,
divide, power, square_root, calculate_percentage, count_words, word_frequency, reverse_text,
transform_case, find_and_replace, extract_emails, count_vowels_consonants, generate_numbers,
calculate_statistics, find_outliers, sort_values, normalize_values
Потім створюються модель мови та агент:
model = ChatOpenAI(model=model_name, temperature=0)
agent = create_react_agent(model, tools)
Функція create_react_agent у LangGraph створює скомпільовану графіку стану з такою структурою:
START
│
▼
[call_model] ─── no tool call ──▶ END
│
tool call requested
│
▼
[call_tools]
│
▼
[call_model] (loop again with tool result in context)
Це шаблон ReAct — міркування разом із дією. Модель аналізує наступний крок, діє шляхом виклику інструменту, спостерігає за результатом та повторює процес, поки не отримає достатньо інформації для відповіді.
Нарешті викликається агент:
config = {"callbacks": [tracker]}
result = await agent.ainvoke({"messages": [("human", query)]}, config=config)
Елемент "callbacks": [tracker] підключається до системи викликів-відповідей LangChain. Кожного разу, коли фреймворк виконує щось значуще, наприклад починає або завершує виклик ШІ чи інструменту, він викликає відповідний метод у tracker. Саме так трекер бачить усе, не знаходячись всередині жодної з логічних частин.
Крок 3: спостереження в реальному часі
MCPTracker розширює клас BaseCallbackHandler з LangChain. Його методи ніколи не викликаються безпосередньо, оскільки LangChain викликає їх у правильний момент.
agent.ainvoke() called
│
├─▶ on_chain_start() "▶ AGENT STARTED" panel
│
├─▶ on_chat_model_start() "🤖 LLM CALL #1" panel (timer starts)
├─▶ on_llm_end() "LLM responded ⏱ 1.23s → will call: add, multiply"
│
├─▶ on_tool_start() "🔧 TOOL CALL #1" panel (timer starts)
├─▶ on_tool_end() "✓ TOOL RESULT ⏱ 0.01s" panel
│
├─▶ on_tool_start() (second tool, if any)
├─▶ on_tool_end()
│
├─▶ on_chat_model_start() "🤖 LLM CALL #2" (LLM synthesises final answer)
├─▶ on_llm_end() no tools this time → loop ends
│
└─▶ agent.ainvoke() returns
Кожного разу, коли викликається on_tool_start, трекер визначає, який сервер володіє інструментом, та присвоює відповідний колір. Єдина мета — покращити читабельність.
TOOL_SERVER_MAP = {
"add": "math_server",
"count_words": "text_server",
"generate_numbers": "data_server",
...
}
SERVER_COLORS = {
"math_server": "cyan",
"text_server": "green",
"data_server": "yellow",
}
Кожна подія стає одним рядком JSON у файлі logs/run_<timestamp>.jsonl. Файл відкривається у режимі додавання та записується негайно, тому виконання команди tail -f logs/run_*.jsonl у іншому терміналі демонструє первинні події, які оновлюються під час роботи агента. Після того, як agent.ainvoke() повертається, файл client/agent.py вручну викликає функцію print_summary(), яка повідомляє про загальну кількість викликів LLM, викликів інструментів та час, що минув, протягом усього запуску.
Першою, що з’являється, є інформація про перший виклик LLM із одним повідомленням:
── 🤖 LLM CALL #1 model=gpt-5-mini messages=1 ──╮
│ Role Content preview │
│ Human Generate 8 random numbers between 5 and 50… │
╰──────────────────────────────────────────────────────╯
Граф ReAct щойно розпочався. Модель отримує системний запит, введений LangGraph разом із списком інструментів та їхніми схемами, а також одне повідомлення від людини, тому messages=1.
LLM responded ⏱ 5.35s → will call: generate_numbers
Трекер перевірив необроблену відповідь моделі. Замість прози модель надіслала структурований запит на виклик інструменту:
{
"name": "generate_numbers",
"arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}
}
У значенні response.generations[0][0].message.tool_calls трекер виявив запит та вивів його назву. 5,35 секунди — це просто час на передачу даних та їх отримання від API OpenAI. LangGraph обробляє це рішення та переходить до вузла call_tools, що призводить до першого виклику інструменту:
╭── 🔧 TOOL CALL #1 ──────────────────╮
│ Tool : generate_numbers │
│ Server: data_server │
│ Args : │
│ {'count': 8, 'min_val': 5, │
│ 'max_val': 50, 'seed': 42} │
╰───────────────────────────────────────╯
За назвою інструменту generate_numbers трекер звернувся до TOOL_SERVER_MAP, який відповідає data_server, і пофарбував панель у жовтий колір, оскільки SERVER_COLORS["data_server"] дорівнює "yellow". Саме в цей момент LangChain надсилає повідомлення JSON-RPC tools/call через канал stdio до дочірнього процесу data_server:
{"method": "tools/call", "params": {"name": "generate_numbers",
"arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}}}
Процес отримує його, виконує функцію Python та записує результат назад у свій stdout.
╭── ✓ TOOL RESULT ⏱ 0.63s ────────────────────────────╮
│ [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91] │
╰──────────────────────────────────────────────────────────╯
Він виконав саме цей код:
random.seed(42)
return [round(random.uniform(5, 50), 2) for _ in range(8)]
# → [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
0,63 секунди — це час від надсилання запиту до отримання відповіді через канал зв’язку, включаючи додаткові витрати на планування процесів у Python. LangGraph додає результат до списку повідомлень агента у вигляді ToolMessage, тож тепер у списку є три елементи: повідомлення від людини, повідомлення від ШІ (рішення щодо використання інструменту) та результат від інструменту.
Далі йде другий виклик LLM із трьома повідомленнями:
╭── 🤖 LLM CALL #2 model=gpt-5-mini messages=3 ──╮
│ Role Content preview │
│ Human Generate 8 random numbers… │
│ AI (the tool-call decision) │
│ Tool [33.77, 6.13, 17.38, ...] │
╰──────────────────────────────────────────────────────╯
Модель знову запускається з усією наявною історією. Вона бачить початкове запитання, власне попереднє рішення про виклик функції generate_numbers та отримані числа. Її міркування виглядають приблизно так: числа вже є, а у запитанні також просили статистику, тому слід виконати функцію calculate_statistics з ними. Це призводить до другого виклику інструменту та його результату:
Tool : calculate_statistics
Server: data_server
Args : {'numbers': [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]}
Result: {"count":8, "min":6.13, "max":45.15, "mean":24.9962,
"median":25.575, "std_dev":14.8181, "variance":219.5755,
"range":39.02, "q1":15.04, "q3":38.14}
Модель тут нічого не запам’ятала. Вона буквально брала значення слово за словом з попереднього ToolMessage у своєму вікні контексту та вставляла їх у аргументи наступного інструменту. Саме так виглядає ланцюгування дій у циклі ReAct: те, що виводить один інструмент, стає контекстом, який може прочитати та використати наступне викликання моделі.
У третьому виклику LLM є п’ять повідомлень, і модель викликає find_outliers:
Tool : find_outliers
Server: data_server
Args : {'numbers': [...], 'threshold': 2}
Result: {"outliers": [], "outlier_count": 0,
"total_checked": 8, "mean": 24.9962, "std_dev": 14.8181}
Функція find_outliers обчислює з-рейтинг кожного значення (z = (x − mean) / std_dev) та перевіряє, чи якийсь з них перевищує поріг у 2. Жоден не перевищує його, тому список outliers є порожнім.
У виклику LLM номер 4 є сім повідомлень:
╭── 🤖 LLM CALL #4 messages=7 ──╮
│ Human / AI / Tool │
│ AI / Tool │
│ AI / Tool │
╰───────────────────────────────────╯
LLM responded ⏱ 30.25s
Відсутній суфікс „will call“ свідчить про те, що модель створила звичайний текст, а не запит на використання інструменту, що завершує цикл ReAct. Виконання запиту зайняло 30 секунд, оскільки контекст був об’ємним (сім повідомлень, включаючи необроблені результати у форматі JSON), і модель створила довгий, ретельний синтез, вручну обчислюючи з-значення для кожного значення. LangGraph не знаходить жодних запитів на використання інструментів у відповіді та направляє процес до END, який виводить кінцеву відповідь:
╭── ✅ FINAL ANSWER ───────────────────────────────╮
│ Random numbers: [33.77, 6.13, 17.38, ...] │
│ Mean: 24.9962 / Median: 25.575 / Std Dev: 14.8181│
│ Outliers: none (all |z| < 2) │
╰───────────────────────────────────────────────────╯
Потім з’являється підсумок пробіжки:
╭─────────────────────────────────────────────────────╮
│ LLM Calls 4 │
│ Tool Calls 3 │
│ Total Time 42.25s │
│ Log File logs/run_1776864980.jsonl │
╰─────────────────────────────────────────────────────╯
Повна послідовність повідомлень
Це всі елементи списку повідомлень агента, які були повернуті після виклику agent.ainvoke():
1 HumanMessage "Generate 8 random numbers…"
2 AIMessage [tool_call: generate_numbers({count:8, min:5, max:50, seed:42})]
3 ToolMessage [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
4 AIMessage [tool_call: calculate_statistics({numbers:[...]})]
5 ToolMessage {count:8, mean:24.9962, std_dev:14.8181, ...}
6 AIMessage [tool_call: find_outliers({numbers:[...], threshold:2})]
7 ToolMessage {outliers:[], outlier_count:0, ...}
8 AIMessage "Here are the results. Random numbers: …" ← final answer
Кожен виклик LLM отримує всю інформацію, накопичену досі, тому показник messages у панелях відстеження зростає на 1, 3, 5, 7.
Журнал JSONL
Усі вищезазначені події також записувалися у logs/run_x.jsonl у момент їх виникнення, причому кожен рядок містив один об’єкт JSON:
{"timestamp": "...", "event": "agent_start", "data": {"runnable": "LangGraph", "run_id": "..."}}
{"timestamp": "...", "event": "llm_call", "data": {"call_number": 1, "model": "gpt-5-mini", "messages": 1}}
{"timestamp": "...", "event": "llm_end", "data": {"elapsed": "5.35s", "tool_calls_requested": ["generate_numbers"]}}
{"timestamp": "...", "event": "tool_start", "data": {"call_number": 1, "tool": "generate_numbers", "server": "data_server", "args": "..."}}
{"timestamp": "...", "event": "tool_end", "data": {"elapsed": "0.63s", "output_preview": "[33.77, 6.13, ...]"}}
{"timestamp": "...", "event": "llm_call", "data": {"call_number": 2, "model": "gpt-5-mini", "messages": 3}}
...
{"timestamp": "...", "event": "run_summary", "data": {"llm_calls": 4, "tool_calls": 3, "total_elapsed": "42.25s"}}
Чому це важливо
Справжня цінність MCP полягає у можливості розповсюдження. До появи стандарту кожна команда, яка хотіла використовувати LLM поза межами його можливостей, мусила створювати власний шар інтеграції, причому весь цей робочий процес не переносився на інші моделі чи фреймворки. Тепер сервер пишеться один раз та обслуговує будь-якого відповідного клієнта. Команда з баз даних може оприлюднити сервер лише для читання для своєї схеми, команда DevOps може зробити доступними інструменти для розгортання, а платформа з обробки даних — функції запитів та аналітики. Будь-який агент може під’єднатися до всіх них, і командам більше не потрібно домовлятися щодо деталей реалізації.
Пов’язана література
- Побудова агента у стилі Claude Code за допомогою LangChain Deep Agents — Як працює система керування кодувальним агентом, від основного циклу до інструментів, планування, пам’яті, підагентів та процедур схвалення в ізольованому середовищі, з покроковою реконструкцією за допомогою deepagents.
- Десять серверів MCP, які варто встановити першими, у порядку пріоритету для розробників — Список серверів MCP для допоміжних систем кодування на основі ШІ, від Context7 та GitHub до Postgres та механізмів пам’яті, із налаштуваннями встановлення та рекомендаціями щодо прав доступу.