iikocloud-mcp

iikocloud-mcp

MCP server that exposes 236 iikoCloud API methods across 22 domains as configurable tools, supporting multi-tenancy with credentials passed through transport channels (HTTP headers or environment variables) for security.

Category
访问服务器

README

iikocloud-mcp

MCP-сервер поверх Iikocloud-manager (IikoCloudApiClientManager): интроспекцией менеджера сервер отдаёт 236 методов iikoCloud в 22 доменах как MCP-тулы, но запускается с вариативно задаваемым подмножеством, а не целиком. Мультиарендный: учётные данные iikoCloud передаёт клиент через канал транспорта (HTTP-заголовки под TLS или переменные окружения для stdio) — секреты никогда не попадают в аргументы тулов, а значит и в контекст модели или логи.

Прямой аналог iikoserver-mcp: тот же принцип, та же модель безопасности, отличия — только там, где различаются сами API (auth v2 вместо логина/пароля, асинхронные команды с опросом, кэш справочников).

  • Транспорты: stdio и streamable-HTTP.
  • Отбор тулов: по домену, по типу операции (read/write), по именам/glob, из разных источников (CLI / env / YAML).
  • Безопасность по умолчанию: read-only; запись — явным опт-ином, под подтверждением.

Зачем подмножество, а не все 236 тулов

Полная регистрация всех 236 тулов весит ~356 КБ JSON-схем (включая guidance-подсказки в описаниях) — это идёт в контекст модели при каждом подключении. Сервер сам вырезает из схем служебные поля, которые ничего не дают модели (pydantic-title, дублирующий имя свойства, и описания вида «Latitude.», буквально повторяющие имя поля) — без обрезки было бы ~433 КБ, то есть экономия около 18%. Read-only подмножество (без write-операций) весит уже ~95 КБ. Разброс по доменам большой: самый тяжёлый домен invoice_processing — 93 тула и 114 КБ, самый тяжёлый отдельный тул — discounts__calculate_loyalty_checkin, 18.9 КБ схемы. Из 236 методов 106 — read, 130 — write; ошибок схематизации при интроспекции — 0, регистрируются все.

Отсюда практический совет: выбирайте --domains под конкретную задачу клиента, а не поднимайте сервер со всем каталогом — это и экономит контекст модели, и сокращает поверхность записи.

Установка

uv pip install "iikocloud-mcp @ git+https://github.com/UserVanya/Iikocloud-mcp.git"
# или для разработки:
git clone https://github.com/UserVanya/Iikocloud-mcp.git && cd Iikocloud-mcp && uv sync

Требуется Python 3.12+ и креды iikoCloud auth v2 (api_key, app_id, client_secret).

Быстрый старт

# stdio: клиент запускает сервер как подпроцесс, креды — через env
IIKOCLOUD_API_KEY=key IIKOCLOUD_APP_ID=app IIKOCLOUD_CLIENT_SECRET=secret \
  iikocloud-mcp --transport stdio --domains organizations,menu

# HTTP: сервер на VPS, только чтение по организациям и меню.
# Слушаем 127.0.0.1 — TLS терминирует reverse-proxy на этом же хосте.
iikocloud-mcp --transport http --host 127.0.0.1 --port 8000 \
  --domains organizations,menu,dictionaries,addresses

--host 0.0.0.0 оправдан только если TLS-прокси работает на другом хосте: сам сервер говорит по HTTP без шифрования, а в каждом запросе едут X-Iikocloud-Api-Key, X-Iikocloud-App-Id и X-Iikocloud-Client-Secret. Открытый в интернет порт — это те же креды открытым текстом (см. Безопасность).

Тот же результат — через конфиг-файл (см. server.example.yml):

cp server.example.yml server.yml   # server.yml в .gitignore
uv run iikocloud-mcp --config server.yml

Отбор тулов

Тул включается, если: домен разрешён И тип операции разрешён И (нет allow ИЛИ имя совпало с allow) И имя не совпало с deny. deny всегда побеждает allow.

