Function Calling / Tool Calling / MCP JSON-RPC — четыре round-trip / диалекты схем / наблюдаемость и изоляция
Откройте Cursor, Claude Code или debug-лог любого Agent-фреймворка — почти каждый payload — JSON: каталоги инструментов — JSON Schema, tool_calls модели — JSON, фреймы MCP Server — JSON-RPC 2.0. Это не случайность — Agents должны соединить непредсказуемый естественный язык и исполняемые программные интерфейсы, и JSON — формат обмена, который обе стороны могут надёжно парсить.
Эта статья проходит Function Calling → Tool Calling → MCP и показывает четыре JSON round-trip полного вызова инструмента. Если вы разворачиваете MCP Server на облачном Mac или выбираете фреймворки из нашей подборки GitHub Agent, понимание этого потока при отладке полезнее, чем заучивание API-доков.
Agents говорят JSON почти везде
LLM выдают потоки токенов; Shell, базы данных и HTTP API нуждаются в структурированных аргументах. Ранняя практика — промпт «ответь в этом JSON-формате» — модели часто добавляли trailing commas, убирали кавычки или оборачивали в Markdown fences, и парсеры постоянно падали.
С 2023 года основные API перенесли структурированные действия в протокол: модель больше не свободно выдаёт произвольный JSON-текст; сервер ограничивает форму вывода, Host выполняет. Pipeline становится:
- Declare — регистрация инструментов через JSON Schema;
- Decide — выбор имени инструмента и параметров в ограниченной грамматике;
- Execute — выполнение через локальный код или MCP Server;
- Write back — записать результаты как JSON-сообщения в контекст.
Принцип проектирования: наблюдаемость Agent = логировать, воспроизводить и diff каждый JSON-шаг. Без структурированных промежуточных данных автоматизация не аудируема.
Function Calling: от естественного языка к структурированным действиям
Объект function эры OpenAPI
OpenAI добавил functions / tools в Chat Completions: вы присоединяете определения инструментов к запросу; модель возвращает function_call или tool_calls вместо текста, который нужно парсить regex.
Типичный фрагмент запроса
{
"model": "gpt-4o",
"messages": [{"role": "user", "content": "Погода в Токио?"}],
"tools": [{
"type": "function",
"function": {
"name": "get_weather",
"description": "Текущая погода по городу",
"parameters": {
"type": "object",
"properties": { "city": { "type": "string" } },
"required": ["city"]
}
}
}]
}Ручные JSON-шаблоны в промптах заменяются ограничениями протокола; Host валидирует arguments по схеме и вызывает реальные функции. Function Calling фиксирует, что говорит модель — не где работают инструменты, как они находятся или как работает auth. Экосистемы Tool Calling и MCP берут это на себя.
Tool Calling: четыре JSON round-trip на turn
- Register — Host отправляет
tools[]с JSON Schema в API модели; - Decide — API возвращает
tool_callsсid,name,arguments(JSON-строка); - Execute — Host парсит аргументы и вызывает локальный код или MCP;
- Write back — сообщения
role: toolвозвращают результаты; модель формирует ответ пользователю.
{
"tool_calls": [{
"id": "call_abc123",
"type": "function",
"function": {
"name": "get_weather",
"arguments": "{\"city\":\"Tokyo\"}"
}
}]
}arguments — строка, не вложенный объект — для streaming и совместимости SDK. Hosts должны выполнить JSON.parse(arguments) перед валидацией. Нажмите Ctrl + Shift + I в DevTools и вы увидите ту же структуру в Network.
| Этап | Направление | Payload | Парсер |
|---|---|---|---|
| ① Register | Host → API | tools[] + JSON Schema | API gateway |
| ② Decide | API → Host | tool_calls | Host / SDK |
| ③ Execute | Host → Tool | Распарсенный объект | Реализация инструмента |
| ④ Write back | Host → API | {role:"tool", content:"..."} | Модель |
Диалекты API-схем
- OpenAI / совместимые endpoints
tools+tool_choice; streaming использует chunksdelta.tool_calls.- Anthropic
toolsсinput_schema; ответы — блокиtool_useи repliestool_result.- Google Gemini
functionDeclarationsиfunctionCallс разными именами полей.- Ollama локально
- OpenAI-совместимые
tools; возможности зависят от обучения модели.
Фреймворки вроде LangGraph и DeepSeek Harness (см. наш гайд Harness) сжимают эти диалекты в одну абстракцию Tool — под ней всё равно JSON.
MCP: JSON-RPC стандартизирует слой инструментов
Model Context Protocol (MCP) находится ниже Function Calling: как процессы инструментов находятся, параметризуются и переиспользуются между Hosts. Транспорт может быть stdio или SSE, но сообщения всегда JSON-RPC 2.0.
| Слой | Протокол | Примеры |
|---|---|---|
| Model API | REST / OpenAI-совместимый | chat/completions + tools |
| MCP | JSON-RPC 2.0 | tools/list, tools/call |
| Business | Любой | файлы, DB, HTTP |
Hosts вызывают tools/list при старте, переводят каталоги в API tools[], затем отправляют tools/call после решения модели — две конвертации диалекта, один семантический pipeline.
{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "read_file",
"arguments": { "path": "/tmp/demo.txt" }
}
}Как разделяются JSON-фреймы в режиме stdio?
MCP stdio использует заголовки Content-Length + JSON body (как LSP), не newline-delimited JSON. Большие payload (например base64-ресурсы) помещаются в один фрейм. SSE оборачивает JSON-RPC в HTTP event streams для multi-client Servers.
Полный поток данных: от ввода пользователя до выполнения
- Логи фиксируют каждую версию
tools/listи число инструментов? argumentsвалидируются по схеме перед выполнением?- Таймауты MCP мапятся на читаемые сообщения
tool? - Секреты удаляются перед логированием?
Та же идея, что этап Verify в нашем AI Coding Workflow: без parseable промежуточных данных вы не можете автоматически проверить, что Agent действительно вызвал правильный инструмент.
Почему не Protobuf или XML?
- API моделей — JSON-first; бинарные форматы добавляют слои сериализации;
- Отладка — инженеры читают параметры в логах;
- Экосистема схем — JSON Schema и OpenAPI — де-факто стандарты;
- Скрипты и браузеры — curl, n8n, front-end демо предполагают JSON.
Tradeoff: размер и CPU. High-QPS setups кэшируют внутри и сжимают логи; большие blob идут base64 внутри JSON-полей — не заменяя JSON envelope.
Затраты JSON и инженерные решения
| Симптом | Причина | Решение |
|---|---|---|
| arguments parse error | Невалидная JSON-строка от модели | Строже схема, ниже temperature, retry |
| Неверный инструмент | Размытые или слишком много описаний | Объединить инструменты, негативные примеры |
| MCP зависает | Неполный stdio-фрейм или мёртвый процесс | launchd supervisor, health checks |
| Секреты в логах | Результат инструмента включает env vars | Redact результаты, отдельный execution account |
Совет для production: запускайте MCP на изолированном облачном Mac — Cursor на ноутбуке отправляет JSON-RPC через SSH; Shell никогда не живёт на вашей повседневной машине.
Agents зависят от JSON, потому что решения в естественном языке и программное выполнение нуждаются в человекочитаемом, машинно-валидируемом, подключаемом контракте. Function Calling определяет, что говорит модель; Tool Calling — как Host выполняет turn; MCP — как процессы инструментов подключаются к экосистеме — JSON — нить через все три.
Запустите JSON execution plane MCP на облачном Mac
Выделенные узлы M4, дневная тарификация, SSH готов
Сингапур · Япония · Корея · Гонконг · регионы US
Разместите tools/call на изолированном облачном Mac; локальный Host только передаёт JSON-RPC. Смотреть тарифы ZekVPS Mac mini