MCP: как агент работает с Gigma ERP
MCP в Gigma — это внешний слой tools над обычным ERP API. В Laravel backend нет отдельного маршрута /api/mcp/* и нет отдельного MCP-контроллера.
После получения Agent Token MCP-сервер вызывает обычные ERP endpoints:
MCP tool
→ точный allowlist HTTP method + path
→ Authorization: Bearer <agent_token>
→ middleware auth:user + banned
→ controller и policy конкретного endpoint
→ response обычного ERP API Наличие route внутри authenticated group ещё не доказывает безопасный MCP-контракт. Для каждого tool нужно отдельно проверить permission, project/branch scope, привязку вложенных ресурсов и состав ответа.
Три разные API-поверхности
| Поверхность | Назначение | Кто вызывает |
|---|---|---|
/api/agent-access-requests/* | первоначальный запрос доступа и одноразовая выдача первого Agent Token | MCP-клиент и подтверждающий человек |
обычные /api/orders, /api/counterparties, /api/nomenclatures и другие ERP endpoints | работа с бизнес-данными | MCP-сервер с Agent Token |
/api/agents/* и /api/tables/agents | создание, изменение и отключение agent accounts, управление токенами | административный actor; token operations — только человек |
/api/agents— не рабочие бизнес-ручки агента. Это административный ресурс для управления учётными записями агентов.
Получение первого токена описано на странице [«Получение доступа»](/ERP/МСП/Получение доступа/), а административные операции — на странице [«Управление агентами»](/ERP/МСП/Управление агентами/).
Откуда берутся права
Agent Token создаётся Laravel Sanctum с abilities *, но эти abilities не являются бизнес-правами. Для endpoints, где policy подключена, фактический доступ определяется текущим agent account:
Bearer
→ User с is_agent = true
→ project_id и branch_id этого User
→ текущие role + permissions
→ middleware, controller и policy конкретного endpoint Разные токены одного agent account используют один и тот же набор role и permissions. Отдельный токен удобен для ротации или разных установок MCP-сервера, но не создаёт отдельную границу полномочий. Для изоляции профилей нужен отдельный agent account.
Если администратор удалил permission, заблокировал агента или отозвал токен, следующий запрос должен перестать работать. Старый Bearer после отзыва или блокировки не восстанавливается.
Статусы профилей
| Профиль | Статус | Что разрешено сейчас |
|---|---|---|
| P0 Connectivity | current | проверить Bearer через GET /api/user |
| P1 Sales Readonly | current | заказы, контрагенты и безопасные справочники |
| People Directory | sensitive / opt-in | сотрудники только при отдельной необходимости и фильтрации ответа |
| P2 Sales Operator | conditional | calculator сразу; записи — после проверки permission catalog и negative tests |
| P3 Catalog / Warehouse | conditional | после проверки наличия catalog permissions в БД |
| P4 Applications / Content | blocked for normal assistant | текущие responses раскрывают application token |
| P5 Agent Administration | current | account operations по permissions; token operations только для human actor |
Профиль — конфигурация MCP-сервера, а не сущность backend. Он состоит из permissions agent account, точного allowlist method + path, request schema и правил подтверждения write-операций.
P0. Preflight: проверить токен
Проверка рабочего Agent Token
- Метод
- GET
- URL
https://api.gigma.ru/api/user- Авторизация
- Agent Bearer
- Headers
Accept: application/json; Authorization: Bearer <agent_token>- Успешный ответ
200
Endpoint возвращает wrapper user с обычным UserResource: ID, login, ФИО, роль, филиал, отдел, состояние блокировки, permissions и даты активности.
Используйте ответ, чтобы проверить:
- токен принят backend;
- учётная запись не заблокирована;
- роль, филиал и permissions соответствуют ожидаемому профилю tools.
Ограничение текущего контракта: GET /api/user не возвращает is_agent и project_id. Поэтому MCP-сервер не может доказать эти два значения по whoami. Тип учётной записи и ожидаемый проект должны храниться в конфигурации подключения, сформированной при выдаче доступа.
Ошибки
401— токен отсутствует, недействителен, истёк или отозван;403— доступ запрещён middleware или policy;- заблокированный agent account не должен доходить до бизнес-контроллера.
P1. Проверенный read-only профиль продаж
Минимальный набор permissions:
[
"view-orders",
"view-counterparties"
] Рабочие списки
GET /api/user
GET /api/orders
GET /api/tables/orders
GET /api/counterparties
GET /api/tables/counterparties Карточки и безопасные вложенные чтения
Сначала получите ID из списка, доступного текущему agent account, затем вызывайте:
GET /api/orders/{order}
GET /api/orders/{order}/history
GET /api/tables/orders/{order}/files
GET /api/tables/orders/{order}/nomenclatures
GET /api/counterparties/{counterparty} Для заказов backend применяет project scope, а для пользователя без роли owner/admin и с назначенным филиалом — ещё и branch scope. Вложенные order routes защищены can:view,order. CounterpartyPolicy проверяет permission и проект карточки.
Контекстные справочники только на чтение
В tool allowlist можно добавить только GET:
GET /api/order_statuses
GET /api/counterparty_types
GET /api/delivery_types
GET /api/sales_channels
GET /api/brands
GET /api/cities
GET /api/countries
GET /api/vats
GET /api/storage_units Не добавляйте POST, PUT, PATCH и DELETE для справочников в обычный read-only профиль.
Подробные query-параметры и response schemas находятся в разделах «Заказы» и «Контрагенты».
Отдельный sensitive-профиль: сотрудники
GET /api/users, GET /api/tables/users и GET /api/users/{user} не входят в минимальный P1. В текущем UserPolicy чтение разрешается не только по view-users, но также при наличии create-users или edit-users. Любое из этих трёх permissions нужно считать доступом к каталогу сотрудников.
Полный UserResource возвращает персональные и кадровые данные, включая phone, birthday, employment_contract и dismissal_date. Табличный resource короче, но всё равно содержит ФИО, login, роль, филиал, отдел и активность.
Подключайте эти endpoints только отдельному people-directory agent account. Для такого профиля:
- выдавайте минимальное право
view-users, если запись сотрудников не нужна; - не передавайте модели полный сырой ответ без необходимости;
- возвращайте только нужные поля, например ID и отображаемое имя;
- не включайте кадровые поля в логи и контекст модели;
- не рассчитывайте на отдельный токен того же агента как на изоляцию permissions.
Helper endpoints GET /api/managers и GET /api/responsible_users возвращают более короткие записи, но не вызывают UserPolicy и не требуют view-users, поэтому в production allowlist они пока не рекомендуются.
Endpoints, которые нельзя включать в production MCP allowlist
Ниже перечислены зарегистрированные routes, для которых текущий runtime не обеспечивает ожидаемую комбинацию permission check, project scope, parent-child scope или безопасный response contract.
Задачи
GET /api/tasks
GET /api/tables/tasks
GET /api/tasks/{task}
POST /api/tasks
PATCH /api/tasks/{task} TaskController не вызывает policy:
- list endpoints вручную добавляют только
project_id; showпринимает route model напрямую;updateизменяет полученную модель без object-level project check;- permissions
view-tasksиedit-tasksв контроллере не проверяются.
Особенно опасны GET /api/tasks/{task} и PATCH /api/tasks/{task}. Не выдавайте их MCP-серверу до backend-hardening и negative tests на объект чужого проекта.
Контакты и история контрагента
GET /api/counterparties/{counterparty}/history
GET /api/counterparties/{counterparty}/contacts
GET /api/counterparties/{counterparty}/contacts/{contact}
POST /api/counterparties/{counterparty}/contacts
PATCH /api/counterparties/{counterparty}/contacts/{contact}
DELETE /api/counterparties/{counterparty}/contacts/{contact} CounterpartyHistoryController не проверяет проект. ContactController проверяет permission, но ContactPolicy не проверяет проект, а nested routes не обеспечивают связь contact → counterparty. Эти endpoints нельзя считать безопасными только из-за наличия view-counterparties или edit-counterparties.
Приложения и интеграционные токены
Не включайте обычному MCP-помощнику:
GET /api/applications
GET /api/tables/applications
GET /api/applications/{application}
POST /api/applications
PATCH /api/applications/{application}
GET /api/applications/{application}/history Текущие ApplicationResource и Tables\ApplicationResource возвращают поле token. Значит даже read-only list раскрывает интеграционный секрет всем, кому выдан view-applications.
Есть и второе несоответствие: list фильтрует приложения по текущему проекту и допускает глобальные записи с project_id = null, а ApplicationPolicy::view() для detail требует точного совпадения application.project_id === user.project_id. Поэтому объект может появиться в списке, но вернуть 403 на карточке.
GET /api/applications/{application}/history дополнительно использует базовый Controller::history() без project check для Application.
До исправления backend нужен один из вариантов:
- убрать
tokenиз стандартных application resources; - вернуть секрет только отдельным endpoint с отдельным permission и аудитом;
- после этого заново доказать list/detail scope и добавить negative tests.
Webhooks и notification channels
Не включайте в обычный assistant-профиль:
/api/applications/{application}/webhooks*
/api/applications/{application}/notification-channels/* Эти методы могут раскрывать конфигурацию, ротировать секреты и повторно отправлять внешние доставки. Для них нужен отдельный integration-admin agent account, отдельный короткоживущий токен и подтверждение каждой write-операции.
Inventory detail и write
GET /api/inventories/{inventory}
POST /api/inventories
PATCH /api/inventories/{inventory}
DELETE /api/inventories/{inventory} InventoryController не подключает authorizeResource. show, update и destroy работают с route model без object-level project check; permission view-inventories или edit-inventories также не проверяется. Эти методы требуют исправления backend до подключения к MCP.
P2. Подтверждаемые операции с заказами и контрагентами
Готовый вычислительный tool
POST /api/orders/calculator Endpoint выполняет чистый расчёт по price, markup и discount, не читает модели из БД и не создаёт бизнес-сущность. Payload всё равно должен проходить фиксированную schema.
Условные write-tools
POST /api/orders
PATCH /api/orders/{order}
POST /api/orders/{order}/files
POST /api/orders/{order}/nomenclatures
PATCH /api/orders/{order}/nomenclatures/{nomenclature}
DELETE /api/orders/{order}/nomenclatures/{nomenclature}
POST /api/counterparties
PATCH /api/counterparties/{counterparty} Фактическая логика permissions:
- создание заказа разрешается с
create-ordersилиedit-orders; - изменение заказа требует
edit-orders; - создание контрагента разрешается с
create-counterpartiesилиedit-counterparties; - изменение контрагента требует
edit-counterparties.
Базовый PermissionSeeder создаёт edit-orders и edit-counterparties, но не создаёт create-orders и create-counterparties. Поэтому create-only профиль нельзя считать доступным во всех инсталляциях. Перед включением write-tools:
- проверьте, что точные permission records существуют с
guard_name = user; - не подменяйте отсутствующее create-only право более широким
edit-*без явного решения владельца; - проверьте положительный запрос в своём проекте и отрицательный запрос к ID другого проекта;
- включите только фиксированные methods и paths.
Каждый write-tool обязан:
- построить payload по фиксированной schema;
- показать человеку окончательные method, path и JSON;
- получить явное подтверждение;
- выполнить запрос один раз;
- перечитать созданный или изменённый объект и сверить результат.
Не повторяйте автоматически POST, PATCH или DELETE после 401, 403, 404, 409 или 422.
P3. Каталог и склады
Контроллеры номенклатуры, категорий и складов используют resource policies и project-scoped списки:
GET /api/nomenclatures
GET /api/tables/nomenclatures
GET /api/nomenclatures/{nomenclature}
POST /api/nomenclatures
PATCH /api/nomenclatures/{nomenclature}
GET /api/categories
GET /api/tables/categories
GET /api/categories/{category}
POST /api/categories
PATCH /api/categories/{category}
GET /api/warehouses
GET /api/tables/warehouses
GET /api/warehouses/{warehouse}
POST /api/warehouses
PATCH /api/warehouses/{warehouse} Их policies используют permissions вида view-*, create-*, edit-*, но catalog permissions не входят в базовый PermissionSeeder. Профиль можно включать только после проверки, что нужные permission records реально существуют с guard_name = user, назначены agent account и проходят negative tests на чужой проект.
Inventory endpoints в этот профиль не входят из-за описанного выше authorization gap.
P4. Приложения и контент
В текущем backend P4 не является обычным production-профилем. Основные application endpoints возвращают token, а nested CMS/integration routes требуют отдельного аудита scopes и секретов.
До redaction application token и отдельного permission contract не создавайте generic tools для:
/api/applications*
/api/pages*
/api/menus*
/api/applications/{application}/blocks*
/api/applications/{application}/webhooks*
/api/applications/{application}/notification-channels/* Разрешать отдельные storefront resources можно только отдельным agent account после проверки конкретного controller, policy, permission record и negative test. Не объединяйте content-admin и обычного sales assistant в одном agent account.
P5. Администрирование агентов
Административная поверхность:
GET /api/agents
GET /api/tables/agents
GET /api/agents/{agent}
POST /api/agents
PATCH /api/agents/{agent}
DELETE /api/agents/{agent}
GET /api/agents/{agent}/tokens
POST /api/agents/{agent}/tokens
DELETE /api/agents/{agent}/tokens/{token} Для неё используются отдельные permissions:
[
"view-agents",
"create-agents",
"edit-agents",
"manage-agent-tokens"
] Текущий UserPolicy не вводит глобальный запрет для agent actor на list, show, create, update или disable. Эти операции доступны authenticated actor, который прошёл соответствующие permission, project и delegation checks. Поэтому обычному MCP-помощнику нельзя выдавать agent-management permissions.
Для token operations действует отдельное правило: UserPolicy::manageAgentTokens() явно запрещает actor с is_agent = true. Выпуск, список и отзыв токенов через /api/agents/{agent}/tokens* выполняются Bearer-токеном человека. Полные request/response contracts находятся на странице [«Управление агентами»](/ERP/МСП/Управление агентами/).
Обязательные правила MCP-сервера
Только точный allowlist
Tool должен хранить конкретные:
HTTP method + path pattern Запрещён generic REST/curl proxy, через который модель может передать произвольный URL, method или JSON.
ID только после scoped lookup
Не принимайте произвольный ID от модели. Сначала получите сущность из проверенного списка текущего проекта. Затем используйте возвращённый ID в следующем tool.
Исключение «ID получен из списка» не делает route безопасным, если сам list возвращает глобальные записи или чувствительные поля. Именно поэтому application endpoints сейчас заблокированы.
Строгий payload
- удаляйте неизвестные поля;
- не отправляйте
undefinedи UI-placeholder; - не используйте
0как «не выбрано»: middlewareConvertZeroToNullможет преобразовать его вnull; - отправляйте
nullтолько когда tool явно поддерживает очистку поля; - показывайте человеку именно тот JSON, который будет отправлен.
Секреты и чувствительные данные
Не записывайте в логи и историю:
- Agent Bearer;
request_token;approval_token;- ответ первого
consume; agent_token.valueиз административной выдачи;- application
token; - кадровые и персональные поля сотрудников, если они не нужны сценарию.
Ошибки
| Код | Что означает для MCP-сервера |
|---|---|
401 | токен отсутствует, истёк или отозван; остановить запросы и запросить ротацию |
403 | permission или policy запретили действие; не обходить другим endpoint |
404 | объект отсутствует либо скрыт scope; не перебирать соседние ID |
409 | конфликт состояния; перечитать ресурс и показать человеку |
422 | payload или бизнес-правило не прошло валидацию; исправить данные, не повторять тот же запрос |
429 | применить backoff только для безопасного read/polling; write не дублировать вслепую |
Минимальный production-набор
Для первого агента используйте:
P0 Connectivity
+ P1 Sales Readonly
+ отдельные подтверждаемые write-tools только после проверки permission catalog Не выдавайте обычному помощнику права и endpoints для сотрудников, приложений, интеграционных секретов, webhooks, ролей, permissions, других агентов и административных операций.