Имена тулов — <домен>__<метод> (например menu__get_nomenclature, deliveries__create_delivery_order). 22 домена: addresses, banquets, customer_categories, customers, deliveries, deliveries_retrieve, delivery_restrictions, dictionaries, discounts, drafts, employees, invoice_processing, marketing_sources, menu, messages, notifications, operations, orders, organizations, report, terminal_groups, webhooks.

Способ CLI env YAML
Домены --domains a,b IIKOCLOUD_MCP_DOMAINS=a,b domains: [a, b]
Разрешить запись --allow-write IIKOCLOUD_MCP_ALLOW_WRITE=1 operations: [read, write]
Allowlist имён/glob --allow 'get_*' --allow '*_report' IIKOCLOUD_MCP_ALLOW=get_*,*_report allow: ["get_*"]
Denylist имён/glob --deny 'delete_*' IIKOCLOUD_MCP_DENY=delete_* deny: ["delete_*"]
Выключить подтверждение записи --no-confirm-writes IIKOCLOUD_MCP_CONFIRM_WRITES=0 confirm_writes: false
Фолбэк без elicitation --write-fallback open IIKOCLOUD_MCP_WRITE_FALLBACK=open write_fallback: open
Лимит JSON-ответа (символы) --max-output-chars N IIKOCLOUD_MCP_MAX_OUTPUT_CHARS=N max_output_chars: N
Таймаут вызова, с --call-timeout N IIKOCLOUD_MCP_CALL_TIMEOUT=N call_timeout: N
Потолок окна лимитера, с --max-rate-window N IIKOCLOUD_MCP_MAX_RATE_WINDOW=N max_rate_window: N
TTL кэша справочников, с --cache-ttl N IIKOCLOUD_MCP_CACHE_TTL=N cache_ttl: N
Потолок записей кэша --cache-max-entries N IIKOCLOUD_MCP_CACHE_MAX_ENTRIES=N cache_max_entries: N
Хост / порт --host / --port IIKOCLOUD_MCP_HOST / IIKOCLOUD_MCP_PORT host: / port:
Транспорт --transport {stdio,http} IIKOCLOUD_MCP_TRANSPORT transport:

Приоритет источников: CLI > env > YAML-файл. Источник, задавший поле, заменяет его целиком (списки не мержаются). Путь к YAML — --config server.yml или IIKOCLOUD_MCP_CONFIG. См. server.example.yml.

--allow-write — это только включение записи со стороны CLI: чтобы выключить её обратно, просто не передавайте флаг. У env-переменной IIKOCLOUD_MCP_ALLOW_WRITE есть и включающее, и выключающее значение (1/0, true/false и т. п.).

Примеры:

# всё чтение по доставкам, но без карт лояльности
iikocloud-mcp --transport http --domains deliveries,deliveries_retrieve --deny '*loyalty*'

# запись включена, но без операций очистки
iikocloud-mcp --transport http --allow-write --deny '*__clear_*'

Передача учётных данных

Секреты идут только по каналу транспорта, не как аргументы тулов — модель их не видит.

HTTP-заголовок env для stdio
API-ключ X-Iikocloud-Api-Key IIKOCLOUD_API_KEY
App ID X-Iikocloud-App-Id IIKOCLOUD_APP_ID
Client secret X-Iikocloud-Client-Secret IIKOCLOUD_CLIENT_SECRET

Фолбэка на Authorization: Basic нет: он вмещает два секрета, а iikoCloud требует три.

Для HTTP-транспорта обязателен TLS — терминируйте HTTPS на reverse-proxy перед сервером, заголовки с кредами передавайте только под ним. Отсюда и дефолт --host 127.0.0.1: сам сервер шифрования не делает, поэтому наружу он должен смотреть только через прокси. stdio — переменные окружения подпроцесса (см. выше), сервер как локальный процесс отдельного TLS не требует.

