diff --git a/README.md b/README.md index 4bd962d..bc85434 100644 --- a/README.md +++ b/README.md @@ -264,6 +264,9 @@ npx playwright test - [Веб-интерфейс](docs/ui.md) - [MCP-интерфейс](docs/mcp-interface.md) - [Admin API](docs/admin-api.md) +- [Практические API-примеры](docs/api-examples.md) +- [Production checklist](docs/production-checklist.md) +- [Troubleshooting](docs/troubleshooting.md) - [Настройки запуска](docs/runtime-config.md) - [Английский README](docs/en/README.md) diff --git a/docs/README.md b/docs/README.md index 35d0220..fe7db1c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -2,7 +2,7 @@ Crank превращает REST API endpoint-ы в MCP-инструменты, которые можно подключать к AI-агентам и MCP-клиентам. -Эта документация подготовлена как основа для будущего сайта. Сейчас файлы лежат в `docs/`, позже их можно перенести в Docusaurus без изменения структуры тем. +Документация хранится в Markdown-файлах внутри `docs/` и читается прямо из репозитория. ## Начать @@ -10,6 +10,7 @@ Crank превращает REST API endpoint-ы в MCP-инструменты, - [Установка](./installation.md) - [Первый инструмент](./quickstart.md) - [Подключение MCP-клиента](./mcp-interface.md) +- [Практические API-примеры](./api-examples.md) ## Возможности @@ -17,13 +18,15 @@ Crank превращает REST API endpoint-ы в MCP-инструменты, - [REST-инструменты](./protocols/rest.md) - [Секреты и профили авторизации](./secrets-and-auth.md) - [Журналы и использование](./observability.md) +- [Проектирование MCP-инструментов](./tool-design.md) ## Справочник - [Настройки окружения](./runtime-config.md) - [Admin API](./admin-api.md) - [Развертывание](./deployment.md) +- [Production checklist](./production-checklist.md) +- [Troubleshooting](./troubleshooting.md) - [Архитектура](./architecture.md) - [Модель данных](./data-model.md) - [Тестирование](./testing-strategy.md) - diff --git a/docs/admin-api.md b/docs/admin-api.md index 853c75e..be8fe57 100644 --- a/docs/admin-api.md +++ b/docs/admin-api.md @@ -1,6 +1,6 @@ # Admin API -Admin API используется UI для управления Crank Community. +Admin API используется веб-интерфейсом Crank. Его можно использовать и напрямую для автоматизации настройки. Base path: @@ -8,7 +8,33 @@ Base path: /api/admin ``` -## Auth +Auth path: + +```text +/api/auth +``` + +## Авторизация + +Администратор входит по email и паролю. После входа сервер устанавливает HttpOnly session cookie. + +```bash +curl -i https://crank.example.com/api/auth/login \ + -H 'Content-Type: application/json' \ + --data '{ + "email": "owner@example.com", + "password": "change-me" + }' +``` + +Дальше используйте cookie из ответа: + +```bash +curl https://crank.example.com/api/auth/session \ + -b 'crank_session=' +``` + +Endpoints: - `POST /api/auth/login` - `POST /api/auth/logout` @@ -17,30 +43,60 @@ Base path: - `PATCH /api/auth/profile` - `POST /api/auth/password` -Авторизация основана на email/password и HttpOnly session cookie. - ## Capabilities -- `GET /api/admin/capabilities` +```bash +curl https://crank.example.com/api/admin/capabilities \ + -b 'crank_session=' +``` Community capabilities: -- supported protocol: `rest` -- supported security level: `standard` -- machine access mode: static agent key +- protocol: `rest`; +- operation security level: `standard`; +- machine access: static agent API keys. ## Workspaces +Community работает с одним workspace. + - `GET /api/admin/workspaces` - `GET /api/admin/workspaces/{workspace_id}` - `PATCH /api/admin/workspaces/{workspace_id}` -Community работает с одним bootstrap workspace. API не поддерживает создание -дополнительных workspace-ов, переключение текущего workspace-а, приглашения -пользователей и управление ролями. +Пример: + +```bash +curl https://crank.example.com/api/admin/workspaces \ + -b 'crank_session=' +``` + +## Upstreams + +Upstream хранит базовый URL внешнего REST API и необязательные статические заголовки. + +- `GET /api/admin/workspaces/{workspace_id}/upstreams` +- `POST /api/admin/workspaces/{workspace_id}/upstreams` +- `PATCH /api/admin/workspaces/{workspace_id}/upstreams/{upstream_id}` + +Пример создания: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/upstreams \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "name": "Frankfurter", + "base_url": "https://api.frankfurter.dev", + "static_headers": {}, + "auth_profile_id": null + }' +``` ## Operations +Операция описывает один REST endpoint как MCP-инструмент. + - `GET /api/admin/workspaces/{workspace_id}/operations` - `POST /api/admin/workspaces/{workspace_id}/operations` - `POST /api/admin/workspaces/{workspace_id}/operations/analyze-quality` @@ -53,8 +109,33 @@ Community работает с одним bootstrap workspace. API не подд - `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/archive` - `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/test-runs` - `GET /api/admin/workspaces/{workspace_id}/operations/{operation_id}/export` +- `POST /api/admin/workspaces/{workspace_id}/operations/import` -`analyze-quality` принимает такой же draft payload, как создание операции, и возвращает отчет: +Пример тестового запуска: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/operations//test-runs \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "version": 1, + "input": { + "base": "USD", + "quote": "EUR" + } + }' +``` + +Пример публикации: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/operations//publish \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ "version": 1 }' +``` + +`analyze-quality` принимает payload операции и возвращает рекомендации: ```json { @@ -70,9 +151,6 @@ Community работает с одним bootstrap workspace. API не подд ] } ``` -- `POST /api/admin/workspaces/{workspace_id}/operations/import` - -Community принимает только `protocol = rest`. ## Samples @@ -80,6 +158,8 @@ Community принимает только `protocol = rest`. - `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/samples/output-json` - `POST /api/admin/workspaces/{workspace_id}/operations/{operation_id}/drafts/generate` +Samples используются для генерации схемы, стартового маппинга и сохранения тестовых примеров wizard-а. + ## Secrets - `GET /api/admin/workspaces/{workspace_id}/secrets` @@ -88,8 +168,20 @@ Community принимает только `protocol = rest`. - `POST /api/admin/workspaces/{workspace_id}/secrets/{secret_id}/rotate` - `DELETE /api/admin/workspaces/{workspace_id}/secrets/{secret_id}` -Create-response может вернуть plaintext secret только один раз. List/read endpoints -возвращают только metadata. +Пример создания token secret: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/secrets \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "name": "production-api-token", + "kind": "token", + "value": "secret-token-value" + }' +``` + +После создания или ротации API возвращает только metadata. Значение секрета нельзя прочитать повторно. ## Auth profiles @@ -99,7 +191,7 @@ Create-response может вернуть plaintext secret только один - `PATCH /api/admin/workspaces/{workspace_id}/auth-profiles/{auth_profile_id}` - `DELETE /api/admin/workspaces/{workspace_id}/auth-profiles/{auth_profile_id}` -Auth profile хранит ссылки на secrets и способ применения credential к REST request. +Auth profile хранит ссылки на secrets и способ применения секрета к REST-запросу. ## Agents @@ -116,6 +208,21 @@ Auth profile хранит ссылки на secrets и способ примен - `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings` - `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/bindings/{operation_id}` +Пример создания агента: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/agents \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "slug": "currency-rates", + "display_name": "Курсы валют", + "description": "Агент с инструментами для получения курсов валют.", + "instructions": {}, + "tool_selection_policy": {} + }' +``` + ## Agent API keys - `GET /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys` @@ -123,9 +230,42 @@ Auth profile хранит ссылки на secrets и способ примен - `POST /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys/{key_id}/revoke` - `DELETE /api/admin/workspaces/{workspace_id}/agents/{agent_id}/platform-api-keys/{key_id}` -Полное значение ключа доступно только в create-response. +Пример создания ключа: + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/agents//platform-api-keys \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "name": "Demo MCP client", + "scopes": ["read", "write"] + }' +``` + +Полное значение ключа доступно только в create response. ## Logs и usage - `GET /api/admin/workspaces/{workspace_id}/logs` - `GET /api/admin/workspaces/{workspace_id}/usage` + +Пример: + +```bash +curl 'https://crank.example.com/api/admin/workspaces/ws_default/logs?limit=20' \ + -b 'crank_session=' +``` + +## Ошибки + +Admin API возвращает JSON-ошибки с человекочитаемым сообщением и контекстом, если он доступен. + +Частые HTTP-коды: + +- `400` - неверный payload; +- `401` - нет сессии; +- `403` - действие запрещено; +- `404` - сущность не найдена; +- `409` - конфликт состояния; +- `429` - rate limit; +- `500` - внутренняя ошибка. diff --git a/docs/api-examples.md b/docs/api-examples.md new file mode 100644 index 0000000..4687f6f --- /dev/null +++ b/docs/api-examples.md @@ -0,0 +1,139 @@ +# Практические API-примеры + +Здесь собраны минимальные запросы для проверки Crank без веб-интерфейса. + +В примерах используется: + +```text +https://crank.example.com +``` + +Замените адрес на свой. + +## Вход + +```bash +curl -i https://crank.example.com/api/auth/login \ + -H 'Content-Type: application/json' \ + --data '{ + "email": "owner@example.com", + "password": "change-me" + }' +``` + +Сохраните cookie `crank_session`. + +## Получить workspace + +```bash +curl https://crank.example.com/api/admin/workspaces \ + -b 'crank_session=' +``` + +Для стандартной установки workspace id: + +```text +ws_default +``` + +## Получить операции + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/operations \ + -b 'crank_session=' +``` + +После demo seed ожидается операция: + +```text +frankfurter_latest_rate +``` + +## Запустить тест операции + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/operations//test-runs \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "version": 1, + "input": { + "base": "USD", + "quote": "EUR" + } + }' +``` + +## Получить агентов + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/agents \ + -b 'crank_session=' +``` + +После demo seed ожидается агент: + +```text +currency-rates +``` + +## Создать API-ключ агента + +```bash +curl https://crank.example.com/api/admin/workspaces/ws_default/agents//platform-api-keys \ + -b 'crank_session=' \ + -H 'Content-Type: application/json' \ + --data '{ + "name": "Manual MCP test", + "scopes": ["read", "write"] + }' +``` + +Сохраните поле `secret`. Оно не будет показано повторно. + +## Проверить MCP 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` из заголовков ответа. + +## Вызвать инструмент + +```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/call", + "params": { + "name": "frankfurter_latest_rate", + "arguments": { + "base": "USD", + "quote": "EUR" + } + } + }' +``` + diff --git a/docs/en/README.md b/docs/en/README.md index c9de059..caa7f21 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -1,52 +1,44 @@ # Crank -Crank Community is a self-hosted platform for publishing REST APIs as MCP tools. +Crank is a self-hosted platform for turning REST API endpoints into MCP tools. -It lets operators describe an upstream REST endpoint, test it, publish it, and -expose it to LLM clients through MCP without writing a custom MCP server for -each integration. +The product provides a web UI for describing an upstream REST endpoint, testing it, publishing it as a tool, and exposing it to MCP clients through an agent-scoped endpoint. -## Features +## What Crank Does -- REST operation creation from the web UI or YAML. -- MCP input mapping into REST query, body, and header fields. -- REST response mapping into structured MCP tool output. -- Agent-scoped MCP endpoints with curated tool catalogs. -- Operation drafts, versions, samples, mappings, logs, and usage in PostgreSQL. -- Simple admin authentication with a bootstrap admin user. -- PostgreSQL-backed secrets and auth profiles for upstream REST APIs. -- Docker Compose deployment. +- Creates REST tools from the web UI or YAML. +- Maps MCP input into REST path, query, headers, or JSON body. +- Maps REST responses into structured tool output. +- Publishes selected tools through a specific agent. +- Issues static API keys for MCP clients. +- Stores operations, versions, samples, secrets, logs, and usage in PostgreSQL. +- Runs with Docker Compose. ## Community Scope -This repository contains only the Community feature set: +This repository contains the Community version: -- REST protocol only. -- Single self-hosted deployment. -- Simple admin authentication. -- Static agent API keys for MCP access. -- PostgreSQL as the system database. -- Optional Valkey/Redis cache for runtime coordination. -- Gitea Actions CI/CD. +- one workspace; +- one admin user; +- unlimited agents; +- REST protocol; +- MCP Streamable HTTP; +- static agent API keys; +- PostgreSQL database; +- optional Valkey or Redis for temporary coordination state. -The repository is focused only on the scope listed above. +## Documentation -## Architecture +The main documentation is currently maintained in Russian: -Core concepts: - -- `Workspace` is the data boundary for operations, agents, secrets, and logs. -- `Operation` is a versioned REST integration contract. -- `Agent` is an MCP surface that exposes a curated set of operations. - -Runtime flow: - -1. An operator creates or imports a REST operation. -2. Crank validates the schema and mapping. -3. The operator runs a test call against the upstream REST API. -4. The operation is published. -5. An agent exposes the published operation as an MCP tool. -6. MCP clients call the tool through `mcp-server`. +- [Documentation index](../README.md) +- [Introduction](../intro.md) +- [Installation](../installation.md) +- [Quickstart](../quickstart.md) +- [MCP interface](../mcp-interface.md) +- [Admin API](../admin-api.md) +- [Runtime configuration](../runtime-config.md) +- [Troubleshooting](../troubleshooting.md) ## License diff --git a/docs/installation.md b/docs/installation.md index 9078364..72e9baf 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -75,3 +75,6 @@ docker compose pull docker compose up -d ``` +## Следующий шаг + +После установки пройдите [первый инструмент](./quickstart.md). Если что-то не запускается, используйте [troubleshooting](./troubleshooting.md). diff --git a/docs/mcp-interface.md b/docs/mcp-interface.md index 57230ab..964d74e 100644 --- a/docs/mcp-interface.md +++ b/docs/mcp-interface.md @@ -1,106 +1,177 @@ -# MCP Interface +# MCP-интерфейс -Crank Community публикует REST operations как MCP tools поверх Streamable HTTP. +Crank публикует REST-операции как MCP-инструменты через Streamable HTTP. -## Transport +## Endpoint агента -MCP server запускается отдельным приложением `mcp-server`. - -Поддерживается: - -- MCP Streamable HTTP; -- JSON-RPC requests через `POST`; -- optional server-to-client stream через `GET`; -- explicit session close через `DELETE`. - -`stdio` не входит в Community deployment. - -## Endpoint model - -Canonical endpoint: +Каждый агент имеет собственный MCP endpoint: ```text /mcp/v1/{workspace_slug}/{agent_slug} ``` -Endpoint определяет: +Для demo seed: -- workspace; -- published agent; -- curated tool catalog агента; -- labels для logs и usage. +```text +/mcp/v1/default/currency-rates +``` -## Authentication +Полный URL зависит от вашего домена: -Community использует static agent API keys. +```text +https://crank.example.com/mcp/v1/default/currency-rates +``` -Правила: +## Авторизация -- каждый published agent может иметь собственные API keys; -- key принадлежит одному workspace и одному agent; -- `mcp-server` показывает только tools, привязанные к этому agent; -- unsupported token issuance modes отклоняются. +MCP-клиент должен передавать API-ключ агента: -## Tool catalog +```http +Authorization: Bearer +``` -Одна published REST operation становится одним MCP tool. +Ключ выдается в разделе **API ключи**. Полное значение показывается только один раз при создании. -Tool definition строится из: - -- operation name или binding-level tool name; -- tool title и description; -- input schema; -- published operation version. - -Draft operations никогда не публикуются через MCP. - -## Supported methods +## Поддерживаемые методы MCP methods: -- `initialize` -- `notifications/initialized` -- `ping` -- `tools/list` -- `tools/call` +- `initialize`; +- `notifications/initialized`; +- `ping`; +- `tools/list`; +- `tools/call`. -Transport endpoints: +HTTP transport: -- `POST /mcp/v1/{workspace_slug}/{agent_slug}` -- `GET /mcp/v1/{workspace_slug}/{agent_slug}` -- `DELETE /mcp/v1/{workspace_slug}/{agent_slug}` +- `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}` - закрытие сессии. -## `tools/list` +## Обязательные заголовки -1. Client authenticates через agent API key. -2. `mcp-server` resolves workspace и agent из path. -3. Server loads published agent catalog. -4. Server returns only tools bound to that agent. +Для `POST`: -## `tools/call` +```http +Authorization: Bearer +Content-Type: application/json +Accept: application/json, text/event-stream +``` -1. Client вызывает tool. -2. `mcp-server` валидирует input по tool schema. -3. Runtime maps MCP input в REST request. -4. REST adapter вызывает upstream API. -5. Runtime maps REST response в tool output. -6. `mcp-server` возвращает normalized result. +Для `GET`: -## Refresh +```http +Authorization: Bearer +Accept: text/event-stream +MCP-Session-Id: +``` -Published catalog refresh управляется `CRANK_MCP_REFRESH_MS`. +После `initialize` сервер возвращает заголовок: -После публикации operation или agent `mcp-server` подхватывает новый catalog без -restart. +```http +MCP-Session-Id: +``` -## Error categories +Если клиент передает `MCP-Protocol-Version`, он должен совпадать с версией, согласованной при инициализации. -MCP responses различают: +## Пример `initialize` -- authentication errors; -- missing workspace или agent; -- missing tool; -- schema validation errors; -- mapping errors; -- upstream REST errors; -- internal runtime errors. +```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 +``` + +## Как формируется каталог инструментов + +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`. diff --git a/docs/production-checklist.md b/docs/production-checklist.md new file mode 100644 index 0000000..f55d6e7 --- /dev/null +++ b/docs/production-checklist.md @@ -0,0 +1,45 @@ +# Production checklist + +Этот список помогает подготовить Crank к постоянной работе на сервере. + +## Перед запуском + +- Сгенерирован сильный `CRANK_MASTER_KEY`. +- Сгенерирован сильный `CRANK_SESSION_SECRET`. +- Сгенерирован сильный `CRANK_PASSWORD_PEPPER`. +- Задан надежный `CRANK_BOOTSTRAP_ADMIN_PASSWORD`. +- `CRANK_BASE_URL` указывает на публичный HTTPS URL. +- PostgreSQL доступен с host, где запускаются контейнеры. +- Для PostgreSQL настроены бэкапы. +- Reverse proxy проксирует `/`, `/api/admin/` и `/mcp/`. +- Для `/mcp/` отключено proxy buffering. +- Порты опубликованы только там, где нужно: `127.0.0.1` или `0.0.0.0`. + +## После запуска + +- `curl /health` для `admin-api` возвращает `ok`. +- `curl /health` для `mcp-server` возвращает `ok`. +- UI открывается по публичному домену. +- Вход под bootstrap admin работает. +- Demo seed создал Frankfurter-пример, если `CRANK_DEMO_SEED=true`. +- Тест операции `frankfurter_latest_rate` проходит. +- MCP-клиент видит инструмент через агента `currency-rates`. + +## Безопасность + +- Не храните `.env` в Git. +- Не передавайте API-ключи агентов в чатах и тикетах. +- Выдавайте отдельный ключ на каждого MCP-клиента. +- Удаляйте или отзывайте ключи, которые больше не используются. +- Используйте secrets/auth profiles для токенов внешних API. +- Не вставляйте реальные токены в статические заголовки операции. + +## Эксплуатация + +- Включите мониторинг контейнеров. +- Следите за свободным местом на диске. +- Проверяйте размер PostgreSQL и директории artifact storage. +- Храните бэкапы PostgreSQL отдельно от application host. +- Перед обновлением фиксируйте текущие image tags. +- После обновления проверяйте UI, Admin API и MCP endpoint. + diff --git a/docs/quickstart.md b/docs/quickstart.md index 82d5e7d..9e0dd16 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -79,3 +79,4 @@ https://your-crank-host/mcp/v1/default/currency-rates Клиент должен передавать API-ключ агента в заголовке авторизации. +Подробные HTTP-примеры для `initialize`, `tools/list` и `tools/call` находятся в [MCP-интерфейсе](./mcp-interface.md) и [практических API-примерах](./api-examples.md). diff --git a/docs/testing-strategy.md b/docs/testing-strategy.md index 2230659..dfb85d2 100644 --- a/docs/testing-strategy.md +++ b/docs/testing-strategy.md @@ -9,7 +9,7 @@ - проверять доменную модель отдельно от транспорта; - ловить регрессии в mapping; - не дать адаптерам начать вести себя по-разному; -- обеспечить воспроизводимость для дипломной демонстрации. +- обеспечить воспроизводимость для демонстрации и регрессионных проверок. ## 2. Уровни тестов @@ -101,7 +101,7 @@ - unit tests для form helpers и schema rendering; - integration tests для critical user flows; - отдельная проверка mapping editor и sample upload flows. -- отдельный regression checklist для post-integration smoke pass: [manual-regression-checklist.md](/home/a.tolmachev/code/rust/mcpaas/docs/manual-regression-checklist.md). +- отдельный regression checklist для post-integration smoke pass: [manual-regression-checklist.md](manual-regression-checklist.md). ## 6. Что нельзя оставлять без тестов diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 0000000..cab8a76 --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,148 @@ +# Troubleshooting + +Этот документ помогает быстро проверить типовые проблемы при запуске и работе Crank. + +## Веб-интерфейс открывается, но данные не загружаются + +Проверьте `admin-api`: + +```bash +curl http://127.0.0.1:3001/health +docker compose logs -f admin-api +``` + +Типовые причины: + +- `admin-api` не подключился к PostgreSQL; +- неверные `POSTGRES_HOST`, `POSTGRES_PORT`, `POSTGRES_USER`, `POSTGRES_PASSWORD`; +- reverse proxy не проксирует `/api/admin/`; +- браузерная сессия истекла. + +## `502 Bad Gateway` через nginx + +Проверьте, на каком адресе опубликованы контейнеры: + +```bash +docker compose ps +``` + +Если nginx работает на другом host, в `.env` нужно: + +```env +CRANK_PUBLISH_BIND=0.0.0.0 +``` + +Если nginx работает на том же host, обычно достаточно: + +```env +CRANK_PUBLISH_BIND=127.0.0.1 +``` + +## MCP-клиент получает `401 Unauthorized` + +Проверьте: + +- API-ключ создан именно для нужного агента; +- ключ передается как `Authorization: Bearer `; +- ключ не был удален или отозван; +- MCP URL содержит правильные `workspace_slug` и `agent_slug`. + +## MCP-клиент не видит инструмент + +Проверьте: + +- операция опубликована; +- операция привязана к агенту; +- агент опубликован; +- ключ выдан на этого агента; +- прошел интервал `CRANK_MCP_REFRESH_MS`. + +Для demo seed ожидаемый инструмент: + +```text +frankfurter_latest_rate +``` + +## Тест операции возвращает ошибку внешнего API + +Откройте preview запроса в wizard-е и проверьте: + +- `base_url`; +- `path_template`; +- HTTP method; +- query/path/body mapping; +- auth profile; +- статические заголовки. + +Для Frankfurter рабочий запрос: + +```text +GET https://api.frankfurter.dev/v1/latest?base=USD&symbols=EUR +``` + +## Секрет не виден после создания + +Это ожидаемое поведение. Crank шифрует секрет и больше не возвращает его значение через UI или API. + +Если значение нужно заменить, используйте **Ротировать**. + +## После обновления не появился demo-пример + +Проверьте: + +```env +CRANK_DEMO_SEED=true +``` + +Затем перезапустите `admin-api`: + +```bash +docker compose up -d admin-api +``` + +Seed идемпотентный: он не создает дубликаты, но поддерживает Frankfurter-пример. + +## Контейнеры не стартуют из-за занятых портов + +Проверьте, кто занимает порт: + +```bash +docker ps --format 'table {{.Names}}\t{{.Ports}}' +sudo ss -ltnp +``` + +Чаще всего конфликтуют: + +- `3000` - UI; +- `3001` - Admin API; +- `3002` - MCP server; +- `5432` - PostgreSQL, если включен profile `local-db`. + +## PostgreSQL недоступен + +Проверьте доступность из контейнера: + +```bash +docker compose exec admin-api sh -lc 'nc -vz "$POSTGRES_HOST" "$POSTGRES_PORT"' +``` + +Проверьте переменные: + +```bash +docker compose exec admin-api env | grep POSTGRES +``` + +## Где смотреть логи + +```bash +docker compose logs -f admin-api +docker compose logs -f mcp-server +docker compose logs -f ui +``` + +Для подробных логов временно укажите: + +```env +CRANK_LOG_LEVEL=debug +``` +