Skip to content
2.12.0

Свой MCP-сервер ​

Как сделать MCP-сервер, который правильно работает с EVA: тенанты при подключении, служебный каталог тенантов, обмен файлами по ссылкам и правила для инструментов. Для разработчиков интеграций.

Принципы ​

  • Модель видит только ваши бизнес-инструменты.
  • EVA не вызывает на старте чата никаких служебных инструментов и не выдаёт серверу доступ к файлам.
  • Тенант передаётся только при подключении: заголовками HTTP или переменными окружения stdio.
  • Файлы ходят по ссылкам: сервер выдаёт ссылку, EVA сама скачивает или загружает файл.

Соединение ​

На каждый чат и каждый источник EVA открывает отдельное соединение. Параметры тенанта фиксируются при подключении и действуют всё время его жизни.

Тенанты ​

ТранспортОсновной тенантВсе разрешённые
Streamable HTTP, SSEX-Eva-Tenant-IdX-Eva-Tenant-Ids через запятую
stdioEVA_TENANT_IDEVA_TENANT_IDS через запятую
  • Основной тенант всегда входит в список разрешённых.
  • Сервер обязан сам проверять доступ по списку и не выходить за него.
  • Если сервер не поддерживает тенанты, EVA ничего не передаёт.

Каталог тенантов ​

Чтобы администратор мог выбирать тенанты для групп, объявите инструмент с фиксированным именем list_eva_tenants без аргументов. EVA вызывает его только при проверке источника, модель его не видит.

json
{
  "tenants": [
    { "id": "main", "name": "Основной", "isDefault": true },
    { "id": "demo", "name": "Демо", "isDefault": false }
  ]
}

Ровно один тенант должен быть isDefault.

Файлы ​

НаправлениеСервер отдаётEVA вызывает
Файл к моделиdownloadUrldownload_url
Файл от моделиuploadUrl, метод, кодировку, имя поляupload_url

Для временной загрузки на ваш сервер используйте POST multipart/form-data:

json
{
  "uploadUrl": "https://mcp.example.com/api/v1/uploads/<token>",
  "method": "POST",
  "encoding": "multipart",
  "fieldName": "file",
  "fileName": "report.pdf"
}

Для pre-signed ссылок объектного хранилища используйте PUT с encoding: "raw".

Правила:

  • не передавайте файл в аргументах инструментов, ни в base64, ни иначе;
  • принимайте загрузку потоком на диск, не читая тело целиком в память;
  • если пришёл заголовок X-Public-Base-Url, стройте ссылки от этого origin. Иначе используйте адрес из своих настроек.

Долгие задачи оформляйте как задание: инструмент запуска возвращает jobId и uploadUrl, инструмент статуса возвращает прогресс и в конце downloadUrl. Так устроены Paleograph и Transcript.

Правила для инструментов ​

  1. Принимайте от модели только бизнес-поля: период, формат, запрос.
  2. Не принимайте в аргументах tenantId, токены и пароли.
  3. Не рассчитывайте на состояние, выданное платформой на чат.
  4. Пишите понятные описания: EVA проверяет их на промпт-инъекции, а модель выбирает инструмент по описанию.

Пример на Python ​

python
import os
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("eva-demo")

PRIMARY = os.environ.get("EVA_TENANT_ID")
ALLOWED = [t for t in os.environ.get("EVA_TENANT_IDS", "").split(",") if t]

@mcp.tool(name="list_eva_tenants", description="Каталог тенантов для администратора EVA.")
def list_eva_tenants() -> dict:
    return {"tenants": [{"id": "main", "name": "Основной", "isDefault": True}]}

@mcp.tool(description="Отчёт за период.")
def get_report(period: str) -> dict:
    if ALLOWED and PRIMARY not in ALLOWED:
        raise RuntimeError("tenant is not allowed")
    return {"tenant": PRIMARY, "period": period}

if __name__ == "__main__":
    mcp.run()

Чек-лист ​

  • Инструменты не требуют тенант и учётные данные в аргументах.
  • Мультитенантный сервер читает тенанты из заголовков или окружения и не выходит за список.
  • Объявлен list_eva_tenants с одним тенантом по умолчанию, если нужны тенанты.
  • Файлы передаются по ссылкам, временная загрузка через POST multipart.
  • Учитывается X-Public-Base-Url.

Как подключить готовый сервер: Источники MCP.

Документация экосистемы EVA 2.1