Install
$ agentstack add mcp-democratize-technology-vikunja-mcp ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
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 and centralized utilities
- Production-ready retry logic with opossum circuit breaker for resilience
- Enhanced security with Zod-based input validation and DoS protection
- Rate limiting protection against DoS attacks with configurable limits
- Memory protection with pagination limits and usage monitoring
- Simplified architecture with 90% code reduction for maintainability
🚀 Major Architectural Improvements (v0.2.0)
This release represents a massive architectural simplification that eliminates technical debt while enhancing security and reliability:
Storage Architecture Refactoring (90% Code Reduction)
- Before: 33 files, 9,803 lines of over-engineered storage system
- After: 4 files, essential functionality only
- Eliminated: Complex orchestrators, health monitors, statistics tracking, migration systems
- Result: Same external API with dramatically improved maintainability
Zod-Based Filter System (850+ Lines Removed)
- Before: Custom tokenizer, parser, and validator with security vulnerabilities
- After: Secure Zod schema validation with production-ready parsing
- Enhanced: DoS protection, input sanitization, and comprehensive error handling
- Result: Faster parsing, better security, and enterprise-grade reliability
Production-Ready Retry System (580+ Lines Replaced)
- Before: Custom retry logic with maintenance overhead
- After: Battle-tested opossum circuit breaker library
- Features: Circuit breaker state sharing, automatic recovery, comprehensive monitoring
- Result: Production resilience with battle-tested patterns
Zero Breaking Changes
All improvements maintain 100% backward compatibility with existing implementations while providing enhanced reliability and security.
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
tokenor 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):
``typescript vikunja_auth.connect({ apiUrl: "https://your-vikunja-instance.com/api/v1", apiToken: "your-api-token" }) ``
- Create your first task:
``typescript vikunja_tasks.create({ projectId: 1, title: "My first task via MCP!" }) ``
- List all your tasks:
``typescript 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 '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",
//
…
## Source & license
This open-source MCP server is cataloged on AgentStack and links to its original source — we do not rehost the code.
- **Author:** [democratize-technology](https://github.com/democratize-technology)
- **Source:** [democratize-technology/vikunja-mcp](https://github.com/democratize-technology/vikunja-mcp)
- **License:** MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.