Bedolaga MCP Server
Bedolaga MCP Server
MCP-сервер для получения пользовательских фактов из Bedolaga Bot по Telegram ID или внутреннему user_id.
Сервер read-only: через Bedolaga MCP нельзя менять баланс, создавать или продлевать подписки, применять промокоды, оформлять возвраты, выводить реферальные средства или выполнять иные действия от имени пользователя.
Breaking migration (1.0.0)
Начиная с версии 1.0.0 публичный контракт инструментов изменён, а старые имена удалены. Обновите конфигурацию клиента:
Старый инструмент | Что вместо него |
| заменён на |
| заменён на |
| не имеет аналога в Bedolaga MCP. Фактический статус подписки и состояние VPN-панели проверяются через отдельный mcp-remnawave, а не через этот сервер |
Также в 1.0.0 удалён устаревший HTTP-путь /mcp: sessionful Streamable HTTP теперь обслуживается на корневом endpoint /, как у mcp-remnawave. Каждая публикация образа получает три тега: :latest, :{version} и :{sha}.
Версия 1.0.0 — первый контракт с корректными API routes, structured результатами и явной границей ответственности с Remnawave.
Related MCP server: Monobank MCP Server
Инструменты (Tools)
Сервер предоставляет ровно восемь инструментов, доступных через MCP-протокол. Все инструменты readonly — данные не изменяются.
Контракт идентичности
Каждый инструмент принимает ровно одно из двух полей:
telegram_id— целое число, Telegram ID пользователя (положительное);user_id— целое число, внутренний ID пользователя в Bedolaga (положительное), используется для email-only тикетов кабинета.
Если не передано ни одного поля или переданы оба — инструмент возвращает ошибку invalid_input. Идентичность никогда не берётся от модели: supportBot всегда пинит фактического отправителя — положительный telegram_id из аутентифицированного Telegram update, либо внутренний user_id кабинета для email-only тикета.
bedolaga_user_get
Получить аккаунт и баланс текущего пользователя Bedolaga.
Параметры:
Параметр | Тип | Обязательный | Описание |
|
| ровно одно из двух | Telegram ID пользователя |
|
| ровно одно из двух | Внутренний ID пользователя Bedolaga (email-only тикет) |
JSON-поля ответа (data):
Поле | Тип | Описание |
|
| Признак, что пользователь найден |
|
| Telegram ID пользователя |
|
| Безопасное отображаемое имя |
|
| Статус аккаунта Bedolaga |
|
| Баланс в копейках |
|
| Баланс в рублях (всегда |
|
| Признак первого пополнения в прошлом |
|
| Признак наличия платной покупки в прошлом |
|
| Реферальный код |
|
| Пользователь пришёл по приглашению |
|
| Название промогруппы и проценты скидок |
|
| Даты создания и последней активности |
Поле promo_group содержит только name, server_discount_percent, traffic_discount_percent, device_discount_percent.
Пример интерпретации (синтетический): balance_kopeks: 350000 и balance_rubles: 3500.0 означают баланс 3 500 рублей. has_had_paid_subscription: false означает, что платных покупок ещё не было.
bedolaga_billing_get
Одним вызовом показать баланс, недавние финансовые события и внутренние записи покупок Bedolaga — чтобы отличить пополнение от покупки.
Параметры:
Параметр | Тип | Обязательный | Описание |
|
| ровно одно из двух | Telegram ID пользователя |
|
| ровно одно из двух | Внутренний ID пользователя Bedolaga (email-only тикет) |
|
| Нет | Лимит операций в списке (по умолчанию 20, максимум 50) |
JSON-поля ответа (data):
Поле | Тип | Описание |
|
| Текущий баланс |
|
| Операции от новых к старым, не более |
|
| Сводка последнего завершённого пополнения |
|
| Сводка последней завершённой покупки подписки |
|
| Завершённая покупка позже последнего завершённого пополнения |
|
| Внутренние записи подписок Bedolaga |
|
| Фиксированное пояснение «deposit ≠ purchase» |
Каждая операция в transactions:
Поле | Тип | Описание |
|
| Внутренний ID транзакции |
|
| Нормализованная категория: |
|
|
|
|
| Исходное безопасное имя типа |
|
| Абсолютная сумма |
|
| Платёжный метод |
|
| Завершённость операции |
|
| Описание |
|
| Время создания и завершения |
Каждая запись в bot_subscriptions содержит id, bot_record_status, bot_record_effective_status, is_trial, tariff_id, tariff_name, start_date, end_date, autopay_enabled, autopay_days_before и фиксированную note. Сервер предпочитает полный upstream-список subscriptions, удаляет повторяющиеся записи по id и сохраняет fallback на одиночное legacy-поле subscription. Поле называется bot_record_status намеренно: это внутренняя запись Bedolaga, а не статус VPN-панели. bot_record_effective_status — тоже бот-сторонний эффективный статус (вычисленный ботом из status и end_date), а не состояние панели.
Пример интерпретации (синтетический): latest_completed_deposit: {amount_kopeks: 350000} и purchased_after_latest_deposit: false — деньги зачислены на баланс, но отдельная покупка после пополнения не завершена.
bedolaga_referrals_get
Получить реферальную сводку текущего пользователя.
Параметры:
Параметр | Тип | Обязательный | Описание |
|
| ровно одно из двух | Telegram ID пользователя |
|
| ровно одно из двух | Внутренний ID пользователя Bedolaga (email-only тикет) |
JSON-поля ответа (data):
Поле | Тип | Описание |
|
| Реферальный код владельца аккаунта |
|
| Владелец пришёл по приглашению |
|
| Эффективная комиссия |
|
| Всего приглашено |
|
| Активных приглашённых |
|
| Заработок за всё время |
|
| Заработок за текущий месяц |
|
| Последние начисления владельца |
|
| Фиксированное пояснение |
Возвращается статистика только владельца аккаунта. Telegram ID, внутренние ID, username, имена, баланс и активность приглашённых пользователей никогда не возвращаются.
bedolaga_subscription_get
Получить бот-сторонние записи подписок и даты жизненного цикла (created_at, start_date, end_date, is_trial, autopay_enabled).
Параметры: telegram_id или user_id (ровно одно).
Возвращает has_subscription_records, active_record_count, список subscriptions и фиксированный meta. Поле bot_record_status — внутренняя запись бота, а не статус VPN-панели (фактическое состояние проверяется через Remnawave MCP).
bedolaga_tickets_get
Получить сводку собственных обращений в поддержку (id, title, status, priority, даты создания/обновления/закрытия) без текстов сообщений и медиа.
Параметры: telegram_id или user_id (ровно одно), limit (по умолчанию 10, максимум 50).
bedolaga_payment_status_get
Получить историю финансовых операций и статус завершённости в учётной системе бота (completed / not_completed / unknown).
Параметры: telegram_id или user_id (ровно одно), limit (по умолчанию 5, максимум 20).
Статус not_completed означает лишь отсутствие завершения операции в биллинге бота, а не сбой или ожидание на стороне платёжного шлюза.
bedolaga_promocode_check
Проверить глобальное определение промокода, срок действия, активность, бонус и остаток применений.
Параметры: code (обязательно), telegram_id или user_id (ровно одно для пиннинга идентичности).
Возвращает маскированный код (code_masked), признак globally_valid, reason_code (not_found, inactive, not_yet_valid, expired_or_exhausted, lookup_incomplete) и user_eligibility: "unknown".
bedolaga_gifts_get
Получить историю покупок подарков владельца аккаунта.
Параметры: telegram_id или user_id (ровно одно), limit (по умолчанию 20, максимум 50).
Отображает только факт покупки подарков (бухгалтерия); токены подарков, получатели и статус активации не раскрываются.
Decision table
Как LLM (supportBot) должен использовать данные Bedolaga и Remnawave по сценариям:
Сценарий | Что видно в Bedolaga MCP | Действие LLM |
Deposit без покупки |
| Объяснить, что деньги зачислены на баланс, но отдельная покупка не завершена; направить завершить покупку из баланса. Не заявлять о неисправной подписке |
Покупка с рабочей панелью | Завершённая | Проверить фактическое состояние панели через Remnawave MCP |
Покупка без записи в панели | Завершённая | Эскалировать как подтверждённое расхождение с кратким factual summary |
Нет пополнения |
| Не заявлять, что платёжный провайдер не списал деньги (Bedolaga подтверждает только отсутствие зачисления в своей учётной системе); эскалировать, если пользователь сообщает о фактическом списании |
Реферальный вопрос |
| Маршрутизировать только в Bedolaga MCP |
Вопрос о ноде / HWID | — | Маршрутизировать только в Remnawave MCP (состояние нод и устройств Bedolaga не знает) |
Формат результата
Каждый инструмент возвращает JSON в текстовом MCP content с единой оболочкой:
успех:
ok: true,source: "bedolaga-mcp",tool,data,meta;ошибка:
ok: false,source,tool,error.code, безопасныйerror.message,error.retryable.
Сырое тело ответа Bedolaga API и исключения Python модели не возвращаются. Инструменты не возвращают email, ссылку подписки, crypto link, ключи, внешние платёжные ID, receipt-идентификаторы, Remnawave-идентификаторы и персональные данные рефералов.
Error codes
Код | Retryable | Когда возникает |
| нет | Переданы оба или ни одного identity-поля; недопустимое значение |
| нет | Отсутствует/некорректна конфигурация окружения |
| нет | Идентичность нельзя сопоставить с пользователем Bedolaga |
| нет | Пользователь не найден (upstream 404 исключительно при поиске пользователя) |
| нет | Неверные/отсутствующие API-креденшелы (upstream 401/403) |
| да | Достигнут rate limit (upstream 429) |
| да | Таймаут или сбой сети до ответа |
| да | Upstream недоступен (5xx, сбой запроса или upstream 404 для непользовательских ресурсов — не означает отсутствие аккаунта) |
| нет | Тело ответа — невалидный JSON или не объект |
| нет | Непредвиденная внутренняя ошибка |
Пользовательское сообщение строится только из безопасного error.message и никогда не раскрывает HTTP body или внутренний URL. Ошибка user_not_found возникает только при прямом поиске учётной записи (get_user_by_telegram_id / get_user_by_id). При статусе 404 для зависимых ресурсов (транзакции, рефералы, подписки, тикеты, промокоды) возвращается upstream_unavailable, что указывает на недоступность конкретного ресурса и не свидетельствует об отсутствии аккаунта пользователя.
Транспорты
Сервер поддерживает два транспорта на одном server factory и одном реестре инструментов:
Транспорт | Launcher | Порт | Протокол |
Streamable HTTP (основной) |
| 3100 по умолчанию | Dual-era MCP на |
Stdio |
| — | MCP stdio handshake (тот же factory) |
Эндпоинт / — единственный, но обслуживает две эры протокола одновременно; SDK v2 сам определяет, к какой эре относится каждый запрос, по заголовку MCP-Protocol-Version:
Современный протокол
2026-07-28— stateless/sessionless. Каждый POST на/самодостаточен: сервер никогда не выдаётMcp-Session-Idи не хранит состояние между запросами. Официальные клиенты MCP SDK v2 (см. «Официальный клиент SDK v2» ниже) используют этот режим автоматически.Legacy-клиенты с initialize-handshake (протоколы вплоть до
2025-11-25, включая2024-11-05) получают заголовокMcp-Session-Idв ответ наinitializeи обязаны передавать его во всех последующих запросах.DELETE /с этим заголовком завершает именно эту сессию; на другие сессии и на современных клиентов это не влияет.
GET /health отдаёт liveness процесса и версию сервера, не раскрывая конфигурацию и секреты.
Версионная совместимость
Компонент | Версия |
Bedolaga Bot API (upstream) | commit |
bedolaga-mcp |
|
Python MCP SDK ( |
|
Поддерживаемые протоколы MCP |
|
supportBot |
|
mcp-remnawave |
|
Контракт инструментов проверен против указанного upstream-коммита и эталона mcp-remnawave v3.2.1.
Требования
Python 3.11+
Docker (опционально)
Развёрнутый Bedolaga Bot с Web API
API-ключ от Bedolaga (выдаётся в админ-панели бота)
Быстрый старт
1. Клонировать
git clone https://github.com/mitetenov/bedolaga-mcp.git
cd bedolaga-mcp2. Настроить
cp .env.example .env
# Заполнить BEDOLAGA_API_URL и BEDOLAGA_API_KEY3. Запустить
Streamable HTTP (рекомендуется):
# Установить зависимости
pip install -r requirements.txt
# Запустить HTTP-сервер
BEDOLAGA_API_URL=https://your-bot.example.com \
BEDOLAGA_API_KEY=your-key \
python3 http_server.pyСервер будет слушать на http://0.0.0.0:3100, MCP endpoint — корень /.
Stdio:
BEDOLAGA_API_URL=https://your-bot.example.com \
BEDOLAGA_API_KEY=your-key \
python3 bedolaga_server.pyЧерез Docker:
docker compose up -dDocker-образ по умолчанию запускает Streamable HTTP сервер на порту 3100.
Подключение как MCP-сервер
Streamable HTTP
Сервер доступен по HTTP на порту 3100, endpoint — корень / (http://localhost:3100).
Hermes Agent
# ~/.hermes/config.yaml
mcp_servers:
bedolaga:
transport: streamable-http
url: "http://localhost:3100"
env:
BEDOLAGA_API_URL: "https://your-bot.example.com"
BEDOLAGA_API_KEY: "your-api-key"Claude Desktop
{
"mcpServers": {
"bedolaga": {
"type": "streamableHttp",
"url": "http://localhost:3100"
}
}
}Cursor / VS Code
{
"mcpServers": {
"bedolaga": {
"transport": "streamable-http",
"url": "http://localhost:3100"
}
}
}Проверка через curl (legacy compatibility check)
Сырой JSON-RPC через curl использует legacy initialize-handshake (протокол 2024-11-05) — это ручная проверка обратной совместимости, а не то, как ходят современные клиенты. Современные клиенты MCP SDK v2 согласовывают протокол 2026-07-28 автоматически и Mcp-Session-Id не получают (см. «Официальный клиент SDK v2 (современный протокол)» ниже).
# Liveness
curl -s http://localhost:3100/health
# Legacy initialize handshake (получить session ID; работает для протоколов вплоть до 2025-11-25)
curl -s -X POST http://localhost:3100/ \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{}},"id":1}' \
-D - | grep -i mcp-session-id
# Список инструментов (с session ID)
curl -s -X POST http://localhost:3100/ \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":2}'
# Вызов инструментов
# Пользователь и баланс
curl -s -X POST http://localhost:3100/ \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"bedolaga_user_get","arguments":{"telegram_id":123456789}},"id":3}'
# Биллинг (операции и внутренние записи покупок)
curl -s -X POST http://localhost:3100/ \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"bedolaga_billing_get","arguments":{"telegram_id":123456789,"limit":20}},"id":4}'
# Реферальная сводка
curl -s -X POST http://localhost:3100/ \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: <SESSION_ID>" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"bedolaga_referrals_get","arguments":{"telegram_id":123456789}},"id":5}'
# Завершение legacy-сессии (для современного протокола 2026-07-28 не требуется и не применяется)
curl -s -X DELETE http://localhost:3100/ \
-H "Mcp-Session-Id: <SESSION_ID>"Официальный клиент SDK v2 (современный протокол)
Официальный клиент из Python MCP SDK v2 (mcp==2.0.0) сам согласовывает протокол — 2026-07-28, если сервер его поддерживает, иначе legacy-handshake — без ручного построения _meta или заголовков:
import asyncio
from mcp.client.client import Client
async def main() -> None:
async with Client("http://localhost:3100/", mode="auto") as client:
print("negotiated protocol:", client.protocol_version) # "2026-07-28" against this server
tools = await client.list_tools()
print([tool.name for tool in tools.tools])
result = await client.call_tool(
"bedolaga_user_get", {"telegram_id": 123456789}
)
print(result.content)
asyncio.run(main())mode="auto" — это то же самое согласование, которое использует supportBot: клиент сам решает, современный сервер перед ним или legacy, и не требует от вызывающего кода знать протокольную эру заранее.
Stdio транспорт
Hermes Agent
# ~/.hermes/config.yaml
mcp_servers:
bedolaga:
command: "python3"
args: ["/path/to/bedolaga-mcp/bedolaga_server.py"]
env:
BEDOLAGA_API_URL: "https://your-bot.example.com"
BEDOLAGA_API_KEY: "your-api-key"Claude Desktop
{
"mcpServers": {
"bedolaga": {
"command": "python3",
"args": ["/path/to/bedolaga-mcp/bedolaga_server.py"],
"env": {
"BEDOLAGA_API_URL": "https://your-bot.example.com",
"BEDOLAGA_API_KEY": "your-api-key"
}
}
}
}Cursor / VS Code
Добавить в .cursor/mcp.json или settings.json:
{
"mcpServers": {
"bedolaga": {
"command": "python3",
"args": ["/path/to/bedolaga-mcp/bedolaga_server.py"],
"env": {
"BEDOLAGA_API_URL": "https://your-bot.example.com",
"BEDOLAGA_API_KEY": "your-api-key"
}
}
}
}Управление сессиями
Streamable HTTP транспорт — dual-era, и сессии применимы только к одной из двух эр:
Legacy initialize-handshake (протоколы вплоть до
2025-11-25): послеinitializeсервер возвращает заголовокMcp-Session-Id, который клиент должен передавать во всех последующих запросах.DELETE /с этим заголовком завершает только указанную сессию; один клиент не может завершить или переиспользовать чужую сессию.Современный протокол
2026-07-28: stateless/sessionless — сервер никогда не выдаётMcp-Session-Id, иDELETE /для таких клиентов не нужен и не применяется.
Переменные окружения
Переменная | Назначение |
| URL Bedolaga Web API |
| API-ключ Bedolaga (передаётся upstream в |
| Адрес для bind (по умолчанию: |
| Порт HTTP-сервера (по умолчанию: |
| Таймаут upstream в миллисекундах (по умолчанию: 10000) |
Для совместимости принимаются legacy-переменные HOST/PORT, если MCP_HTTP_HOST/MCP_HTTP_PORT не заданы.
Upstream API
Bedolaga Web API: X-API-Key в заголовке. Используемые маршруты:
GET /users/by-telegram-id/{telegram_id}— пользователь по Telegram ID;GET /users/{user_id}— пользователь по внутреннему ID (email-only тикеты);GET /transactions?user_id=...— операции с фильтрами и пагинацией;GET /partners/referrers/{user_id}— реферальная карточка.
Подробнее: https://docs.bedolagam.ru
Ограничения первой версии
Нет provider-specific попыток платежей. Bedolaga возвращает только операции, ставшие записями в общей таблице transactions. Сырые попытки платёжного провайдера, которые не стали записью, недоступны.
Нет чтения Redis-корзины пользователя. Актуальный Web API не предоставляет безопасный read-only endpoint для этого. Текущую проблему «пополнил, а покупки нет» достоверно диагностируют по разнице между
depositиsubscription_payment(см. decision table).Email-only lookup поддерживается. Для тикетов кабинета без Telegram ID сервер принимает внутренний
user_id(положительное целое) и резолвит его черезGET /users/{user_id}. supportBot пинит внутреннийuser_idкабинета (абсолютное значение отрицательного synthetic conversation key) — для таких тикетов Bedolaga-данные доступны, а Remnawave-инструменты возвращаютidentity_unavailable, потому что у такого пользователя нет Telegram-идентичности и доказанной записи в панели.
Откат (rollback)
Выключение BEDOLAGA_MCP_ENABLED=false в supportBot возвращает его в Remnawave-only режим: Bedolaga MCP не подключается, его инструменты исчезают из allowlist, а вебхук/poller-обработка тикетов (BEDOLAGA_ENABLED) остаётся независимой. Откат не трогает пользовательскую базу и финансовые данные — Bedolaga MCP read-only и не хранит состояние.
Откат образа bedolaga-mcp до тега 1.1.0 (последний релиз до миграции на MCP SDK v2, только legacy-эра Streamable HTTP) тоже безопасен: клиент supportBot на MCP SDK v2 автоматически переходит (auto-fallback) на legacy initialize-handshake, если сервер не отвечает на современный протокол 2026-07-28, поэтому инструменты Bedolaga MCP остаются доступны без дополнительной настройки.
This server cannot be deployed
Maintenance
Related MCP Connectors
Non-custodial crypto payments for AI assistants: balances, payments, and create payment links.
Accept crypto payments via the TgPay Merchant API — invoices, subscriptions, webhooks.
Pay-per-use web extract, token prices, and wallet balances via x402 USDC micropayments.
Telegram bridge for your MCP-compatible agent. Bidirectional, no LLM in our stack.
Related MCP Servers
FlicenseNot gradedqualityNot gradedmaintenanceProvides user balance information by connecting to a backend service through the users_balance tool. Built with TypeScript and Express for retrieving financial data.-- AlicenseAqualityAmaintenanceEnables integration with Monobank API to check currency exchange rates, view account balances, and retrieve transaction statements through natural language queries.329 npm9MIT
- AlicenseNot gradedqualityDmaintenanceEnables interaction with Telegram Bot API for sending messages, photos, editing messages, answering callbacks, and fetching updates.MIT
- AlicenseNot gradedqualityBmaintenanceEnables sending Telegram messages, photos, and documents, and retrieving bot information through the Telegram Bot API.23 npm1MIT