- Python 99.6%
- Shell 0.4%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| bin | ||
| docs | ||
| src/vikunja_mcp | ||
| tests | ||
| .gitignore | ||
| .mcp.json | ||
| pyproject.toml | ||
| README.md | ||
| uv.lock | ||
vikunja-mcp
MCP-сервер к трекеру Vikunja (https://task.dev.lab, v2.4.0). Локальный процесс,
транспорт stdio, один пользователь, один сервер Vikunja.
Установка
uv sync
Токен
Токен создаётся в Vikunja → Настройки → API-токены и кладётся в .env в корне репозитория:
VIKUNJA_API_TOKEN=tk_…
.env в .gitignore. Сам сервер .env не читает — его читает скрипт запуска
bin/vikunja-mcp и передаёт значения процессу через окружение.
| Переменная | Обязательна | Смысл |
|---|---|---|
VIKUNJA_API_TOKEN |
да | токен tk_… |
VIKUNJA_URL |
нет | по умолчанию https://task.dev.lab |
VIKUNJA_CA_BUNDLE |
нет | явный CA, если системного хранилища мало |
VIKUNJA_DEBUG |
нет | 1 — уровень логирования DEBUG и полный стек упавшего инструмента в stderr (stdout занят протоколом) |
В ответ инструмента стек не попадает ни при каком значении VIKUNJA_DEBUG: неожиданная
ошибка возвращается строкой, которая называет инструмент, класс исключения и говорит, где
искать стек.
Без токена сервер не падает при старте: он поднимается и отвечает ошибкой на первый вызов инструмента, называя переменную окружения и место создания токена.
Подключение
Сервер зарегистрирован в .mcp.json этого репозитория: запустите Claude Code
в каталоге проекта и подтвердите подключение сервера vikunja.
Инструменты
list_projects, list_tasks, get_task, create_task, update_task,
complete_task, delete_task (требует confirm=true), add_comment,
list_labels, set_task_labels, vikunja_get (только GET).
Тесты
uv run pytest # контрактные, без сети
set -a; . ./.env; set +a
VIKUNJA_LIVE=1 uv run pytest tests/live -v # живой smoke, создаёт и удаляет пробную задачу
Что известно про сервер Vikunja
docs/API Vikunja.md — карта эндпоинтов, снятая запросами к живому серверу, а не
выведенная из документации. Она определяет архитектуру сервера:
POST /tasks/{id}заменяет объект задачи целиком, а не патчит его. Любая правка — этоGET→ изменить поля →POSTсо всем объектом (read-modify-write). ЧастичныйPOSTобнуляет остальные поля задачи.- TLS: сертификат сервера выдан частным CA без расширения
keyUsage; Python 3.13+ отвергает такой сертификат из-заVERIFY_X509_STRICT. Снимается ровно этот один флаг (ctx.verify_flags &= ~ssl.VERIFY_X509_STRICT), проверка цепочки и имени хоста остаются включёнными. Отключение проверки (verify=False,curl -k) не используется и не нужно. GET /tasks/allотвечает 400 всегда, при любых параметрах и правах токена. «Все задачи» собираются перебором проектов изGET /projects.- HTTP 401 не различает недействительный токен и нехватку прав — сервер отвечает одинаково в обоих случаях, поэтому текст ошибки называет обе причины, а не выдумывает одну.
Живой smoke
Тест в tests/live/test_smoke.py запускается только под VIKUNJA_LIVE=1, ходит на
настоящий сервер и создаёт, читает, закрывает и удаляет пробную задачу в проекте Inbox,
подчищая её за собой даже при падении. Без VIKUNJA_LIVE=1 он пропускается, поэтому
обычный uv run pytest его не запускает.