Skip to main content
Glama
1artik1

Combo Engine MCP Server

by 1artik1

Combo Engine MCP Server

Расчёт выгодных комбо по сетям доставки Воронежа. Это MCP-сервер + библиотека парсеров: подбирает набор еды под бюджет, сравнивает сети по выгодности, следит за ценами и меню.

Все зависимости и браузер Playwright изолированы внутри .venv\ — системное окружение не затрагивается.

Смысл и сценарии каждой команды — в COMMANDS.md.

Сети

7 служб доставки Воронежа (kind=combo): Ла Пицца, Пицца Куба, Ниндзя Фуд, Сушитайм, Суши Даром, Антисуши, Додо Пицца. Дополнительно подключены продуктовые магазины (kind=store): Магнит (включён — поиск товаров/категории), Пятёрочка (выключена, анти-бот).

Related MCP server: yandex-eda-mcp

Как это работает

  • Сервер получает меню сетей (парсинг сайтов/API, с кэшированием и защитой от сбоев — «stale-if-error»).

  • По запросу строит комбо под бюджет: по умолчанию 3 варианта — Оптимум (вес + вкус, 1 напиток) → Без повторов → Макс. вес.

  • Поддерживает категории, промо-скидки, сравнение сетей, мониторинг цен и меню.

  • Комбо/меню/сравнение работают только по сетям доставки; магазины — отдельные store-тулы (поиск товаров и категории через нативный API).

Структура

├── combo_mcp\          # пакет MCP-сервера
│   ├── server.py       # точка входа (stdio)
│   ├── config.py       # конфиг сетей (config\chains_config.json)
│   ├── cache.py        # дисковый кэш + stale-if-error
│   ├── http_client.py  # requests-обёртка (UA, ретраи, куки)
│   ├── playwright_client.py  # ленивый браузер (фолбэк dodo)
│   ├── weights.py      # справочник расчётных весов (config\estimated_weights.json)
│   ├── engines\        # dp.py (комбо), taste.py (вкусность), drinks.py (напитки)
│   ├── chains\         # 1 файл = 1 сеть (@chain("id"))
│   └── tools\          # 1 файл = 1 инструмент MCP
├── scripts\            # selftest.py, autotest.py, smoke_test.py, gen_expected.py
├── tests\expected.json # эталоны для autotest
├── config\chains_config.json
├── config\estimated_weights.json  # веса позиций без веса на сайте (с источником)
├── cache\              # создаётся автоматически
├── COMMANDS.md         # для чего нужна каждая команда (смысл и сценарии)
└── archive\            # старые файлы + референсы разведки (recon\)

Запуск

# MCP-сервер (регистрируется opencode через opencode.json)
.\.venv\Scripts\python.exe combo_mcp\server.py

# Selftest: все сети + эталоны Ла Пиццы (3000₽ → 4400/2950, 4850/3000, 5100/2800)
.\.venv\Scripts\python.exe scripts\selftest.py

# Автотесты: эталоны комбо + инварианты + контрольные блюда + health_check
.\.venv\Scripts\python.exe scripts\autotest.py

# Smoke-тест реального MCP-протокола (15 инструментов)
.\.venv\Scripts\python.exe scripts\smoke_test.py

# Очистка кэша
.\.venv\Scripts\python.exe scripts\clear_cache.py

Инструменты MCP (15)

Подбор и сравнение

  • best_combo(chain_id, budget, variations=3, refresh=, categories=, promos=, sort_by=) варианты комбо под бюджет.

    • по умолчанию 3 вариации в порядке: Оптимум (максимум веса еды в бюджете

      • вкус, напиток оптимизируется внутри подбора) → Без повторов (макс. вес, каждый продукт по 1 шт) → Макс. вес (чистый максимум веса); при variations>3 — ещё доп. стратегии

    • 1 напиток в каждой вариации (если есть напитки с весом, влезающие в бюджет)

    • chain_id — одна сеть (обычный режим), пустая строка («все сети») или список через запятую («dodo, ninja_food») — сквозной топ-N: кандидаты сетей сортируются метрикой и отбирается топ variations (mode=all/multi)

    • sort_by=price_per_100g (по умолчанию), weight, price (только в cross-chain режиме)

    • categories= — фильтр по категориям: pizza/rolls/sushi/sets/combo/noodles/ snacks/desserts/drinks/sauces/other + русские слова («пицца», «напитки»…). combo — наборы/комбо-предложения, sets — чистые ролл-сеты; напитки — только если группа drinks в списке

    • promos= — применить промо-скидки: order / pickup / all

    • refresh=true — реальный прогон парсера, иначе ответ по кэшу

  • compare(budget, categories=) — лучшее комбо каждой сети на бюджет, отсортировано по выгодности (₽/100г).

Меню и контент

  • parse_menu(chain_id, category=, min_weight=, sort_by=, limit=, refresh=) меню сети с фильтрами и сортировкой (limit не более 500).

Контроль цен и меню

  • check_price(chain_id, item_name, expected_price=) — свежая проверка цены позиции (реальный парсинг).

  • diff_menu(chain_id) — изменения меню с прошлой загрузки.

  • chain_info(chain_id, refresh=) — доставка, акции, лояльность сети.

Состояние и качество данных

  • list_chains(refresh=) — сети: id, название, город, available, описание.

  • status() — конфиг, возраст кэша, ошибки.

  • verify_chain(chain_id) — качество данных сети: веса, дубликаты, аномалии.

  • check_config() — валидация chains_config.json.

  • health_check(refresh=False) — HTTP + парсинг + кол-во позиций по всем сетям (по кэшу или live).

