Vikunja MCP Server — 28 tools
contains code
The Vikunja DADL turns Vikunja's API into an MCP server that Claude, GPT or any MCP-compatible agent can consume directly. One YAML file declares all 28 tools — task, project, bucket, label, view, attachment, and more — and ToolMesh serves them at runtime. No Python boilerplate, no per-endpoint code, no separate MCP server process.
Below: the endpoint coverage matrix, a two-block ToolMesh setup, the full tool reference grouped by Vikunja feature area, required credential scopes.
Source: Vikunja REST API
Which Vikunja endpoints are covered?
35% (28 of ~80 endpoints)
Focus: projects, tasks, views, buckets, labels, comments, positions, filters, attachments
Missing: teams, users, shares, assignees, task relations, reactions, notifications, webhooks, subscriptions, saved filters
How do you configure the Vikunja DADL?
- Log in to the Vikunja web UI
- Open Settings → API Tokens (user menu, top right)
- Click 'Create a token', enter a name and an optional expiry
- Under Permissions grant at least: Projects (read & write), Tasks (read & write), Labels (read & write), Task Comments (read & write)
- Click Create and copy the token immediately — it is shown only once (format: tk_…)
Environment variable: CREDENTIAL_VIKUNJA_API_TOKEN
Vikunja is self-hosted — replace the URL with your instance address, including the /api/v1 suffix. API tokens are shown only once at creation and their granted permissions cap what these tools can do (a read-only token returns 403 on create/update/delete).
How do you install the Vikunja MCP server with ToolMesh?
Add to your backends.yaml:
- name: vikunja
transport: rest
dadl: vikunja.dadl
url: "https://your-vikunja-instance.com/api/v1"
Set the credential:
CREDENTIAL_VIKUNJA_API_TOKEN=your-token-here What 28 tools does the Vikunja DADL expose?
POST set_task_position Set task position (sort order) within a project view. The position is a float64 value — use values between existing tasks to insert. GET list_project_tasks List all tasks in a project view. Use view_id from list_views. Supports sorting by position, due_date, created, etc. Kanban views return buckets with nested tasks, not a flat list. GET list_tasks Query tasks across ALL projects the user can access (not scoped to a single view). Supports the Vikunja filter DSL, full-text search (s) and multi-field sorting — the best endpoint for analytics/reporting (velocity, ETA, throughput): filter or sort by done_at, created, updated, due_date, percent_done. Returns a flat task array.
GET get_task Get a single task by its ID, including all details, assignees, labels, and relations. PUT _create_task_raw Internal: raw task creation (leaves the new card at kanban position 0, i.e. the top of the board). Use the create_task composite, which appends it to the end of its bucket. POST _update_task_raw Internal: raw task update (sends full object). Use the update_task composite instead. POST move_task_to_bucket Move a task to a different kanban bucket. Use list_buckets to get bucket IDs. This is the only way to move tasks between kanban columns. DELETE delete_task Permanently delete a task. GET list_task_attachments List all attachments on a task (metadata only: attachment id, uploader, and file name/mime/size). Use download_task_attachment to fetch the bytes. PUT upload_task_attachment Upload a file as an attachment to a task. ToolMesh fetches the given URL and uploads the bytes to Vikunja as the multipart form field "files". Returns the created attachment together with its stored file metadata.
GET download_task_attachment Download one task attachment. Returns a ToolMesh file-broker URL (file_url) to fetch the bytes, not the raw binary. For image attachments, pass preview_size to get a scaled preview instead of the original.
DELETE delete_task_attachment Permanently delete a task attachment. GET list_projects List all projects accessible to the authenticated user. Projection now also includes parent_project_id and position (hierarchy + ordering), plus hex_color and owner (username). GET get_project Get a single project by ID. PUT create_project Create a new project. Only 'title' is required. Set parent_project_id to nest it under another project (hierarchy). 'identifier' (≤10 chars) is the short prefix used to build task identifiers (e.g. OPS-1); omit to auto-derive. hex_color is a 6-digit hex string without a leading '#'.
POST _update_project_raw Internal: raw project update (sends a full object — omitted fields are reset to zero). Use the update_project composite instead. DELETE delete_project Permanently delete a project and all of its tasks, views and buckets. Irreversible. Verify the project_id with get_project first. (There is no delete for labels — those must be removed in the Vikunja UI.)
GET list_views List all views (list, kanban, gantt, table) for a project. Each view has its own task positions. Call this first to get view_id for list_project_tasks. GET list_buckets List all kanban buckets for a project view. Returns bucket id, title, and task count. Use move_task_to_bucket to move tasks between columns. PUT create_bucket Create a new kanban bucket in a project view. POST update_bucket Rename a kanban bucket, set its WIP task limit, or set its position (column order — lower position is further left). title is required (Vikunja rejects an empty title); limit 0 means no limit. Sends a full bucket object, so pass the current title/limit when changing only one field (set_bucket_position does this for you). Which bucket is the DEFAULT or DONE bucket is a view property — use set_default_bucket for that, not this.
DELETE delete_bucket Permanently delete a kanban bucket. Its tasks are not deleted — they fall back to the view's default bucket. POST _update_view_raw Internal: raw project-view update. Vikunja replaces the full view object, so omitted fields reset to zero — use the set_default_bucket composite, which reads the current view and preserves the rest. GET list_labels List all labels the user has access to. Returns id, title, description, hex_color. PUT create_label Create a new label. NOTE: Vikunja creates labels with PUT (not POST). 'title' is required. hex_color is a 6-digit hex string without a leading '#'. Useful for setting up reusable S/M/L estimate labels.
PUT add_label_to_task Add a label to a task. GET list_task_comments List all comments on a task. PUT create_task_comment Add a comment to a task. What composite workflows does the Vikunja DADL provide? ⚠ contains code
FN update_task Update an existing task. Only include the fields you want to change — unchanged fields are preserved (GET → merge → POST). Set project_id to MOVE the task to another project (its identifier is reassigned on move — reference by global id afterwards). To move between kanban buckets, use move_task_to_bucket instead.
FN create_task Create a task in a project and append it to the END of its kanban bucket (max position + step), server-side, so API-created tasks do not jump to the top of the board and disturb the priority order (board order = priority). Pass bucket_id to place it into a specific kanban bucket; omit to use the view's default bucket. Priority: 0=unset, 1=low, 2=medium, 3=high, 4=urgent, 5=critical.
FN set_default_bucket Set which kanban bucket is the DEFAULT (where new tasks land) and, optionally, the DONE bucket (moving a task there marks it done) for a project view. Reads the current view first and preserves its title, kind, filter and layout, so only the bucket assignments change. Get view_id from list_views (the kanban view) and bucket IDs from list_buckets.
FN set_bucket_position Reorder a kanban bucket (column) within its view. Pass an explicit position (float64, lower = further left), or place 'first' / 'last' to compute one from the sibling buckets (first = min/2, last = max + step). Reads the bucket first so its title and WIP limit are preserved (the raw bucket update would otherwise need them). Use this to move an Inbox column to the very left.
FN update_project Update an existing project. Only include the fields you want to change — unchanged fields are preserved (this composite does GET → merge → POST, because Vikunja's raw project update resets omitted fields). Set parent_project_id to re-parent (0 = top-level). To create a project use create_project.