Model Context Protocol server for Vikunja task management. Enables AI assistants to interact with Vikunja instances via MCP.
Vikunja MCP Server
A Model Context Protocol (MCP) server that enables AI assistants to interact with Vikunja task management instances.
Features
- Subcommand-based tools for intuitive AI interactions
- Session-based authentication with automatic token management
- Full task management operations implemented
- Complete project management with CRUD operations
- Label management for organizing tasks
- Team operations for collaboration (get/update/members limited by API)
- User management with settings and search
- Webhook management for project automation
- Batch import tasks from CSV or JSON files
- Input validation for dates, IDs, and hex colors
- Efficient diff-based updates for assignees
- TypeScript with strict mode for type safety
- Comprehensive error handling with typed errors
- Automatic retry logic with exponential backoff for transient failures
Requirements
- Node.js 20+ (LTS versions only)
- Vikunja instance with API access
- API token (starting with
tk_
) or JWT token for authentication
Installation
Option 1: Install from NPM (Recommended)
The easiest way to use vikunja-mcp is through npx in your Claude Desktop or other MCP-compatible client configuration:
{
"vikunja": {
"command": "npx",
"args": ["-y", "@democratize-technology/vikunja-mcp"],
"env": {
"VIKUNJA_URL": "https://your-vikunja-instance.com/api/v1",
"VIKUNJA_API_TOKEN": "your-api-token"
}
}
}
Option 2: Local Development
For development or customization:
git clone https://github.com/democratize-technology/vikunja-mcp.git
cd vikunja-mcp
npm install
npm run build
Then configure your MCP client:
{
"vikunja": {
"command": "node",
"args": ["/path/to/vikunja-mcp/dist/index.js"],
"env": {
"VIKUNJA_URL": "https://your-vikunja-instance.com/api/v1",
"VIKUNJA_API_TOKEN": "your-api-token"
}
}
}
Configuration
Logging Configuration
The server includes a structured logging system. Configure it via environment variables:
# Enable debug logging (default: false)
DEBUG=true
# Set specific log level (error, warn, info, debug)
# If not set, defaults to 'info' (or 'debug' if DEBUG=true)
LOG_LEVEL=debug
Log output includes timestamps and log levels:
[2025-05-25T17:00:00.000Z] [INFO] Vikunja MCP server started
[2025-05-25T17:00:00.100Z] [DEBUG] Executing tasks tool { subcommand: 'list', args: {...} }
All logs are written to stderr to keep stdout reserved for MCP protocol communication.
Authentication Methods
The Vikunja MCP server supports two authentication methods, each with different capabilities:
API Token Authentication (Default)
API tokens are the standard authentication method for Vikunja:
- How to obtain: Go to Vikunja Settings → API Tokens → Create new token
- Token format: Starts with
tk_
(e.g.,tk_abc123def456
) - Capabilities: Full access to tasks, projects, labels, teams, and webhooks
- Limitations: Cannot access user-specific endpoints (user profile, settings, export)
- Best for: Automation, CI/CD, and general task management
JWT Authentication (Advanced)
JWT (JSON Web Token) authentication provides full access to all Vikunja endpoints:
- How to obtain: Extract from your browser session (see instructions below)
- Token format: Long string starting with
eyJ
(standard JWT format) - Capabilities: Full access to all endpoints including user management and export
- Limitations: Tokens expire (typically after 24 hours)
- Best for: User management, data export, and operations requiring user context
How to Extract Your JWT Token
- Log into Vikunja in your web browser
- Open Developer Tools (F12 or right-click → Inspect)
- Go to the Application/Storage tab
- Find the JWT token:
- Look in Local Storage → your Vikunja domain
- Find the key named
token
or similar - The value is your JWT token
- Copy the entire token value (it's quite long)
Using JWT Authentication
// Connect with JWT token - automatically detected!
vikunja_auth.connect({
apiUrl: "https://your-vikunja-instance.com/api/v1",
apiToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
})
Important Notes:
- JWT tokens expire; you'll need to extract a new one when it expires
- Token type is automatically detected based on format (no flag needed)
- Some tools (users, export) are only available with JWT authentication
Quick Start
-
Set up authentication (if not using environment variables):
vikunja_auth.connect({ apiUrl: "https://your-vikunja-instance.com/api/v1", apiToken: "your-api-token" })
-
Create your first task:
vikunja_tasks.create({ projectId: 1, title: "My first task via MCP!" })
-
List all your tasks:
vikunja_tasks.list({ allProjects: true })
Usage
The MCP server exposes tools with subcommands. All operations require authentication first (either via environment variables or manual connection).
Authentication
// Connect with API token (automatically detected)
vikunja_auth.connect({
apiUrl: "https://your-vikunja-instance.com/api/v1",
apiToken: "tk_your-api-token"
})
// Connect with JWT token (automatically detected, enables additional tools: users, export)
vikunja_auth.connect({
apiUrl: "https://your-vikunja-instance.com/api/v1",
apiToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
})
// Check authentication status
vikunja_auth.status()
// Disconnect and clean up resources
vikunja_auth.disconnect()
Task Management Examples
// List all tasks across all projects
vikunja_tasks.list({ allProjects: true })
// List tasks for a specific project with pagination
vikunja_tasks.list({
projectId: 1,
page: 1,
perPage: 20,
sort: "due_date"
})
// List tasks with filters (high priority, not done)
vikunja_tasks.list({
filter: "(priority >= 4 && done = false)"
})
// List tasks with simple filter
vikunja_tasks.list({
filter: "priority >= 3"
})
// List tasks with complex filter conditions
vikunja_tasks.list({
filter: "(priority >= 3 && priority <= 5) || (done = true && updated > '2024-01-01')"
})
// Combine filter with search
vikunja_tasks.list({
filter: "priority >= 4",
search: "urgent"
})
// Create a new task with labels and assignees
vikunja_tasks.create({
projectId: 1,
title: "Complete documentation",
description: "Update README with examples",
dueDate: "2024-12-31T23:59:59Z",
priority: 3,
labels: [1, 2], // Label IDs
assignees: [1, 3] // User IDs
})
// Create a recurring task (repeats every week)
vikunja_tasks.create({
projectId: 1,
title: "Weekly team meeting",
description: "Sync up with the team",
dueDate: "2024-12-01T10:00:00Z",
repeatAfter: 7, // Number of units
repeatMode: "day" // Unit: "day", "week", "month", or "year"
})
// Create a monthly recurring task
vikunja_tasks.create({
projectId: 1,
title: "Monthly report",
repeatAfter: 1,
repeatMode: "month"
})
// Get detailed information about a task
vikunja_tasks.get({ id: 123 })
// Update a task (partial updates supported)
vikunja_tasks.update({
id: 123,
done: true,
priority: 5
})
// Update recurring settings on an existing task
vikunja_tasks.update({
id: 123,
repeatAfter: 14, // Change to bi-weekly
repeatMode: "day"
})
// Update task assignees (uses efficient diff-based approach)
vikunja_tasks.update({
id: 123,
assignees: [1, 2, 4] // Only adds/removes differences
})
// Delete a task
vikunja_tasks.delete({ id: 123 })
// Bulk assign users to a task
vikunja_tasks.assign({
id: 123,
assignees: [2, 3, 4]
})
// Remove users from a task
vikunja_tasks.unassign({
id: 123,
assignees: [2, 4] // Removes only these users
})
// List all assignees for a task
vikunja_tasks.list-assignees({ id: 123 })
// Add a comment to a task
vikunja_tasks.comment({
id: 123,
comment: "This task is now complete!"
})
// List all comments on a task
vikunja_tasks.comment({ id: 123 })
// Create a task relation (e.g., subtask, blocking, related)
vikunja_tasks.relate({
id: 123,
otherTaskId: 124,
relationKind: "subtask" // 124 is a subtask of 123
})
// Available relation kinds:
// - subtask: Other task is a subtask of this task
// - parenttask: Other task is the parent of this task
// - related: Tasks are related
// - duplicateof: This task is a duplicate of the other
// - duplicates: Other task is a duplicate of this one
// - blocking: This task blocks the other
// - blocked: This task is blocked by the other
// - precedes: This task precedes the other
// - follows: This task follows the other
// - copiedfrom: This task was copied from the other
// - copiedto: Other task was copied from this one
// Remove a task relation
vikunja_tasks.unrelate({
id: 123,
otherTaskId: 124,
relationKind: "subtask"
})
// Get all relations for a task
vikunja_tasks.relations({ id: 123 })
// Add a reminder to a task
vikunja_tasks.add-reminder({
id: 123,
reminderDate: "2024-12-25T10:00:00Z"
})
// List all reminders for a task
vikunja_tasks.list-reminders({ id: 123 })
// Remove a specific reminder from a task
vikunja_tasks.remove-reminder({
id: 123,
reminderId: 1
})
// Bulk create multiple tasks at once (max 100)
vikunja_tasks.bulk-create({
projectId: 1,
tasks: [
{
title: "Task 1",
description: "First task",
priority: 3,
labels: [1, 2]
},
{
title: "Task 2",
dueDate: "2024-12-31T23:59:59Z",
assignees: [1]
},
{
title: "Weekly standup",
repeatAfter: 7,
repeatMode: "day"
}
]
})
// Bulk update multiple tasks with the same field value
vikunja_tasks.bulk-update({
taskIds: [123, 124, 125],
field: "done", // Field to update
value: true // New value for all tasks
})
// Other bulk update examples
vikunja_tasks.bulk-update({
taskIds: [123, 124, 125],
field: "priority",
value: 5
})
vikunja_tasks.bulk-update({
taskIds: [123, 124],
field: "project_id",
value: 2 // Move tasks to different project
})
vikunja_tasks.bulk-update({
taskIds: [123, 124, 125],
field: "labels",
value: [1, 3, 5] // Set same labels on all tasks
})
// Bulk delete multiple tasks (max 100)
vikunja_tasks.bulk-delete({
taskIds: [123, 124, 125]
})
// Batch import tasks from CSV or JSON
vikunja_batch_import({
projectId: 1,
format: "json",
data: JSON.stringify([
{
title: "Task 1",
description: "First imported task",
priority: 3,
dueDate: "2024-12-31T23:59:59Z"
},
{
title: "Task 2",
labels: ["bug", "urgent"], // Will look up label IDs by name
assignees: ["john.doe"] // Will look up user IDs by username
}
])
})
// Import from CSV with headers
vikunja_batch_import({
projectId: 1,
format: "csv",
data: `title,description,priority,dueDate,labels,assignees
"Task 1","Description with, comma",3,2024-12-31T23:59:59Z,"bug;feature","john.doe"
"Task 2","Another task",5,,"urgent","john.doe;jane.smith"`
})
// Dry run to validate without creating tasks
vikunja_batch_import({
projectId: 1,
format: "json",
data: JSON.stringify([...]),
dryRun: true // Only validates, doesn't create tasks
})
// Continue on errors instead of stopping
vikunja_batch_import({
projectId: 1,
format: "csv",
data: csvData,
skipErrors: true // Skip invalid tasks and continue with valid ones
})
Data Export Examples
// Export a project with all its data
vikunja_export_project({
projectId: 1,
includeChildren: false // Only export the specified project
})
// Export a project including all child projects
vikunja_export_project({
projectId: 1,
includeChildren: true // Recursively export child projects
})
// The export returns JSON data with the following structure:
// {
// project: { ... }, // Project details
// tasks: [ ... ], // All tasks in the project
// labels: [ ... ], // All labels used in tasks
// child_projects: [ ... ], // Nested child project exports (if includeChildren: true)
// exported_at: "...", // ISO timestamp of export
// version: "1.0.0" // Export format version
// }
// Request a full user data export (sent via email)
vikunja_request_user_export({
password: "your-password" // Required for security
})
// Download a previously requested user data export
vikunja_download_user_export({
password: "your-password" // Required for security
})
Project Management Examples
// List all projects
vikunja_projects.list()
// List projects with search and pagination
vikunja_projects.list({
search: "frontend",
page: 1,
perPage: 10,
isArchived: false
})
// Get a specific project
vikunja_projects.get({ id: 1 })
// Create a new project
vikunja_projects.create({
title: "New Frontend Project",
description: "React-based web application",
hexColor: "#4287f5"
})
// Update a project
vikunja_projects.update({
id: 1,
title: "Updated Project Name",
isArchived: true
})
// Archive a project
vikunja_projects.archive({ id: 1 })
// Unarchive a project
vikunja_projects.unarchive({ id: 1 })
// Delete a project
vikunja_projects.delete({ id: 1 })
// --- Project Hierarchy Management ---
// Create a child project
vikunja_projects.create({
title: "Frontend Module",
description: "React components",
parentProjectId: 1, // Will be a child of project 1
hexColor: "#3498db"
})
// Get all direct children of a project
vikunja_projects.get-children({ id: 1 })
// Returns: Array of projects that have parentProjectId = 1
// Get complete project hierarchy as a tree
vikunja_projects.get-tree({ id: 1 })
// Returns: Project with nested children structure
// {
// id: 1,
// title: "Main Project",
// children: [
// {
// id: 2,
// title: "Frontend Module",
// children: [
// { id: 4, title: "Components", children: [] },
// { id: 5, title: "Styles", children: [] }
// ]
// },
// {
// id: 3,
// title: "Backend Module",
// children: []
// }
// ]
// }
// Get breadcrumb path from root to a project
vikunja_projects.get-breadcrumb({ id: 5 })
// Returns: Array of projects from root to target
// [
// { id: 1, title: "Main Project" },
// { id: 2, title: "Frontend Module" },
// { id: 5, title: "Styles" }
// ]
// Also includes a formatted path: "Main Project > Frontend Module > Styles"
// Move a project to a new parent
vikunja_projects.move({
id: 5, // Project to move
parentProjectId: 3 // New parent
})
// Validates against circular references and depth limits
// Move a project to root level (no parent)
vikunja_projects.move({
id: 5,
parentProjectId: undefined
})
// --- Project Sharing ---
// Create a read-only share link
vikunja_projects.create-share({
id: 1,
right: 0, // 0=Read, 1=Write, 2=Admin
label: "Public read-only access"
})
// Create a password-protected share with write access
vikunja_projects.create-share({
id: 1,
right: 1,
password: "securepassword123",
label: "Team collaboration link"
})
// Create an expiring share link
vikunja_projects.create-share({
id: 1,
right: 0,
expires: "2025-12-31T23:59:59Z",
label: "Temporary access until year end"
})
// List all shares for a project
vikunja_projects.list-shares({ id: 1 })
// Get details of a specific share
vikunja_projects.get-share({
id: 1,
shareId: 123
})
// Delete a share link
vikunja_projects.delete-share({
id: 1,
shareId: 123
})
// Authenticate to access a shared project
vikunja_projects.auth-share({
shareHash: "abc123def456"
})
// Authenticate to a password-protected share
vikunja_projects.auth-share({
shareHash: "abc123def456",
password: "securepassword123"
})
Label Management Examples
// List all labels
vikunja_labels.list()
// Search for labels
vikunja_labels.list({
search: "bug",
page: 1,
perPage: 20
})
// Get a specific label
vikunja_labels.get({ id: 1 })
// Create a new label
vikunja_labels.create({
title: "Critical",
description: "Critical priority issues",
hexColor: "#ff0000"
})
// Update a label
vikunja_labels.update({
id: 1,
title: "High Priority",
hexColor: "#ff6600"
})
// Delete a label
vikunja_labels.delete({ id: 1 })
Team Management Examples
// List all teams
vikunja_teams.list()
// Search for teams
vikunja_teams.list({
search: "frontend",
page: 1,
perPage: 10
})
// Create a new team
vikunja_teams.create({
name: "Frontend Team",
description: "Responsible for UI/UX development"
})
// Delete a team
vikunja_teams.delete({ id: 1 })
// Note: get, update, and members operations are not yet
// implemented in the node-vikunja library
User Management Examples
⚠️ Known Issue: User endpoints may fail with authentication errors even when using valid tokens. This is a known Vikunja API issue. The MCP server will provide helpful error messages when this occurs. If you encounter this issue, please contact your Vikunja server administrator.
// Get current user information
vikunja_users.current()
// Search for users
vikunja_users.search({
search: "john"
})
// Get current user settings
vikunja_users.settings()
// Update user settings
vikunja_users.update-settings({
name: "John Doe",
language: "en",
timezone: "America/New_York",
weekStart: 1 // Monday
})
// Update notification preferences
vikunja_users.update-settings({
emailRemindersEnabled: true, // Enable email reminders for tasks
overdueTasksRemindersEnabled: true, // Enable daily overdue task emails
overdueTasksRemindersTime: "09:00" // Time to send overdue task summary
})
Webhook Management Examples
// List all available webhook events
vikunja_webhooks.list-events()
// Returns: ["task.created", "task.updated", "task.deleted", "task.assigned", ...]
// List webhooks for a project
vikunja_webhooks.list({ projectId: 1 })
// Create a webhook for task events
vikunja_webhooks.create({
projectId: 1,
targetUrl: "https://example.com/webhook",
events: ["task.created", "task.updated"],
secret: "my-secret-key" // Optional, for HMAC signing
})
// Create a webhook without secret
vikunja_webhooks.create({
projectId: 1,
targetUrl: "https://example.com/notifications",
events: ["task.assigned", "task.comment.created"]
})
// Get a specific webhook
vikunja_webhooks.get({
projectId: 1,
webhookId: 123
})
// Update webhook events
vikunja_webhooks.update({
projectId: 1,
webhookId: 123,
events: ["task.created", "task.updated", "task.deleted"]
})
// Delete a webhook
vikunja_webhooks.delete({
projectId: 1,
webhookId: 123
})
Advanced Filtering Examples
// Create a saved filter for high priority tasks
vikunja_filters.create({
name: "High Priority Tasks",
description: "All undone tasks with priority 4 or 5",
filter: "done = false && priority >= 4",
isGlobal: true
})
// Alternative format using title and filters object
vikunja_filters.create({
title: "🔥 High Priority Tasks",
description: "All tasks with priority 4 or 5 that are not completed",
filters: {
filter_by: ["priority"],
filter_value: ["5"],
filter_comparator: [">="],
filter_concat: ""
},
is_favorite: true
})
// Create a filter with multiple conditions
vikunja_filters.create({
title: "Urgent & Incomplete",
filters: {
filter_by: ["priority", "done"],
filter_value: ["3", "false"],
filter_comparator: [">=", "="],
filter_concat: "&&"
}
})
// Create a project-specific filter
vikunja_filters.create({
name: "This Week's Tasks",
filter: "dueDate >= now && dueDate < now+7d",
projectId: 1,
isGlobal: false
})
// List all saved filters
vikunja_filters.list()
// List filters for a specific project
vikunja_filters.list({ projectId: 1 })
// Apply a saved filter to task listing
vikunja_tasks.list({
filterId: "550e8400-e29b-41d4-a716-446655440000"
})
// Build a filter programmatically
vikunja_filters.build({
conditions: [
{ field: "done", operator: "=", value: false },
{ field: "priority", operator: ">=", value: 3 },
{ field: "assignees", operator: "in", value: ["user1", "user2"] }
],
groupOperator: "&&"
})
// Returns: { filter: "(done = false && priority >= 3 && assignees in user1, user2)", valid: true }
// Update an existing filter
vikunja_filters.update({
id: "550e8400-e29b-41d4-a716-446655440000",
name: "Critical Tasks",
filter: "done = false && priority = 5"
})
// Validate a filter string
vikunja_filters.validate({
filter: "done = false && priority >= 3"
})
// Returns: { valid: true, errors: [] }
Filter Syntax Reference
The Vikunja filter syntax supports SQL-like queries with the following:
Fields:
done
- Task completion status (boolean)priority
- Task priority (1-5)percentDone
- Completion percentage (0-100)dueDate
- Task due dateassignees
- Task assigneeslabels
- Associated labelscreated
- Task creation timeupdated
- Task update time
Operators:
- Comparison:
=
,!=
,>
,>=
,<
,<=
- Pattern matching:
like
(uses%
wildcard) - List matching:
in
,not in
Date Math:
now
- Current timenow+24h
- 24 hours from nownow-7d
- 7 days agonow/d
- Start of current day- Supports: s (seconds), m (minutes), h (hours), d (days), w (weeks), M (months), y (years)
Examples:
priority = 4
dueDate < now
done = false && priority >= 3
assignees in user1, user2
dueDate >= now && dueDate < now+7d
title like "%urgent%"
Important Note on Filtering: Due to a known limitation in Vikunja v0.22.1 where the server ignores filter parameters, this MCP server implements client-side filtering as a workaround. When you use filters:
- All tasks are fetched from the server first
- Filters are then applied locally using the same syntax
- The response will include
clientSideFiltering: true
in metadata - This may impact performance for projects with many tasks
- All filter features work correctly, just processed client-side
Response Format
All operations in the Vikunja MCP server follow a standardized response format for consistency and predictability:
interface StandardResponse {
success: boolean;
operation: string; // The operation performed (e.g., 'create', 'update', 'list')
message?: string; // Human-readable description of the result
data?: any; // The primary data returned (task, project, label, etc.)
metadata?: {
timestamp: string; // ISO 8601 timestamp of the operation
[key: string]: any; // Additional operation-specific metadata
};
}
Response Examples
Success:
{
"success": true,
"operation": "create",
"message": "Task created successfully",
"data": { "id": 123, "title": "Complete documentation" },
"metadata": { "timestamp": "2025-05-25T12:00:00Z" }
}
Error:
{
"success": false,
"operation": "update",
"message": "Task not found",
"error": { "code": "TASK_NOT_FOUND", "details": "No task exists with ID 999" }
}
This standardized format ensures:
- Consistency: All tools return responses in the same structure
- Predictability: Clients always know what fields to expect
- Debugging: Metadata provides context for troubleshooting
- Error Handling: Clear error information with codes and messages
Available Tools
Authentication
vikunja_auth
- Authentication managementconnect
- Initialize connection with API tokenstatus
- Check authentication statusrefresh
- Refresh authentication token
Task Management ✅
vikunja_tasks
- Task operations (fully implemented)list
- List tasks with filters- Filter by project or get all tasks
- Support for pagination, search, sorting
- Filter by completion status
- Apply saved filters with
filterId
parameter
create
- Create a new task- Required: title, projectId
- Optional: description, dueDate, priority, labels, assignees
- Validates date format (ISO 8601) and IDs
get
- Get task details by IDupdate
- Update existing task- Supports partial updates
- Can update title, description, dueDate, priority, done status
- Can update labels and assignees (uses efficient diff-based approach)
delete
- Delete a task by IDassign
- Bulk assign users to tasksunassign
- Remove users from taskscomment
- List or add comments to tasksbulk-update
- Update multiple tasks at once- Required: taskIds array, field name, value
- Supported fields: done, priority, due_date, project_id, assignees, labels
- Validates field types and values
- ⚠️ Performance: Makes API calls to fetch each updated task
bulk-delete
- Delete multiple tasks at once- Required: taskIds array
- Returns deleted task details for confirmation
- Handles partial failures gracefully
- ⚠️ Performance: Makes individual delete calls for each task
- Recommended: Process in batches of 20 or fewer tasks
attach
- Not implemented (file handling not available in MCP)
Batch Import ✅
vikunja_batch_import
- Import multiple tasks from CSV or JSON (fully implemented)- Required: projectId, format ('csv' or 'json'), data
- Optional: skipErrors (continue on errors), dryRun (validate only)
- Batch Size Limit: Maximum 100 tasks per import
- CSV Format:
- Requires header row with field names
- Supports quoted values and escaped quotes
- Fields: title, description, priority, dueDate, labels, assignees
- Labels and assignees as semicolon-separated values (semicolons used to avoid conflicts with CSV commas)
- JSON Format:
- Array of task objects
- Same fields as CSV, plus direct support for arrays
- Features:
- Automatic label lookup by name
- Automatic user lookup by username
- Validation before creation
- Detailed error reporting
- Dry run mode for testing
- Skip errors option for partial imports
Project Management ✅
vikunja_projects
- Project operations (fully implemented)list
- List all projects with filters- Support for pagination and search
- Filter by archived status
get
- Get project details by IDcreate
- Create new project- Required: title
- Optional: description, parentProjectId, isArchived, hexColor (format: #RRGGBB)
- Validates parent project hierarchy depth (max 10 levels)
update
- Update existing project- Supports partial updates
- Can update all project fields including hexColor (format: #RRGGBB)
- Validates parent project hierarchy depth when changing parent
delete
- Delete a project by IDarchive
- Archive a projectunarchive
- Unarchive a project- Hierarchy Management (New!)
get-children
- List direct children of a projectget-tree
- Get complete project hierarchy as a treeget-breadcrumb
- Get path from root to a projectmove
- Move a project to a new parent- Validates against circular references
- Enforces maximum depth of 10 levels
- Project Sharing
create-share
- Create share link with permissionslist-shares
- List all shares for a projectget-share
- Get share detailsdelete-share
- Remove a share linkauth-share
- Authenticate to access a shared project
Label Management ✅
vikunja_labels
- Label operations (fully implemented)list
- List all labels with filters- Support for pagination and search
get
- Get label details by IDcreate
- Create new label- Required: title
- Optional: description, hexColor (format: #RRGGBB)
update
- Update existing label- Supports partial updates
- Can update title, description, hexColor
delete
- Delete a label by ID
Project Templates ✅
vikunja_templates
- Template operations (fully implemented)create
- Create a template from existing project- Required: projectId, name
- Optional: description, tags
- Captures all project settings and tasks
list
- List all available templates- Shows template name, tags, and author
get
- Get template details by IDupdate
- Update template metadata- Can update name, description, tags
delete
- Delete a templateinstantiate
- Create new project from template- Required: id (template ID), projectName
- Optional: parentProjectId, variables
- Supports variable substitution:
{{PROJECT_NAME}}
- The new project name{{TODAY}}
- Current date (YYYY-MM-DD){{NOW}}
- Current timestamp- Custom variables via the variables parameter
- Creates all tasks with labels from template
Team Management ✅
vikunja_teams
- Team operations (partially implemented)list
- List all teams with filters- Support for pagination and search
create
- Create new team- Required: name
- Optional: description
delete
- Delete a team by ID (with fallback API support)get
- Not yet implemented in node-vikunjaupdate
- Not yet implemented in node-vikunjamembers
- Not yet implemented in node-vikunja
User Management ✅
vikunja_users
- User operations (fully implemented) [Requires JWT authentication]current
- Get current authenticated user infosearch
- Search for users- Optional: search query, pagination
settings
- Get current user settingsupdate-settings
- Update user settings- Optional: name, language, timezone, weekStart, frontendSettings
- Note: User operations require JWT authentication. When using API token authentication, these tools will not be available.
Webhook Management ✅
-
vikunja_webhooks
- Webhook operations for project automation (fully implemented)list-events
- Get all available webhook event typeslist
- List webhooks for a project- Required: projectId
get
- Get a specific webhook- Required: projectId, webhookId
create
- Create a new webhook- Required: projectId, targetUrl, events (array)
- Optional: secret (for HMAC signing)
- Note: Events are validated against available event types
update
- Update webhook events- Required: projectId, webhookId, events (array)
- Note: Events are validated against available event types
delete
- Delete a webhook- Required: projectId, webhookId
Event Validation: When creating or updating webhooks, the provided events are automatically validated against the list of available events from the API. Invalid events will result in a clear error message showing which events are invalid and listing all valid options. Valid events are cached for 5 minutes to improve performance.
Filter Management ✅
-
vikunja_filters
- Advanced filtering for tasks (fully implemented)list
- List saved filters- Optional: projectId (for project-specific filters), global flag
get
- Get a specific filter by IDcreate
- Create a new saved filter- Required: name, filter (query string)
- Optional: description, projectId, isGlobal
update
- Update an existing filter- Required: id
- Optional: name, description, filter, projectId, isGlobal
delete
- Delete a saved filterbuild
- Build a filter string from conditions- Required: conditions array
- Optional: groupOperator (&&, ||)
validate
- Validate a filter string
Note: Saved filters are currently stored in memory and will be lost when the MCP server restarts. For production use, consider implementing persistent storage.
Data Export ✅
⚠️ WARNING: Memory Usage
Export operations load entire project hierarchies into memory. For very large projects with thousands of tasks or deeply nested structures, this may consume significant memory. Consider exporting smaller projects individually.
-
vikunja_export_project
- Export project data [Requires JWT authentication]- Parameters:
projectId
(required) - ID of the project to exportincludeChildren
(optional) - Include child projects recursively (default: false)
- Returns: Complete project data including tasks, labels, and metadata
- Features:
- Exports all tasks with full details
- Includes all labels used in the project
- Optionally includes complete child project hierarchy
- Circular reference detection for nested projects
- Export metadata includes timestamp and version
- Note: Export operations require JWT authentication. When using API token authentication, this tool will not be available.
- Parameters:
-
vikunja_request_user_export
- Request full user data export- Parameters:
password
(required) - User password for security verification
- Returns: Confirmation that export has been requested
- Note: You will receive an email when the export is ready
- Parameters:
-
vikunja_download_user_export
- Download previously requested user data export- Parameters:
password
(required) - User password for security verification
- Returns: Complete user data export
- Note: Export must be requested first via
vikunja_request_user_export
- Parameters:
Known Limitations
- File Attachments: The
attach
subcommand is not implemented due to MCP protocol limitations - Team Operations: Limited functionality due to incomplete node-vikunja API support:
- Cannot get team by ID
- Cannot update team information
- Cannot delete teams
- Cannot manage team members
- Pagination: Some endpoints may not fully support pagination parameters due to API limitations
- Authentication Issues: Some Vikunja API endpoints have known authentication issues:
- User endpoints: May fail with token errors even with valid tokens (known Vikunja API limitation)
- Bulk operations: May have authentication issues with certain Vikunja API versions
- Label operations: May fail with authentication errors on some server configurations
- Assignee operations: May fail with authentication errors when creating/updating tasks with assignees
- The server provides detailed error messages when these issues occur, suggesting workarounds
Roadmap
- [ ] Add bulk operations support
- [ ] Implement webhook subscriptions for real-time updates
- [ ] Add caching for frequently accessed data
- [ ] Improve error messages for better user experience
- [ ] Add integration tests with real Vikunja instance
Contributing
Please see CONTRIBUTING.md for development guidelines and workflow.
License
MIT