# MCP-интерфейс Crank публикует REST-операции как MCP-инструменты через Streamable HTTP. ## Endpoint агента Каждый агент имеет собственный MCP endpoint: ```text /mcp/v1/{workspace_slug}/{agent_slug} ``` Для demo seed: ```text /mcp/v1/default/currency-rates ``` Полный URL зависит от вашего домена: ```text https://crank.example.com/mcp/v1/default/currency-rates ``` ## Авторизация MCP-клиент должен передавать API-ключ агента: ```http Authorization: Bearer ``` Ключ выдается в разделе **API ключи**. Полное значение показывается только один раз при создании. Для операций с подтверждением человеком нужен отдельный ключ подтверждения. Его тоже выдают в разделе **API ключи**, но в режиме **Подтверждения**. Такой ключ нельзя передавать LLM или MCP-клиенту. Он нужен только вашему внешнему интерфейсу, где пользователь нажимает «Подтвердить» или «Отклонить». ## Поддерживаемые методы MCP methods: - `initialize`; - `notifications/initialized`; - `ping`; - `tools/list`; - `tools/call`. HTTP transport: - `POST /mcp/v1/{workspace_slug}/{agent_slug}` - JSON-RPC запросы; - `GET /mcp/v1/{workspace_slug}/{agent_slug}` - server-to-client stream; - `DELETE /mcp/v1/{workspace_slug}/{agent_slug}` - закрытие сессии. ## Обязательные заголовки Для `POST`: ```http Authorization: Bearer Content-Type: application/json Accept: application/json, text/event-stream ``` Для `GET`: ```http Authorization: Bearer Accept: text/event-stream MCP-Session-Id: ``` После `initialize` сервер возвращает заголовок: ```http MCP-Session-Id: ``` Если клиент передает `MCP-Protocol-Version`, он должен совпадать с версией, согласованной при инициализации. ## Пример `initialize` ```bash curl -i https://crank.example.com/mcp/v1/default/currency-rates \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json, text/event-stream' \ --data '{ "jsonrpc": "2.0", "id": 1, "method": "initialize", "params": { "protocolVersion": "2025-06-18", "capabilities": {}, "clientInfo": { "name": "curl", "version": "1.0.0" } } }' ``` Сохраните `MCP-Session-Id` из ответа. ## Пример `tools/list` ```bash curl https://crank.example.com/mcp/v1/default/currency-rates \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'MCP-Session-Id: ' \ --data '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list", "params": {} }' ``` Ожидаемый результат для demo seed содержит инструмент: ```text frankfurter_latest_rate ``` ## Пример `tools/call` ```bash curl https://crank.example.com/mcp/v1/default/currency-rates \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -H 'Accept: application/json' \ -H 'MCP-Session-Id: ' \ --data '{ "jsonrpc": "2.0", "id": 3, "method": "tools/call", "params": { "name": "frankfurter_latest_rate", "arguments": { "base": "USD", "quote": "EUR" } } }' ``` Crank выполнит REST-запрос: ```text GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR ``` ## Операции с подтверждением человеком Если в мастере операции включено **Подтверждение человеком**, первый `tools/call` не выполняет REST-запрос сразу. Вместо этого Crank создает ожидающий запрос на подтверждение и возвращает MCP-клиенту структурированный результат: ```json { "status": "approval_required", "approval_id": "approval_...", "approval_url": "/v1/default/sales/approvals/approval_...", "approve": { "method": "POST", "url": "/v1/default/sales/approvals/approval_.../approve", "body": { "approve": "yes" } }, "deny": { "method": "POST", "url": "/v1/default/sales/approvals/approval_.../deny", "body": { "approve": "no" } } } ``` `approval_url` в ответе является путем на MCP-сервере. Если вы публикуете MCP через префикс `/mcp`, внешний URL будет начинаться с `/mcp/v1/...`. Внешний интерфейс подтверждения работает отдельным ключом подтверждения: ```bash curl https://crank.example.com/mcp/v1/default/sales/approvals \ -H 'Authorization: Bearer ' ``` Статус конкретного запроса: ```bash curl https://crank.example.com/mcp/v1/default/sales/approvals/ \ -H 'Authorization: Bearer ' ``` Подтверждение: ```bash curl https://crank.example.com/mcp/v1/default/sales/approvals//approve \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ --data '{ "approve": "yes", "note": "Пользователь подтвердил действие" }' ``` После подтверждения Crank выполняет исходный REST-запрос с тем payload, который был сохранен при первом `tools/call`. Если запрос прошел успешно, заявка получает статус `completed`, а результат сохраняется в `response_payload`. Если upstream вернул ошибку, заявка получает статус `failed`, а в `response_payload` сохраняется код и текст ошибки. Перед обращением к upstream заявка атомарно переходит в статус `executing`. Если `mcp-server` завершился во время выполнения, другой рабочий цикл повторно захватит заявку после истечения аренды. Для изменяющих операций рекомендуется настроить `execution_config.idempotency` и передавать поддерживаемый upstream заголовок идемпотентности: универсальный HTTP-клиент не может гарантировать ровно одно внешнее побочное действие при падении процесса между ответом upstream и записью результата. Повторный `tools/call` с теми же агентом, операцией, версией и JSON-аргументами возвращает уже существующую активную заявку вместо создания дубликата. Отклонение: ```bash curl https://crank.example.com/mcp/v1/default/sales/approvals//deny \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ --data '{ "approve": "no", "note": "Пользователь отклонил действие" }' ``` Ключ MCP-клиента не подходит для этих endpoints. Ключ подтверждения, наоборот, не подходит для `initialize`, `tools/list` и `tools/call`. Текущая реализация возвращает `approval_required` сразу и не держит исходный `tools/call` открытым до решения пользователя. Поэтому внешний интерфейс может восстановить результат через `GET /approvals/`. Долгое ожидание через Streamable HTTP/SSE запланировано отдельно. ## Как формируется каталог инструментов MCP-клиент видит только опубликованные операции, которые привязаны к опубликованному агенту. Черновики операций не попадают в MCP-каталог. Если два пользователя работают в одном workspace, один может редактировать черновик, а второй публиковать агента. В опубликованный каталог попадут только опубликованные версии операций. ## Обновление каталога `mcp-server` периодически обновляет опубликованный каталог. Интервал задается: ```env CRANK_MCP_REFRESH_MS=5000 ``` После публикации операции или агента подождите один интервал обновления или перезапустите `mcp-server`. ## Ошибки Частые причины ошибок: - `401 Unauthorized` - отсутствует или неверен API-ключ агента. - `403 Forbidden` - ключ не имеет нужного доступа. - `404 Not Found` - workspace, агент или инструмент не опубликованы. - `400 Bad Request` - неверный MCP-заголовок, session id или JSON-RPC payload. - `429 Too Many Requests` - сработал rate limit. Runtime-ошибки инструмента возвращаются как структурированный MCP tool error с кодом, сообщением и `request_id`.