elba-mcp
# elba-mcp
[](https://github.com/igor-batrakov/elba-mcp/actions/workflows/tests.yml)
[](https://pypi.org/project/elba-mcp/)
MCP-сервер для [Контур.Эльбы](https://e-kontur.ru/): ИИ-ассистент (Claude Code, Claude Desktop, Cursor и
другие MCP-клиенты) находит или заводит клиента, выставляет счёт, акт или УПД, получает публичную ссылку на
документ и следит за оплатами через [публичный API Эльбы](https://developer.kontur.ru/doc/elba.public.api).
Неофициальный проект, с СКБ Контур не связан.
## Установка
Нужен [uv](https://docs.astral.sh/uv/). Ключ API: Эльба → «Настройки и оплата» → «Настройки сервиса» →
«API» → «Выпустить ключ».
Claude Code:
```
claude mcp add --scope user elba -e ELBA_API_KEY=ваш-ключ -- uvx elba-mcp
```
Claude Desktop и другие клиенты с JSON-настройкой:
```json
{
"mcpServers": {
"elba": {
"command": "uvx",
"args": ["elba-mcp"],
"env": { "ELBA_API_KEY": "ваш-ключ" }
}
}
}
```
Из исходников — `uv run --script elba_mcp.py` (зависимости `uv` ставит сам по метаданным скрипта); ключ
тогда можно положить строкой `ELBA_API_KEY=…` в `.env` рядом с `elba_mcp.py`.
Работает на macOS, Linux и Windows; тесты в CI идут на всех трёх.
## Настройки
| Переменная | Что задаёт |
|---|---|
| `ELBA_API_KEY` | ключ API, обязателен |
| `ELBA_ORG_ID` | организация, если по ключу их несколько; иначе берётся единственная |
| `ELBA_STATE_DIR` | каталог журнала счетов, по умолчанию `~/.local/state/elba-mcp` |
## Инструменты
| Инструмент | Что делает |
|---|---|
| `elba_organizations` | организации и банковские счета |
| `elba_templates` | шаблоны документов — `template_id` для счёта и акта |
| `elba_find_contractor` | поиск клиента по ИНН или названию |
| `elba_lookup_inn` | реквизиты организации или ИП по ИНН из ЕГРЮЛ/ЕГРИП ФНС (без ключа) |
| `elba_get_contractor`, `elba_create_contractor` | карточка клиента, новый клиент |
| `elba_create_bill` | счёт: позиции `{name, price, quantity?, unit?}`, без НДС по умолчанию; `project` — метка в журнале |
| `elba_repeat_bill` | новый счёт по образцу прошлого (ежемесячная поддержка) |
| `elba_get_bill` | счёт с суммой `total` и статусом оплаты |
| `elba_track_bill` | добавить в журнал счёт, выставленный не через сервер |
| `elba_unpaid` | неоплаченные счета из журнала со свежими статусами и общий долг |
| `elba_payment_news` | оплаты с прошлой проверки |
| `elba_report` | сводка: выставлено, оплачено, закрыто актами — всего, по проектам, за период |
| `elba_act_from_bill` | акт по счёту: позиции и клиент из счёта, основание «Счёт № от» |
| `elba_create_act` | акт с произвольными позициями |
| `elba_upd_from_bill` | УПД по счёту; счёт с НДС → со счётом-фактурой (статус 1), без НДС → статус 2 |
| `elba_create_upd` | УПД с произвольными позициями; при `with_nds` ставка `nds_rate` обязательна |
| `elba_document_link` | публичная ссылка с печатью, подписью и QR-оплатой — её отправляют клиенту |
| `elba_link_publish` | снять ссылку с публикации (отменённый счёт) или вернуть |
Банковский счёт подставляется сам, если открыт один; при нескольких открытых `bank_account_id` обязателен.
PDF через API Эльбы не скачать — клиент скачивает его по ссылке. Перед первым счётом сверьте текст
шаблона: шаблон-оферта может описывать не тот договор, что ваши услуги.
## Журнал счетов
API Эльбы не отдаёт список счетов, только счёт по id, поэтому сервер ведёт журнал сам: каждый счёт из
`elba_create_bill` записывается туда с клиентом, суммой, проектом, ссылкой, актом и УПД. У каждой
организации свой файл `journal-<id организации>.json`. В журнале данные клиентов — храните его как
бухгалтерские документы.
- Защита от дублей: тому же клиенту на ту же сумму в пределах недели счёт не создаётся без
`allow_duplicate=true`; второй акт или УПД по одному счёту — тоже. Проверка и создание идут под общей
блокировкой, так что параллельные сессии ассистента дубль не создадут.
- Оплаты приходят из ленты новостей Эльбы. Первый вызов `elba_payment_news` только ставит отметку в
конец ленты (у новостей нет дат, история не выводится), дальше — оплаты с прошлого вызова.
- `elba_unpaid` берёт оплаченную часть из всей ленты, статус — из Эльбы. Оплаченные и отменённые
перечитываются, если лента с ними расходится; счёт, восстановленный из отменённых, — `recheck_all=true`.
Долг `null`, если какую-то сумму узнать не удалось.
- Счета, выставленные в Эльбе вручную, в журнал не попадают сами — `elba_track_bill`.
## Сценарии
Готовые сценарии — MCP-промпты: в Claude Code они вызываются как `/mcp__elba__<имя>`, в других клиентах —
из меню промптов. Каждый ведёт ассистента по шагам с проверками и ничего не отправляет клиенту сам:
письма — только черновиками.
| Промпт | Что делает |
|---|---|
| `elba_invoice` (клиент, работы, сумма) | найти или завести клиента, показать счёт на подтверждение, выставить, ссылка, черновик письма |
| `elba_close_work` (счёт, документ) | акт или УПД по счёту, ссылка, черновик письма |
| `elba_remind_debtors` (дней) | что оплачено, кто должен дольше N дней, черновики напоминаний |
Без промптов — обычной фразой:
- «Выстави ООО Ромашка счёт на 40 000 за доработку сайта, проект romashka.ru, и подготовь письмо».
- «Что оплатили? Кто мне должен?» — `elba_payment_news`, `elba_unpaid`.
- «Счёт 114 оплачен — сделай акт и пришли ссылку» — `elba_act_from_bill`, `elba_document_link`.
- «Повтори счёт за поддержку на ноябрь» — `elba_repeat_bill` с новым названием позиции.
- «Сколько выставлено и оплачено по romashka.ru в этом году?» — `elba_report`.
- «Счёт 120 отменили — сними ссылку» — `elba_link_publish`.
Удобнее всего работать из проекта клиента: ассистент там знает, какие работы сделаны, и точнее пишет
позиции счёта и письмо.
## Без MCP, из шелла
```
uvx elba-mcp call elba_find_contractor args.json
```
`args.json` — аргументы инструмента, например `{"inn": "<ИНН клиента>"}`. Пригодится, когда сессия
ассистента запущена до подключения сервера.
## Разработка
Тесты — на моке API, без сети и без ключа, журнал во временном каталоге:
```
uv run pytest -q
```
Релиз: поднять `__version__` в `elba_mcp.py`, закоммитить и отправить тег `vX.Y.Z` — GitHub Actions
прогонит тесты и опубликует пакет на PyPI через Trusted Publishing.
Спецификация API: https://elba-api.kontur.ru/swagger/v1/swagger.json
## Лицензия
MIT, см. [LICENSE](LICENSE).
TDQS
Scored across 19 tools
Most tools have clearly distinct purposes: creation flows are split between from-scratch (elba_create_act/elba_create_upd) and from-bill variants, and contractor find/get/create are distinguishable. The only mild fuzziness is in the reporting cluster (elba_unpaid, elba_report, elba_payment_news, elba_get_bill), which all surface bill/payment status, though descriptions do differentiate list vs aggregate vs news feed vs single bill.
All tools share a consistent elba_ prefix and snake_case, which makes the set easy to scan. Most are verb_noun (create_bill, act_from_bill, find_contractor), but several are bare nouns (organizations, templates, unpaid, report, payment_news), a minor deviation from the pattern.
At 19 tools the set is slightly on the heavy side, but the domain (bills, acts, UPDs, contractors, links, orgs, templates, reporting, INN lookup) legitimately needs this breadth. Each tool maps to a real operation, with no obvious filler.
Creation and read paths are well covered, but mutation is thin: no update/delete for contractors, no update/cancel/delete for bills, and acts/UPDs can be created but not fetched or listed by id. The elba_link_publish description references cancelled bills, yet no cancellation tool exists, which is a notable lifecycle gap.