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/
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。