8.1 KiB
8.1 KiB
Vikunja MCP usage guide.
This MCP server is your persistent memory and project management layer,
backed by a self-hosted Vikunja instance. You are the only user. Follow
these conventions exactly so that memories stored today remain findable
in six months.
VOCABULARY
project container of tasks. One per repo, one for general memory,
one per life area. Create once, reuse forever.
task a single unit of work, note, or memory entry. Fields: title,
description (markdown), done, priority (1-5), labels,
assignees, bucket_id, created, updated.
label a reusable tag. Cross-cutting across all projects. Labels
have a numeric id that filters require.
view a saved layout for a project (list, kanban, gantt, table).
bucket a column inside a kanban view (Todo, In Progress, Done, ...).
filter a saved query recallable by id.
TAGGING RULES (MANDATORY)
Labels are the primary recall mechanism. Without discipline here,
memory becomes unsearchable noise.
1. Always namespace labels as "namespace:value". The only exceptions
are the universal workflow tags listed below.
Good: topic:postgres, kind:decision, lang:python
Bad: postgres, decision, python
2. Always lowercase. "topic:Postgres" and "topic:postgres" are two
labels and will fragment recall.
3. Before creating a label, search with get__labels s=. Only
create if no match exists. Reuse is the whole point.
4. Never invent synonyms. Once "topic:postgres" exists, never create
"topic:postgresql" or "topic:pg". One canonical form per concept.
5. Tag aggressively. Every memory gets two to five labels. A decision
about Postgres replication for the backend project should carry:
topic:postgres, topic:replication, kind:decision, project:backend.
More angles means more recall paths.
6. Cache label ids within a session. Resolve each label once, build
a local name-to-id map, stop re-resolving on every write.
CANONICAL NAMESPACES
topic: Technical subjects, tools, concepts, systems.
Examples: topic:postgres, topic:docker, topic:auth,
topic:networking, topic:dns, topic:linux, topic:irc.
kind: The shape of the memory entry.
Examples: kind:fact, kind:decision, kind:preference,
kind:reference, kind:snippet, kind:question, kind:todo,
kind:lesson, kind:idea, kind:config, kind:howto.
lang: Programming language when relevant.
Examples: lang:python, lang:go, lang:bash, lang:c.
project: Scope to a specific codebase or initiative.
Examples: project:backend, project:mcp, project:dotfiles.
area: Broader life or work area.
Examples: area:infra, area:homelab, area:learning,
area:networking, area:security.
source: Where the information originated, when it matters.
Examples: source:docs, source:manpage, source:rfc,
source:github, source:irc, source:experiment.
status: Temporal relevance markers for things that expire.
Examples: status:current, status:outdated, status:blocked.
Add new namespaces when you genuinely need one. Keep the format
namespace:value. If you find yourself wanting a namespace that only has
one or two entries, consider whether an existing namespace covers it.
The following tags are allowed un-namespaced because they are universal
workflow labels in a repo context: bug, feature, refactor, docs, chore,
breaking, p0, p1, p2. Do not use these outside code projects.
MEMORY CONVENTIONS
One project titled "Memory" holds general long-term knowledge: facts,
decisions, preferences, references, snippets, and anything that does
not belong to a specific repo. Create it on first use if missing.
Cache its id for the rest of the session.
Every memory is a single task:
title short headline, 3 to 10 words. Treat it like a filename.
description full markdown body, arbitrarily long. This is the content.
labels two to five tags following the rules above.
priority 1-5, default 2. Reserve 4-5 for truly critical info.
Evolving memories: add comments via put__tasks_taskID_comments rather
than rewriting the description. Comments preserve the timeline.
Superseded memories: set done=true. They stay searchable but are
excluded from default "active" queries.
NEVER store secrets, credentials, tokens, API keys, or private keys.
PER REPOSITORY PROJECT CONVENTIONS
One Vikunja project per code repository. Title must match the repo name.
On first touch:
1. get__projects s= to check for an existing project
2. If missing, put__projects with {"title": "",
"description": ""}
3. Ensure workflow labels exist: bug, feature, refactor, docs,
chore, breaking, p0, p1, p2
Task workflow:
- Create tasks via put__projects_id_tasks
- Every task gets a type label (bug | feature | refactor | docs | chore)
and a priority label (p0 | p1 | p2)
- Mark done=true when complete. Never delete. History matters.
- Record implementation notes via put__tasks_taskID_comments
Session startup: call get__tasks with
filter="project = && done = false" to see what is in flight.
FILTER SYNTAX (CRITICAL)
Operators: = != > >= < <= like in
Combinators: && (and), || (or). Parentheses for grouping.
Strings are double-quoted. Numbers and booleans are bare.
Fields: title, description, done, priority, due_date, start_date,
end_date, created, updated, labels, assignees, project, bucket_id.
LABEL FILTERS USE NUMERIC IDS, NOT NAMES.
1. Resolve each tag name to its id via get__labels s=
2. Filter: labels = 3
3. Multiple: labels in 3,5,7
(comma separated, NO brackets, NO quotes, NO spaces after commas)
Wrong: labels in ["topic:postgres"]
Wrong: labels = "topic:postgres"
Right: labels = 3
Right: labels in 3,5,7
Text search with `like` against title or description:
title like "postgres"
description like "replication"
Dates are RFC3339 in double quotes:
created > "2026-01-01"
due_date < "2026-04-20" && done = false
Combined examples:
project = 5 && done = false
labels = 3 && priority >= 4
(labels = 3 || labels = 5) && done = false
title like "postgres" || description like "postgres"
project = 5 && labels in 8,9 && done = false
WRITE WORKFLOW (STORING A NEW MEMORY)
1. Decide the tag set. Aim for 2 to 5 labels.
2. For each tag, call get__labels s=. If missing, create with
put__labels using a hex_color by namespace:
topic=3b82f6 kind=8b5cf6 lang=06b6d4 project=10b981
area=f59e0b source=6b7280 status=ef4444
Cache ids for the session.
3. Resolve the Memory project id once via get__projects s=Memory.
4. Create the task via put__projects_id_tasks with
{title, description, priority}.
5. Attach each label via put__tasks_task_labels with {"label_id": }.
6. Confirm by echoing the stored title and tag set.
READ WORKFLOW (RECALLING MEMORIES)
1. Translate the question into candidate tags.
2. Resolve each tag to its id (cached when possible).
3. Build a filter: labels in 3,5,7. Add && done = false unless
historical entries are explicitly wanted.
4. Call get__tasks with the filter, per_page 5-15.
5. Zero hits? Fall back to text search:
title like "" || description like ""
6. Surface 1-3 matches concisely. Full descriptions only on request.
DEFAULTS
priority 1..5, 5 is highest
hex_color 6-char hex, no leading hash
done false by default
per_page keep <= 20 unless a full dump is requested
timezone UTC unless specified otherwise
SAFETY
- Always check-or-create for projects and labels. A duplicate Memory
project splits the memory store and is a critical failure.
- Confirm before destructive calls (delete, bulk update, label removal)
when the target is ambiguous.
- Verify ids by reading first when intent is vague.