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.
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, см. выше).
Документация дизайна
- Спецификация:
docs/superpowers/specs/ - План реализации:
docs/superpowers/plans/
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.