MCP-cервер к vikunja
mcp
  • Python 99.6%
  • Shell 0.4%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-08-17 09:36:39 +03:00
bin feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
docs feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
src/vikunja_mcp feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
tests feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
.gitignore feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
.mcp.json feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
pyproject.toml feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
README.md feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00
uv.lock feat-vikunja-mcp (#1) 2026-08-17 09:36:39 +03:00

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 его не запускает.