Служебные

  • help(action=, command=) — справочник команд: список с пагинацией (/help next, /help back), детали одной команды (/help best_combo).

  • favorites(action=, chain_id=, label=, items=, query=) — избранное: сохранить (add), показать (list), удалить (remove), очистить (clear). Хранение: cache/favorites.json.

Магазины (kind=store)

  • store_search(query, store=, min_price=, max_price=, in_stock=, sort=, limit=) — поиск товаров по магазинам (живой нативный API, не меню-кэш).

  • store_categories(store=) — серверное дерево категорий магазинов. Только kind=store; рестораны — ошибка. Подробности — в разделе «Магазины».

Параметры и защита от дурака

Числовые параметры передаются строками и валидируются. Капы: budget ≤ 100000, variations ≤ 50, limit ≤ 500 — иначе явная ошибка {"error": ...}. Нераспознанные categories/sort_by/chain_id — ошибка с перечнем доступных значений, а не молча пустой ответ. Мусор в числовых параметрах (abc, 0, отрицательные) не роняет сервер — возвращается корректная ошибка.

Автотесты

tests\expected.json — фиксированные эталоны (комбо по сетям/бюджетам, контрольные блюда). Без record-режима: scripts\autotest.py сверяет фактический результат с эталоном, расхождение → FAIL + дифф. Эталон обновляется только осознанным коммитом.

Сравнение комбо: вариант 1 (оптимум) сверяется по точному составу, а варианты 2+ — с допуском ±5% на вес и цену: меню сетей регулярно меняются, и состав «добивок» (соусы, маффины, имбирь, палочки) в вариантах 2+ легко сдвигается без потери качества. Так автотест ловит реальные регрессии оптимума, но не спамит ложными падениями из-за дрейфа меню в не-оптимальных вариантах.

CI (GitHub Actions)

  • .github\workflows\ci.yml — на каждый push: компиляция + быстрый smoke без сети (сервер стартует, 15 инструментов зарегистрированы, JSON-ответы). Запуск вручную: scripts\ci_smoke.py.

  • .github\workflows\nightly.yml — ежедневно в 06:00 UTC: живой парсинг всех сетей (health_check refresh=true) + полный автотест (30 блоков). Это мониторинг парсеров: упавшая сеть или регрессия → красный статус + артефакт с отчётом (cache/).

Магазины (kind=store)

Магазины — отдельный мир: комбо/меню/сравнение (parse_menu/best_combo/compare) для них не работают, их обслуживают два store-тула:

  • store_search(query, store=, min_price=, max_price=, in_stock=, sort=, limit=) — поиск товаров через нативный серверный поиск магазина (parser.search): свежие цены и наличие (не меню-кэш). store="" — все включённые магазины, или список через запятую. Матчинг — combo_mcp/engines/textmatch.py (регистр/ё→е не важны, Левенштейн ≤1 для слов ≥5 симв., бонус за категорию). Сортировка: relevance (default) | price_asc | price_desc. В ответе score, chain_id, stores_errors (ошибка одного магазина не роняет ответ).

  • store_categories(store=) — серверное дерево категорий магазина (parser.get_categories), store="" — все включённые.

  • magnit — включён. API webgate.magnit.ru (requests, без браузера): категории /webgate/v3/categories/store/992301, товары/поиск POST /webgate/v2/goods/search (цены — рубли, вес из weight/имени, weight_source=name). TTL кэша меню — неделя (menu_ttl_minutes: 10080).

  • pyaterochka — выключен (enabled: false). API 5d.5ka.ru закрыт анти-ботом (капча вне браузера); парсер написан на Playwright, но headless стабильно получает капчу → явная ошибка «магазин отключён (enabled=false)».

  • Для обоих магазинов работают store_search/store_categories (серверный путь) и общие status/health_check/check_config. Рестораны (kind=combo) в store-тулах — ошибка.

Конфиг сетей

config\chains_config.json — per-chain: url, enabled, ttl_minutes, headers, cookies. Смена URL/куки не требует правки кода.

Добавление новой сети

  1. Скопировать combo_mcp\chains\_template.pycombo_mcp\chains\my_chain.py (или проще: python scripts\new_chain.py my_chain "Моя Сеть" https://example.com)

  2. Реализовать метод parse() (возвращает список позиций: {name, weight_g, price_rub, is_from_price, description, category, product_url, in_stock, extra})

  3. Заполнить category_map — маппинг категорий меню → группы комбо (pizza/rolls/sushi/sets/noodles/snacks/desserts/drinks/sauces/other)

  4. Указать url в chains_config.json (генератор делает это сам)

Больше ничего: парсеры регистрируются автоматически (pkgutil), метаданные сети (id/name/city/url/description) берутся из класса парсера, категории — из его category_map. По желанию: parse_extra() (доставка/акции), веса в config\estimated_weights.json, переводы в config\translations.json.

Добавление нового инструмента

Положить файл с функцией-хендлером в combo_mcp\tools\ и зарегистрировать декоратором (см. существующие инструменты) — server.py не трогается.

Правила данных

  • Вес позиции: с сайта/API (weight_source site), из названия размера (size_name, pizza_kuba), из справочника config\estimated_weights.json (reference, поле source — откуда взят вес) или отсутствует (none).

  • Позиции без веса исключаются из расчёта комбо (мерч, палочки — намеренно).

  • Недоступные сети честно помечаются в list_chains/compare с причиной.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

No tool schema history has been recorded yet.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    MCP server for iiko restaurant management system REST API, providing 39 tools to manage products, employees, entities, documents, payments, reports, and raw API access.
    1
    -

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/1artik1/ComboPizzaSushiMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server