Оформление
Контракт init_eva_session
Как платформа привязывает сессию MCP к чату, что передаёт сервису, сколько живут выданные доступы и почему модель их никогда не видит.
Про имя
Инструмент называется init_eva_session. В некоторых документах он упоминается как eva_mcp_init, такого имени в коде нет ни в платформе, ни в сервисах. Правильное имя одно, оно приведено выше.
Зачем он нужен
Сервису MCP нужно знать, с каким чатом он работает и как ему дотянуться до файлов этого чата. Передавать эти сведения через параметры рабочих инструментов нельзя: их формирует модель, а модель не должна видеть ни ключей доступа, ни адресов хранилища.
Поэтому есть отдельный инструмент. Его вызывает Runtime, он скрыт от модели, и только через него передаются доступы.
Кто и когда вызывает
Вызывает только Runtime. Модель этот инструмент не видит в своём списке и вызвать не может.
Вызов происходит перед каждым обращением к инструментам сервиса, а не один раз на чат. Это же и есть механизм обновления доступа: повторный вызов с тем же чатом просто перезаписывает сохранённые данные.
Что передаётся
json
{
"chatId": "sess_123",
"userId": "usr_456",
"workspace": {
"kind": "chat",
"title": "Название чата"
},
"capabilities": {
"sessionFiles": true,
"uiBlocks": true,
"chatS3": true
},
"chatS3": {
"endpoint": "http://localhost:3000/api/chat-s3",
"bucket": "chat-files",
"prefix": "sessions/sess_123/",
"region": "auto",
"authMode": "query-token",
"token": "eyJ....sig",
"expiresAt": "2026-07-30T10:30:00.000Z"
}
}Обязательное поле только одно.
| Поле | Обязательно | Что означает |
|---|---|---|
chatId | да | Идентификатор чата. Без косых черт |
userId | нет | Идентификатор пользователя |
workspace | нет | Вид рабочего пространства и его название |
capabilities | нет | Что умеет платформа в этом чате |
chatS3 | нет | Доступ к файлам чата. Если его нет, сервис работает без файлов |
Минимальный вызов выглядит так:
json
{ "chatId": "sess_123" }Поля доступа к файлам
| Поле | Что означает |
|---|---|
endpoint | Адрес слоя доступа к файлам, всегда заканчивается на /api/chat-s3 |
bucket | Имя корзины, по умолчанию chat-files |
prefix | Границы чата, всегда sessions/<chatId>/ |
region | Всегда auto. Сервисы его сохраняют, но не используют |
authMode | Всегда query-token. Другое значение сервис обязан отклонить |
token | Ключ доступа |
expiresAt | Время истечения ключа |
Что возвращается
json
{
"ok": true,
"sessionBound": true,
"serverSessionId": "mcp_local_sess_abc"
}Значение serverSessionId сервис формирует сам, платформа его не разбирает.
Что сервис обязан проверить
Порядок проверок жёстко описан в общем регламенте сервисов.
- Сначала личность:
chatIdне пустой и не содержит косых черт. Иначе ошибка неверной сессии. - Затем разбор доступа: обязательны адрес, корзина, префикс и ключ. Значение
authMode, отличное отquery-token, отклоняется. Адрес, корзина и префикс приводятся к единому виду. - Затем главная проверка доверия: префикс обязан быть в точности
sessions/<chatId>/. Если нет, сессия отклоняется. - Сохраняется только простой набор данных, пригодный к сериализации. Живые объекты вроде открытых соединений сохранять нельзя.
- Возвращается ответ с признаком привязки.
Третья проверка это и есть защита
Именно совпадение префикса с идентификатором чата не даёт сервису обратиться к файлам другого чата. Скрытость инструмента от модели защитой не считается.
Два разных срока
Их нельзя путать.
| Срок | Кто управляет | Порядок величины |
|---|---|---|
| Время жизни состояния сессии | Библиотека сервиса | Часы |
| Время жизни ключа доступа | Платформа, поле expiresAt | 15 минут |
Проверять нужно именно второй срок, и делать это перед каждым обращением к хранилищу.
Пример отклонения
Попытка привязаться к чужому чату:
json
{
"chatId": "sess_test",
"chatS3": { "prefix": "sessions/another_chat/", "...": "..." }
}Ответ: ошибка с кодом неверной сессии.
Резервный инструмент list_eva_tenants
Платформа умеет спрашивать у сервиса список пространств, если сервис объявляет инструмент list_eva_tenants. Он тоже скрыт от модели и вызывается при подключении и проверке источника.
Ответ имеет вид {"tenants": [{"id", "name", "isDefault"}]}, ровно одно пространство должно быть помечено основным.
Ни один сервис его не реализует
Ни один из переданных сервисов этот инструмент не объявляет, поэтому платформа считает многопространственность выключенной и поле tenantId в вызов не добавляет. Если источник когда-нибудь пометить многопространственным, все четыре реализации init_eva_session получат незнакомый параметр, которого нет в их сигнатурах.
Что важно знать про обработку ошибок
Сервисы возвращают неудачу в виде обычного успешного ответа MCP, внутри которого стоит признак ok: false и код ошибки. Платформа при этом смотрит только на признак ошибки самого протокола MCP.
Неудачная привязка может быть принята за успешную
Для сервисов, у которых init_eva_session завёрнут в общий формат ответа, платформа не увидит неудачу привязки и продолжит работу. Чтобы платформа увидела неудачу, привязку сессии стоит оставлять без общей обёртки: тогда ошибка приходит как настоящая ошибка протокола.