Selectel Billing MCP Server
README.md
# Selectel MCP Server
MVP MCP-сервера для получения балансов Selectel через сервисного пользователя.
## Возможности
- Подключение аккаунта Selectel один раз через `.env`, REST API или MCP tool
- Автоматическое обновление токена Selectel (24 часа) без участия пользователя
- MCP tools `connect_selectel_account`, `get_balance` и `get_balance_prediction`
- Audit log всех вызовов MCP tools
## Стек
- Python 3.12+
- FastAPI
- PostgreSQL
- SQLAlchemy 2.x
- Alembic
- Pydantic Settings
- httpx
- MCP (Streamable HTTP transport)
- Docker / Docker Compose
## Структура проекта
```
app/
├── main.py # FastAPI + MCP mount
├── mcp_stdio.py # Stdio entry point для Hermes Agent
├── config.py # Настройки из env
├── db.py # SQLAlchemy engine/session
├── models.py # ORM-модели
├── schemas.py # Pydantic-схемы API
├── selectel_client.py # Клиент Selectel API
├── mcp_tools.py # MCP tools
├── api/
│ └── users.py # REST API подключения аккаунта
├── services/
│ ├── balance_formatter.py
│ └── credentials_service.py
└── tests/
└── test_balance_formatter.py
alembic/ # Миграции БД
Dockerfile
docker-compose.yml
requirements.txt
```
## Быстрый старт
### 1. Создайте `.env`
```bash
cp .env.example .env
```
Заполните учётные данные Selectel (один раз):
```env
DEFAULT_USER_ID=default
SELECTEL_ACCOUNT_ID=12345
SELECTEL_SERVICE_USER_NAME=svc-user
SELECTEL_SERVICE_USER_PASSWORD=your-password
```
При старте сервис сохранит их в БД. Дальше авторизация и обновление токена выполняются автоматически.
### 2. Запуск через Docker Compose
```bash
docker compose up --build
```
Сервисы:
- `app` — http://localhost:8000
- `postgres` — localhost:5432
Миграции применяются автоматически при старте контейнера `app`.
### 3. Локальный запуск (без Docker)
```bash
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# PostgreSQL должен быть доступен
export DATABASE_URL=postgresql://postgres:postgres@localhost:5432/selectel_mcp
alembic upgrade head
uvicorn app.main:app --reload
```
## Одноразовая настройка и автоматическая авторизация
Вы передаёте `account_id`, `service_user_name` и `service_user_password` **один раз**. Сервер:
1. Сохраняет credentials в PostgreSQL
2. Получает токен Selectel (живёт ~24 часа)
3. Кеширует токен в БД
4. Автоматически обновляет токен по логину/паролю из БД, когда он истекает
5. При `401` сбрасывает токен и запрашивает новый без вашего участия
### Способ 1: через `.env` (рекомендуется для одного аккаунта)
```env
DEFAULT_USER_ID=default
SELECTEL_ACCOUNT_ID=12345
SELECTEL_SERVICE_USER_NAME=svc-user
SELECTEL_SERVICE_USER_PASSWORD=your-password
```
### Способ 2: через MCP tool `connect_selectel_account`
```json
{
"account_id": "12345",
"service_user_name": "svc-user",
"service_user_password": "your-password"
}
```
`user_id` опционален, если задан `DEFAULT_USER_ID` в `.env`.
### Способ 3: через REST API
```bash
curl -X POST http://localhost:8000/users/demo-user/selectel-credentials \
-H "Content-Type: application/json" \
-d '{
"account_id": "12345",
"service_user_name": "svc-user",
"service_user_password": "password"
}'
```
После любого из способов достаточно вызывать `get_balance` — без повторной передачи пароля.
## Подключение пользователя (REST API)
```bash
curl -X POST http://localhost:8000/users/demo-user/selectel-credentials \
-H "Content-Type: application/json" \
-d '{
"account_id": "12345",
"service_user_name": "svc-user",
"service_user_password": "password"
}'
```
Логика endpoint:
1. Получает токен Selectel по логину и паролю сервисного пользователя
2. Выполняет тестовый запрос баланса
3. При успехе сохраняет credentials в БД
Возможные ошибки:
- `400` — неверный логин или пароль
- `403` — нет доступа к балансу
- `502` — проблемы с Selectel API
## Подключение в Cursor
1. Запустите сервис: `docker compose up --build`
2. Настройте credentials в `.env` или вызовите `connect_selectel_account` один раз
3. В проекте уже есть `.cursor/mcp.json`:
```json
{
"mcpServers": {
"selectel": {
"url": "http://localhost:8000/mcp"
}
}
}
```
4. Откройте этот проект в Cursor (или добавьте блок `selectel` в `~/.cursor/mcp.json` для всех проектов)
5. **Cursor Settings → Tools & MCP** — убедитесь, что сервер `selectel` в статусе connected (зелёный)
6. Если не подключается — перезапустите Cursor и проверьте `curl http://localhost:8000/health`
В чате можно спросить: «Проверь мой баланс в Selectel» — агент вызовет `get_balance` без передачи пароля.
> Нужен Cursor **0.48+** (поддержка Streamable HTTP).
## Подключение в Hermes Agent
Hermes удобнее подключается через **stdio** — агент сам запускает MCP-процесс, без Docker и PostgreSQL.
### Вариант 1: stdio (рекомендуется)
```bash
git clone https://github.com/EduardGuselnikov/mcp_selectel_billing.git
cd mcp_selectel_billing
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
Добавьте в `~/.hermes/config.yaml`:
```yaml
mcp_servers:
selectel:
command: "/absolute/path/to/mcp_selectel_billing/.venv/bin/python"
args: ["-m", "app.mcp_stdio"]
env:
DATABASE_URL: "sqlite:////Users/you/.hermes/selectel-mcp.db"
DEFAULT_USER_ID: "default"
SELECTEL_ACCOUNT_ID: "12345"
SELECTEL_SERVICE_USER_NAME: "svc-user"
SELECTEL_SERVICE_USER_PASSWORD: "your-password"
tools:
resources: false
prompts: false
```
Или через CLI:
```bash
hermes mcp add selectel \
--command /absolute/path/to/mcp_selectel_billing/.venv/bin/python \
--args -m app.mcp_stdio \
--env DATABASE_URL=sqlite:////Users/you/.hermes/selectel-mcp.db \
--env DEFAULT_USER_ID=default \
--env SELECTEL_ACCOUNT_ID=12345 \
--env SELECTEL_SERVICE_USER_NAME=svc-user \
--env SELECTEL_SERVICE_USER_PASSWORD=your-password
```
Проверка:
```bash
hermes mcp test selectel
hermes mcp list
```
В чате Hermes: «Проверь мой баланс в Selectel».
Готовый манифест для каталога Hermes: `hermes/manifest.yaml`. Примеры конфигурации: `hermes/config.example.yaml`.
### Вариант 2: HTTP (если уже запущен Docker)
```yaml
mcp_servers:
selectel:
url: "http://localhost:8000/mcp"
```
Перед использованием: `docker compose up --build` и credentials в `.env`.
## MCP tools
MCP endpoint: `http://localhost:8000/mcp`
> Открытие `/mcp` в браузере может не показать страницу — это нормально, MCP работает через POST (JSON-RPC), а не через обычный GET.
### `connect_selectel_account` (один раз)
```json
{
"account_id": "12345",
"service_user_name": "svc-user",
"service_user_password": "password"
}
```
### `get_balance`
```json
{}
```
или с явным `user_id`:
```json
{
"user_id": "demo-user"
}
```
Если задан `DEFAULT_USER_ID` в `.env`, `user_id` можно не передавать.
### `get_balance_prediction`
Оценка, на сколько хватит текущего баланса (в часах по категориям услуг). API: `GET /v2/billing/prediction` ([документация Selectel](https://docs.selectel.ru/api/balance/)).
```json
{}
```
Пример ответа:
```
Прогноз: на сколько хватит текущего баланса при текущем потреблении.
• Облачные серверы и основные услуги: 4 дн. 4 ч.
• Объектное хранилище: средств недостаточно
• VMware: 1 дн.
• VPC: 5 ч.
```
Возвращает человекочитаемый текст с балансами по `agreement_id`.
Пример ответа:
```
На аккаунте Selectel найдены балансы в валюте RUB.
ID договора: 263632, тип биллинга: primary
• Бонусный баланс: 36 614,64 ₽
• VK-баланс: 0 ₽
• Основной баланс: 5,14 ₽
Сумма балансов: 36 619,78 ₽
Задолженность: 0 ₽
Итоговый доступный баланс: 36 619,78 ₽
Режим оплаты: prepay
```
## Health check
```bash
curl http://localhost:8000/health
```
## Тесты
```bash
pytest
```
## Переменные окружения
| Переменная | Описание |
|---|---|
| `DATABASE_URL` | URL PostgreSQL |
| `DEFAULT_USER_ID` | Пользователь по умолчанию для `get_balance` |
| `SELECTEL_ACCOUNT_ID` | ID аккаунта Selectel (одноразовая настройка через `.env`) |
| `SELECTEL_SERVICE_USER_NAME` | Логин сервисного пользователя |
| `SELECTEL_SERVICE_USER_PASSWORD` | Пароль сервисного пользователя |
| `SELECTEL_IDENTITY_URL` | URL авторизации Selectel |
| `SELECTEL_BALANCES_URL` | URL API балансов |
| `SELECTEL_BALANCE_PREDICTION_URL` | URL API прогноза баланса |
| `HTTP_TIMEOUT_SECONDS` | Таймаут HTTP-запросов |
## Безопасность
- Авторизация в Selectel выполняется по логину и паролю сервисного пользователя
- Пароли и токены не логируются
- API не возвращает пароль и токен
## Управление токенами Selectel
- Токен Selectel живёт ~24 часа — это ограничение API Selectel, не MCP-сервера
- Сервер кеширует токен в БД и обновляет его автоматически по сохранённому паролю
- Срок кеша: `now() + 23 hours` (запас 1 час до обновления)
- При `401 Unauthorized` токен сбрасывается и запрос повторяется автоматически
- Пользователю не нужно повторно передавать credentials после первоначальной настройки
## Дальнейшее расширение
Архитектура готова к добавлению:
- услуг
- счетов
- расходов
- отчётов
- аналитики
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues