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
Audiense Insights MCP Server

Audiense Insights MCP Server

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

官方
精选
本地
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

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

官方
精选
本地
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
Exa MCP Server

Exa MCP Server

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

官方
精选
mcp-server-qdrant

mcp-server-qdrant

这个仓库展示了如何为向量搜索引擎 Qdrant 创建一个 MCP (Managed Control Plane) 服务器的示例。

官方
精选
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选