npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fswap/mcp-vikunja

v0.1.10

Published

MCP server for Vikunja — manage tasks, assignees, comments, attachments, relations and kanban from Claude

Readme

@fswap/mcp-vikunja

An MCP server for Vikunja that lets Claude Desktop, Claude Code, Cursor and other MCP clients manage your tasks: create, update, complete, assign, comment, attach files, relate, move on kanban boards and everything else in the task menu.

Runs locally over stdio. No install step — clients launch it with npx.

Quick start

  1. Create an API token in Vikunja under Settings → API Tokens (scope it to projects, tasks, labels, task comments, attachments, assignees, relations, subscriptions, reactions and users — tools whose scope is missing return a 401).

  2. Run the interactive setup once:

    npx -y @fswap/mcp-vikunja@latest setup

    It asks for your Vikunja URL and token, verifies them against /api/v1/user, lets you pick a default project, and stores the answers in your OS config directory (mode 0600).

  3. Add the server to your client. At the end, setup offers to do this for you in Claude Code, Claude Desktop, Cursor and Codex: clients it finds are pre-selected (except Claude Code when Claude Desktop is installed, because the desktop app's Code tab already loads claude_desktop_config.json), an existing vikunja entry is only replaced after you confirm, and any config file it changes gets a one-time .bak copy.

    To add it by hand instead, use the snippets below. Every value asked in setup can be skipped with Enter; anything you skip goes into the env block instead. setup --print shows these snippets again at any time.

    Claude Desktop (claude_desktop_config.json) and Cursor (~/.cursor/mcp.json or <project>/.cursor/mcp.json):

    {
      "mcpServers": {
        "vikunja": {
          "command": "npx",
          "args": ["-y", "@fswap/mcp-vikunja@latest"]
        }
      }
    }

    Codex (~/.codex/config.toml):

    [mcp_servers.vikunja]
    command = "npx"
    args = ["-y", "@fswap/mcp-vikunja@latest"]

    Claude Code:

    claude mcp add vikunja -- npx -y @fswap/mcp-vikunja@latest

Without setup (environment variables)

Environment variables take precedence over the config file, so you can skip setup entirely (or skip individual values in it and set them here):

{
  "mcpServers": {
    "vikunja": {
      "command": "npx",
      "args": ["-y", "@fswap/mcp-vikunja@latest"],
      "env": {
        "VIKUNJA_URL": "https://try.vikunja.io",
        "VIKUNJA_API_TOKEN": "tk_..."
      }
    }
  }
}

Codex equivalent:

[mcp_servers.vikunja]
command = "npx"
args = ["-y", "@fswap/mcp-vikunja@latest"]
[mcp_servers.vikunja.env]
VIKUNJA_URL = "https://try.vikunja.io"
VIKUNJA_API_TOKEN = "tk_..."

| Variable | Purpose | |---|---| | VIKUNJA_URL | Vikunja base URL (with or without /api/v1) | | VIKUNJA_API_TOKEN | API token or login JWT | | VIKUNJA_ALLOW_DELETE | true to expose delete_task, delete_task_comment and delete_task_attachment | | VIKUNJA_DEFAULT_PROJECT_ID | Project used by create_task when projectId is omitted |

Tools

| Tool | Method + endpoint | Notes | |---|---|---| | list_projects | GET /projects | id, title, description, parent | | get_project | GET /projects/{id} | | | create_project | PUT /projects | optional parent project | | list_tasks | GET /tasks or GET /projects/{id}/tasks | open tasks by default; assignedToMe, filter, sortBy, pagination | | get_task | GET /tasks/{id} + GET /tasks/{id}/comments | everything on the task page, including comments (includeComments=false skips them) | | create_task | PUT /projects/{id}/tasks | all task fields, see below | | update_task | POST /tasks/{id} (+ labels/assignees bulk) | merges your changes onto the current task | | complete_task | POST /tasks/{id} with done: true | done=false marks undone | | duplicate_task | PUT /tasks/{id}/duplicate | copies labels, assignees, attachments, reminders | | set_subscription | PUT / DELETE /subscriptions/{task\|project}/{id} | subscribe / unsubscribe | | list_labels | GET /labels | label ids for create/update | | create_label | PUT /labels | | | get_current_user | GET /user | your own user id, e.g. to assign yourself | | find_users | GET /projects/{id}/projectusers or GET /users | user ids for assigneeIds | | list_task_comments | GET /tasks/{id}/comments | author, HTML body, reactions | | add_task_comment | PUT /tasks/{id}/comments | plain text is wrapped in <p>; filePaths uploads files and shows them in the comment | | update_task_comment | POST /tasks/{id}/comments/{commentId} | filePaths without comment adds files to the existing text | | set_reaction | PUT /{tasks\|comments}/{id}/reactions | remove=true removes your reaction | | add_task_relation | PUT /tasks/{id}/relations | subtask, parenttask, blocking, related, … | | remove_task_relation | DELETE /tasks/{id}/relations/{kind}/{otherId} | | | list_task_attachments | GET /tasks/{id}/attachments | | | upload_task_attachment | PUT /tasks/{id}/attachments (multipart) | local file paths | | download_task_attachment | GET /tasks/{id}/attachments/{attachmentId} | saves to disk; small images/text returned inline | | list_kanban_buckets | GET /projects/{id}/views + /views/{view}/buckets | kanban columns | | move_task_to_bucket | POST /projects/{id}/views/{view}/buckets/{bucket}/tasks | | | delete_task | DELETE /tasks/{id} | only when delete is allowed (setup answer or VIKUNJA_ALLOW_DELETE=true) | | delete_task_comment | DELETE /tasks/{id}/comments/{commentId} | delete-gated like delete_task | | delete_task_attachment | DELETE /tasks/{id}/attachments/{attachmentId} | delete-gated like delete_task |

create_task and update_task cover the rest of the task menu: due/start/end dates, priority, progress (percentDone), colour (hexColor), favorite (isFavorite), repeating interval (repeatAfterSeconds, repeatMode), reminders (absolute or relative to a date), labels (labelIds), assignees (assigneeIds) and moving to another project (projectId). labelIds, assigneeIds and reminders replace the current values. descriptionFilePaths uploads local files and shows them at the end of the description. get_task returns all of these plus related tasks, attachments, kanban buckets, subscription and comments.

Vikunja has no comment-level attachments. Files shown in a comment or description are task attachments, exactly as when pasting into the web editor: images are embedded as <img data-src>, other files are referenced by name.

Every task and project includes a url to its page in the Vikunja web UI (taken from /info frontend_url). Vikunja's zero date (0001-01-01T00:00:00Z) is normalised to null in every response. API errors are returned to the model as isError results rather than crashing the server.

Development

TypeScript source in src/, bundled to dist/ with tsdown. Only dist/ is published.

npm install
npm run build        # tsdown → dist/index.js
npm run lint         # eslint (typescript-eslint)
npm run typecheck    # tsc --noEmit
npm test             # builds, then spawns the server and checks the tool list
npm run check        # all of the above (also runs on prepublishOnly)
VIKUNJA_URL=... VIKUNJA_API_TOKEN=... npm run inspect   # MCP Inspector UI against dist/

Never write to stdout from server code — it is the protocol channel. Use console.error.

Reset

npx -y @fswap/mcp-vikunja@latest setup --reset

License

MIT