Один сервер обслуживает несколько аккаунтов iikoCloud: экземпляр менеджера кэшируется по отпечатку sha1(api_key:app_id) (ApiCredentials.key_id).

Подключение MCP-клиента

stdio (например, конфиг Claude Desktop):

{
  "mcpServers": {
    "iikocloud": {
      "command": "iikocloud-mcp",
      "args": ["--transport", "stdio", "--domains", "organizations,menu,dictionaries"],
      "env": {
        "IIKOCLOUD_API_KEY": "key",
        "IIKOCLOUD_APP_ID": "app",
        "IIKOCLOUD_CLIENT_SECRET": "secret"
      }
    }
  }
}

Удалённый HTTP:

{
  "mcpServers": {
    "iikocloud": {
      "url": "https://mcp.example.com/mcp",
      "headers": {
        "X-Iikocloud-Api-Key": "key",
        "X-Iikocloud-App-Id": "app",
        "X-Iikocloud-Client-Secret": "secret"
      }
    }
  }
}

Программный API

from iikocloud_mcp import ServerConfig, ToolFilter, create_server

cfg = ServerConfig(
    # host="0.0.0.0" — только если TLS терминирует прокси на другом хосте
    transport="http", host="127.0.0.1", port=8000,
    tool_filter=ToolFilter(domains={"menu", "dictionaries"}, operations=frozenset({"read"})),
)
server = create_server(cfg)        # FastMCP с зарегистрированными тулами
server.run(transport="streamable-http")

Подтверждение операций записи

Write-тулы по умолчанию требуют подтверждения пользователя перед мутацией — сервер вызывает MCP-elicitation и выполняет метод только при явном accept. Это серверный гейт, а не просто хинт клиенту (destructiveHint): даже клиент с авто-подтверждением тулов не выполнит запись без ответа пользователя. Политику задаёт оператор при запуске (не LLM):

  • по умолчанию — подтверждение включено, фолбэк closed;
  • --write-fallback open — если клиент не умеет elicitation, выполнять запись без подтверждения (оператор берёт риск на себя); по умолчанию (closed) такая запись блокируется;
  • --no-confirm-writes — полностью отключить гейт (для доверенной автоматизации).

Встроенные подсказки

Сервер обогащает описание и результат каждого тула, не полагаясь на память модели.

Асинхронные команды. 42 тула из 236 возвращают только correlationId — это квитанция о принятой команде, самого результата в ответе нет. Описание такого тула получает пометку:

⏳ Асинхронная команда: ответ содержит только correlationId, результата в нём нет. Чтобы узнать исход, вызовите operations__wait_command с этим correlationId и organizationId.

Ещё для 8 write-тулов с содержательным ответом (например создание доставки) сервер проверяет поле creationStatus: если оно равно InProgress, к JSON-результату добавляется ключ _iikocloudMcpHint с той же инструкцией — опросить operations__wait_command.

«Где взять ID». Схема параметров каждого тула сверяется с курируемой картой полей вида organizationId → organizations__get_organizations, terminalGroupId → terminal_groups__get_terminal_groups, productId → menu__get_nomenclature и т. д. Совпавшие поля попадают в описание тула строкой «Где взять ID: …», так что модель не пытается угадывать идентификаторы.

Лимит метода. Если у метода есть запись в лимитере менеджера, описание получает приписку вида «Лимит: не чаще N запрос(ов) за M с — кэшируйте результат в диалоге».

Версии внешнего меню. У menu__get_external_menu_by_id результат — объединение ExternalMenuV2 | ExternalMenuV3 | ExternalMenuV4: форма ответа зависит от параметра version. Описание тула вручную перечисляет все переименования полей между версиями и рекомендует явно указывать version=4.

Адрес доставки. У deliveries__create_delivery_order описание отдельно поясняет: формат адреса задаёт сама организация (addressFormatType, значение — из organizations__get_organization_settings), улицу можно передать и id (addresses__get_streets_by_city), и просто name вместе с city, а город указывать нужно всегда — он определяет разбор остального адреса.

