feat: complete Epic 1 production foundation
This commit is contained in:
+43
-3
@@ -34,6 +34,13 @@ Authorization: Bearer <agent_api_key>
|
||||
|
||||
Для операций с подтверждением человеком нужен отдельный ключ подтверждения. Его тоже выдают в разделе **API ключи**, но в режиме **Подтверждения**. Такой ключ нельзя передавать LLM или MCP-клиенту. Он нужен только вашему внешнему интерфейсу, где пользователь нажимает «Подтвердить» или «Отклонить».
|
||||
|
||||
Ключи разных типов не взаимозаменяемы: `mcp_client` не принимается на approval
|
||||
endpoints, а `approval` не принимается для `initialize`, `tools/list` и
|
||||
`tools/call`. Revocation проверяется через PostgreSQL source of truth и начинает
|
||||
действовать без restart, включая уже существующие MCP session. Для approval keys
|
||||
может быть задан список `allowed_origins`; если HTTP `Origin` присутствует и не
|
||||
совпадает с разрешённым origin, запрос отклоняется до выполнения side effect.
|
||||
|
||||
## Поддерживаемые методы
|
||||
|
||||
MCP methods:
|
||||
@@ -76,6 +83,21 @@ MCP-Session-Id: <session_id>
|
||||
|
||||
Если клиент передает `MCP-Protocol-Version`, он должен совпадать с версией, согласованной при инициализации.
|
||||
|
||||
## Авторитетное evidence первого вызова
|
||||
|
||||
Getting Started засчитывает первый вызов только после полной публичной
|
||||
последовательности `initialize` → `notifications/initialized` → `tools/list` →
|
||||
успешный `tools/call` с тем же активным `mcp_client` key. Одного discovery,
|
||||
failed call, success через другой key или external verifier credential
|
||||
недостаточно. Invocation History сохраняет exact key ID вместе с Agent,
|
||||
immutable Operation Version, tool, UTC timestamp, Request ID и Trace ID.
|
||||
|
||||
Admin UI может безопасно сослаться на соответствующую history row и correlation
|
||||
IDs, но не показывает input arguments, payload, bearer value или upstream body.
|
||||
Если key отозван/deleted, Agent/Operation archive либо binding/revision больше
|
||||
не подтверждаются authoritative source of truth, onboarding возвращается в
|
||||
actionable state; старый raw key не восстанавливается.
|
||||
|
||||
## Пример `initialize`
|
||||
|
||||
```bash
|
||||
@@ -131,7 +153,9 @@ call_tool
|
||||
|
||||
`search_tools` принимает текст задачи, необязательные идентификаторы разделов и предел результатов. Ответ содержит полные входные схемы найденных инструментов и `catalog_revision`.
|
||||
|
||||
`call_tool` принимает имя найденного инструмента, его аргументы и полученную `catalog_revision`. Если за время между поиском и вызовом опубликована новая версия агента, вызов отклоняется с кодом `catalog_revision_changed`: клиент должен повторить поиск.
|
||||
`call_tool` принимает имя найденного инструмента, его аргументы и полученную `catalog_revision`. Если за время между поиском и вызовом опубликована новая версия агента, вызов отклоняется с кодом `agent_catalog_result_stale`: клиент должен повторить поиск.
|
||||
|
||||
`catalog_revision` берётся из immutable Published Agent catalog. Он не является user-controlled label и не заменяет Request/Trace ID; это bounded revision token для защиты пары `search_tools → call_tool` от stale results.
|
||||
|
||||
## Пример `tools/call`
|
||||
|
||||
@@ -161,6 +185,12 @@ Crank выполнит REST-запрос:
|
||||
GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR
|
||||
```
|
||||
|
||||
Ошибка `tools/call` сохраняет существующие JSON-RPC/`isError` semantics и
|
||||
добавляет в structured content поля `error_code`, `stage`, `retryability`,
|
||||
`outcome_certainty`, `request_id` и `trace_id`. Значение `manual_reconcile` вместе
|
||||
с `outcome_unknown` означает, что автоматический повтор небезопасен. Raw upstream
|
||||
body, URL, headers и внутренний текст ошибки не возвращаются.
|
||||
|
||||
## Операции с подтверждением человеком
|
||||
|
||||
Если в мастере операции включено **Подтверждение человеком**, первый `tools/call` не выполняет REST-запрос сразу. Вместо этого Crank создает ожидающий запрос на подтверждение и возвращает MCP-клиенту структурированный результат:
|
||||
@@ -185,6 +215,14 @@ GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR
|
||||
|
||||
`approval_url` в ответе является путем на MCP-сервере. Если вы публикуете MCP через префикс `/mcp`, внешний URL будет начинаться с `/mcp/v1/...`.
|
||||
|
||||
Approval identity считается по полному scope: workspace, Agent, immutable
|
||||
Operation Version и canonical JSON аргументы. Служебные поля Crank, например
|
||||
`_crank_confirmation_token`, не входят в fingerprint и не создают дубликаты.
|
||||
Активный pending request с тем же scope возвращается повторно. В metadata и
|
||||
`payload_preview` хранится только bounded safe summary: secret-like поля
|
||||
редактируются, raw approval key/auth headers/control tokens не сохраняются и не
|
||||
отдаются клиенту.
|
||||
|
||||
Внешний интерфейс подтверждения работает отдельным ключом подтверждения:
|
||||
|
||||
```bash
|
||||
@@ -217,8 +255,10 @@ curl https://crank.example.com/mcp/v1/default/sales/approvals/<approval_id>/appr
|
||||
идемпотентности: универсальный HTTP-клиент не может гарантировать ровно одно внешнее
|
||||
побочное действие при падении процесса между ответом upstream и записью результата.
|
||||
|
||||
Повторный `tools/call` с теми же агентом, операцией, версией и JSON-аргументами
|
||||
возвращает уже существующую активную заявку вместо создания дубликата.
|
||||
Повторный `tools/call` с теми же агентом, операцией, версией и canonical
|
||||
JSON-аргументами возвращает уже существующую активную заявку вместо создания
|
||||
дубликата. Повторный approve/deny terminal заявки возвращает текущий status и не
|
||||
запускает второй side effect.
|
||||
|
||||
Отклонение:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user