Ваш REST API не умеет разговаривать с ИИ — и это нормально
Скажите честно: у вас есть legacy REST-сервис, который работает как часы, но абсолютно нем перед лицом AI-агентов? Знакомо. Enterprise живёт на старых эндпоинтах, а новые модные протоколы — A2A (Agent-to-Agent) от Google и MCP (Model Context Protocol) от Anthropic — требуют другого языка. Переписывать монолит? Нет, спасибо. Ретрофит — вот что реально спасает.
В середине 2026 года AWS опубликовала практическое руководство с архитектурой и кодом для превращения классических REST-сервисов в A2A-совместимых агентов. Идея простая: не трогать исходный код, а надеть поверх него тонкий слой-переходник. Звучит как магия? На деле — это всего лишь правильный gateway и немного конфигов.
Почему нельзя просто взять и позвать REST из агента?
Технически — можно. Но тогда каждый агент должен знать все эндпоинты, форматы данных, схемы авторизации. В мире, где агентов сотни, это превращается в ад. MCP и A2A предлагают единый контракт: MCP — для подключения инструментов к LLM, A2A — для общения между агентами. Ваш старый REST просто не умеет ни того, ни другого.
Ретрофит — это прослойка, которая принимает MCP/A2A запросы, транслирует их в REST-вызовы вашего legacy-сервиса и возвращает ответ в понятном агенту формате. Ни строчки в старом коде.
Кстати, если вы ещё не знакомы с MCP, советую прочитать обзор протокола — там всё разложено по полочкам.
Архитектура ретрофита: надеваем оверлей
Представьте себе обратный прокси, но с AI-акцентом. Компоненты:
- MCP Gateway — принимает запросы от LLM по MCP-протоколу, вызывает REST API и возвращает результат.
- A2A Adapter — позволяет вашему сервису выступать в роли агента для других агентов (регистрирует agent card, обрабатывает задачи).
- OpenAPI-Parser — динамически генерирует описание инструментов MCP из вашей OpenAPI-спеки.
- Auth Proxy — пробрасывает аутентификацию (если нужно per-user OAuth — держите референсную архитектуру).
Вот как выглядит типичный flow:
- Агент (через MCP) запрашивает инструмент «getOrderStatus».
- MCP Gateway смотрит в кэшированный OpenAPI, маппит на GET /v2/orders/{id} вашего legacy.
- Gateway делает HTTP-запрос с нужными заголовками (Authorisation может быть переписана).
- Ответ (JSON) оборачивается в MCP-фрейм и возвращается агенту.
Для A2A всё чуть сложнее: нужно объявить agent card — что ваш сервис умеет делать как агент. Но каркас тот же.
Шаг 1. Инвентаризация: что вы вообще выставляете?
Не надо вываливать все 500 эндпоинтов агенту. Во-первых, LLM запутается. Во-вторых, безопасность. Выберите 5-10 ключевых операций, которые реально нужны AI: проверка статуса заказа, создание тикета, получение данных клиента. Всё остальное — позже.
Заведите OpenAPI 3.0 спецификацию (если нет — напишите, это час работы). Именно она станет источником правды для генерации MCP tools. Подробнее про то, как превратить OpenAPI в MCP-сервер, мы уже писали в гайде MCP-сервер из Spring-сервиса за вечер.
Шаг 2. Генерация MCP tool definitions
Берём OpenAPI и конвертируем каждую операцию в MCP tool. Формат — JSON Schema для parameters и возвращаемого значения. Можно написать скрипт на Python или использовать готовые утилиты (например, openai-to-mcp или кастомный парсер).
import json
from openapi_parser import parse
spec = parse('openapi.yaml')
tools = []
for path, methods in spec.paths.items():
for method, operation in methods.items():
tool = {
"name": operation.operation_id or f"{method}_{path.replace('/', '_')}",
"description": operation.description or "",
"inputSchema": {
"type": "object",
"properties": {}
}
}
# ... заполняем параметры из OpenAPI
tools.append(tool)
print(json.dumps(tools, indent=2))Этот список передаётся в MCP-сервер при старте. Теперь любой LLM-клиент видит ваш REST как набор готовых функций. Осталось написать сам сервер.
Шаг 3. Собираем MCP-сервер (с кодом)
Берём любой фреймворк — Python (FastMCP), TypeScript (ModelContextProtocol/sdk), Go. Я покажу на Python — он лаконичен.
from mcp import Server, Tool
import httpx
server = Server("legacy-gateway")
@server.list_tools()
async def list_tools():
return [
Tool(
name="get_order",
description="Получить заказ по ID",
inputSchema={"type":"object","properties":{"order_id":{"type":"string"}}}
)
]
@server.call_tool()
async def call_tool(name: str, arguments: dict):
if name == "get_order":
async with httpx.AsyncClient() as client:
resp = await client.get(f"https://legacy.example.com/orders/{arguments['order_id']}")
return {"content": resp.json()}
raise ValueError(f"Tool {name} not found")
server.run(transport="stdio")Важно: В production не используйте stdio. Ставьте SSE или WebSocket. И обязательно добавьте timeout и retry — legacy API может тормозить.
Хотите тестировать такие серверы без головной боли? Попробуйте MCP Chat Studio v2 — это как Postman для MCP, только умнее.
Шаг 4. Добавляем A2A: делаем ваш сервис агентом
A2A требует, чтобы ваш сервис умел принимать задачи (task) и отдавать результат. Здесь уже не просто tool call, а полноценный lifecycle: submitted -> working -> completed. AWS в своём руководстве предлагает использовать агентный gateway, который оборачивает REST в A2A task API.
Кратко:
- Регистрируете Agent Card (JSON, описывающий возможности).
- Реализуете эндпоинты
/a2a/task/sendи/a2a/task/result. - Внутри gateway преобразует их в вызовы вашего REST.
Типичный Agent Card:
{
"name": "Legacy Order Agent",
"description": "Работает с заказами из старой системы",
"url": "https://a2a-gateway.example.com/a2a",
"capabilities": {
"transports": ["https"],
"skills": ["orders.read", "orders.write"]
}
}Когда другой агент найдёт этот card в реестре (например, MCP Tool Registry), он сможет с ним взаимодействовать. Никакого переписывания legacy.
Подводные камни: что может пойти не так
Ретрофит — не серебряная пуля. Вот три типовые грабли, на которые я наступал лично:
1. Авторизация — боль
Ваш REST использует Basic Auth или JWT для конкретного пользователя. А MCP/A2A запрос приходит от агента, который не знает контекста. Решение — Auth Proxy, который подменяет токены. В статье про per-user OAuth с Keycloak как раз такой кейс разобран.
2. Скорость
MCP-сервер может вызывать legacy API синхронно. Если ваш REST отвечает за 5 секунд — агент будет ждать. LLM-клиенты часто ставят таймаут 10-15 секунд. Решение: асинхронные паттерны (A2A task), кэширование (если данные не критичные).
3. Ошибки и нестабильность
Legacy может вернуть 500, а агент не поймёт. Нормальная практика — оборачивать ошибки в MCP error content с читаемым текстом. И обязательно логируйте все вызовы — потом будете разбираться, почему агент накупил 100 билетов.
Enterprise-кейс: как это работает на реальных проектах
Платформа MWS Octapi, о которой мы писали в обзоре low-code интеграций, сделала ровно это: натянула MCP поверх десятка legacy-сервисов за месяц. Их секрет — не пытаться покрыть всё сразу, а идти по одному инструменту за раз, начиная с read-only операций.
Кстати, если вы используете Claude Code для автоматизации разработки, вот полное руководство — там тоже есть раздел про подключение кастомных MCP-инструментов.
Инструменты, которые упрощают жизнь
К моменту середины 2026 года экосистема созрела. Вот что реально стоит попробовать:
- MCP Chat Studio — дебаг MCP-серверов, AI-воркфлоу, экспорт в Python.
- MCP Tool Registry — автоматическая регистрация и поиск инструментов (идеально для RAG-систем).
- Self-hosted MCP server — если конфиденциальность важна (пример с финансовыми данными здесь).
- Code-memory MCP-сервер — помогает LLM понимать код вашего legacy, если нужно генерировать адаптеры автоматически (читайте обзор).
Совет, который вы не услышите на конференциях
Не пытайтесь сделать ретрофит идеальным с первого раза. Начните с одного read-only инструмента. Пусть агенты сначала научатся получать данные, а писать — позже. И обязательно протестируйте на реальных агентах, а не только в изоляции. MCP-сервер может работать идеально, но A2A-оркестратор — завалиться из-за формата даты.
И помните: ретрофит — это не навсегда. Вы просто выигрываете время, пока legacy не умрёт естественной смертью. Но к тому моменту ваши AI-агенты уже будут приносить бизнесу деньги.