Кэш справочников

16 из 23 тулов-источников идентификаторов (тех самых, куда отправляют подсказки «где взять ID») допускают не чаще одного запроса в 60 секунд — а диалог с моделью легко делает несколько похожих запросов подряд. Поэтому ответы примерно 27 справочных read-тулов (организации, домены справочников, адреса, меню, курьеры и т. п.) кэшируются в памяти процесса с TTL.

  • --cache-ttl — время жизни записи в секундах, по умолчанию 300; 0 полностью выключает кэш.
  • --cache-max-entries — потолок числа записей (LRU-вытеснение), по умолчанию 256; обязателен, потому что ответ menu__get_nomenclature может весить мегабайты.

Ключ кэша учитывает аккаунт (по хэшу кредов, не сами секреты) и аргументы вызова — на HTTP-транспорте один процесс безопасно обслуживает разных арендаторов. Инвалидация — только по TTL.

Лимит размера ответа и таймаут вызова

По умолчанию лимита на размер ответа нет. Если установить положительный --max-output-chars, слишком длинный результат вернётся не оборванным текстом, а корректным JSON-объектом:

{
  "truncated": true,
  "totalChars": 250000,
  "limitChars": 100000,
  "contentPrefix": "..."
}

contentPrefix — начало полного JSON-результата, так модель может распознать усечение и сузить запрос вместо того, чтобы принять обрезанный ответ за полный.

--call-timeout (по умолчанию 120 с) ограничивает время одного вызова тула — лимитер менеджера иначе просто блокирует запрос без таймаута. При превышении сервер тоже возвращает корректный JSON, а не обрыв соединения:

{
  "timeout": true,
  "tool": "menu__get_nomenclature",
  "timeoutSeconds": 120,
  "reason": "Вызов не уложился в лимит времени. Обычная причина — rate limit метода: лимитер ждёт освобождения окна. Повторите позже или сузьте запрос."
}

--max-rate-window (по умолчанию 120 с) отдельно зажимает окна лимитера методов сверху: у методов с окном шире потолка (например 1 запрос/1800 с) окно укорачивается до потолка при сохранении числа запросов — иначе --call-timeout по умолчанию не успел бы дождаться собственного окна лимитера.

Тесты

uv run pytest -m unit -v          # 145 тестов, быстро, без сети и кредов
uv run pytest -m integration -v   # 4 read-only теста; без креда IIKOCLOUD_TEST_CONFIG — skip, не fail

Интеграционный набор (tests/integration/) гоняет реальные тулы через _make_tool против живого iikoCloud: получение организаций, camelCase-алиасы в ответе, попадание в кэш при повторном вызове, усечение по max_output_chars. Он только читающий — write-тестов против живого API нет и не будет: мутационный путь проверяется моками в tests/test_server.py.

Креды берёт из YAML по пути IIKOCLOUD_TEST_CONFIG (секция read) — см. config.test.example.yml и .env.example. Скопируйте оба в config.test.yml и .env: оба файла в .gitignore, секреты в репозиторий не попадают. Без IIKOCLOUD_TEST_CONFIG в окружении фикстура read_creds делает pytest.skip, а не падение, — так что набор безопасно запускать и на машине без кредов.

Безопасность

  • Секреты не попадают в аргументы тулов (модель их не видит), не логируются, живут только в памяти на время сессии.
  • Для HTTP обязателен TLS (reverse-proxy). Заголовки с кредами — только под HTTPS.
  • Дефолт и все примеры — host: 127.0.0.1. 0.0.0.0 открывает нешифрованный порт с кредами в заголовках; он оправдан только когда TLS-прокси стоит на другом хосте.
  • Своих гейтов по организациям или app_id сервер не вводит — доступ ограничивают настройки самого iikoCloud-аккаунта.
  • Дефолт read-only: мутации требуют явного --allow-write.
  • Дефолт: write-тулы требуют подтверждения пользователя (elicitation, см. выше).

Документация дизайна

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选