# Cairn [Health: Active]

**Category:** 📂 File Systems  
**Repository:** https://github.com/luckyjackluo/cairn  
**GitHub Stars:** 2  
**Views:** 3  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/cairn-4

## Description
Local-first file-organization tools for your AI agent: tag, query, and digest a folder. No cloud.

## Tools
Capabilities this server exposes over MCP:

- **list_dir** — List files and folders directly under a workspace-relative directory.
- **get_file_tree** — Return the nested file/folder tree under a directory (default: whole workspace).
- **read_detail** — Read a file. For .uni docs returns HTML content, flattened text, and tags;
    for text/.md files returns raw text plus any YAML frontmatter tags & metadata.
- **search_files** — Find files/folders whose name contains `query` (case-insensitive).
- **grep** — Search file contents for `pattern`; returns {path, line, text} matches.
- **get_file_tags** — Return a document's tags — from a .uni's tags array or a text file's YAML frontmatter.
- **get_tag_tree** — Return {tag: [file paths]} aggregated across the workspace.
- **find_by_meta** — Find documents whose metadata matches all `filters` (exact, not fuzzy).

    Reads .uni JSON fields and .md YAML frontmatter alike. Scalar fields match
    case-insensitively; `tags` (or any list field) matches when every requested
    value is present. Example: {"status": "to-read", "project": "amazon"}.
    
- **list_tasks** — List tasks (documents with `category: task`), sorted by due date.

    A task is an ordinary frontmatter note with a lifecycle; this is the task
    view over it. `status` defaults to the open set (todo/doing/blocked) — pass
    "all" to include done, or a specific status / comma-separated list.
    `project` and `context` (e.g. "@errand") are exact case-insensitive filters;
    `due_before` (YYYY-MM-DD) keeps only tasks due before that date. Each result
    carries derived `overdue` and `today` flags relative to the current date.
    
- **digest_workspace** — Return a token-efficient map of the workspace: one entry (title, date,
    tags, summary) per document, grouped by `folder`, `tag`, or a metadata field
    like `status`/`project`. Read this before loading individual files.
- **list_templates** — List available document templates (built-ins + workspace .cairn/templates).
- **semantic_retrieve** — Return the documents most relevant to `query`.

    Uses embeddings when an embedding endpoint is configured (env), else
    lexical scoring.
    
- **list_paper_projects** — List projects configured for paper recommendations (.cairn/paper_reco.json).
- **preview_paper_recommendations** — Preview the top unseen recommended papers for a project WITHOUT saving.

    Ranks the project's candidate pool by relevance × citation impact and skips
    anything already recommended or already filed. Use this to inspect the queue
    or check a project's topic queries before committing notes. Set `refresh` to
    re-pull the pool from Semantic Scholar instead of using the cached one.
    
- **create_file** — Create a file under `path`. If `name` ends in .uni, wraps content as a .uni doc.

    Pass `template` (e.g. "paper", "note" — see list_templates) with `fields` to
    stamp out a document with frontmatter pre-filled; `content` is then ignored.
    
- **create_folder** — Create a new folder `name` under `path`.
- **add_task** — Create a task (a `category: task` note) and return its record.

    Files into `dir` (default `tasks/`) with a slug from `title`. `due` is
    YYYY-MM-DD; `context` is a tag like "@errand"; `status` is
    todo/doing/blocked/done. `priority` is p1/p2/p3. `blocked_by` is a
    space/comma-separated list of task slugs (a task's slug is its filename stem)
    that must finish before this one becomes actionable. `recur` makes it
    recurring (daily/weekly/monthly/yearly/biweekly or `<N><d|w|m|y>`): completing
    it rolls the task forward to its next due date instead of archiving it.
    Colliding names get a numeric suffix, never clobber.
    
- **complete_task** — Complete a task (surgical frontmatter edit), stamping `completed` (today by default).

    A one-off task is marked `done`; its result gains `unblocked` — the tasks it
    was blocking that are now actionable. A **recurring** task (one with a `recur`
    cadence) is instead rolled forward in place: status back to `todo`, `due`
    advanced to the next occurrence, and the result carries
    `recurred: {next_due, occurrences}`. The rest of the file is preserved.
    
- **next_actions** — The actionable tasks right now — open, unblocked — best-first.

    Answers "what should I work on next?": excludes done, manually blocked, and
    anything still waiting on an open `blocked_by` dependency, then ranks by
    urgency — overdue first, then priority (p1>p2>p3), then soonest due. Pass
    `project` to scope it, `limit` to cap the list (0 = no cap).
    
- **update_task** — Update one or more fields of a task in place (surgical frontmatter edit).

    Pass only the fields to change; an empty argument leaves that field untouched.
    `status` must be todo/doing/blocked/done; `due` is YYYY-MM-DD; `context` is a
    tag like "@deep"; `priority` is p1/p2/p3; `blocked_by` replaces the dependency
    list (space/comma-separated task slugs); `recur` sets the recurrence cadence.
    
- **harvest_checklists** — Promote `- [ ]` checkbox lines in notes into canonical task files.

    Scans text under `path` (a file or folder; default whole workspace), turning
    each unchecked checkbox into a task and parsing inline `due:YYYY-MM-DD`,
    `+project` and `@context` tokens. With `link_back` (default), each harvested
    line is annotated so re-running never double-harvests. Returns {created, count}.
    
- **who_owes** — Summarize who still owes the user money, across all open shared bills.

    This is the reminder view: one row per person — {name, owes, bills,
    oldest_days} — sorted so whoever has been owing longest comes first, plus a
    grand `total` and `bill_count`. Returns an empty `people` list when
    everything is settled, which is the signal to stay quiet rather than send an
    empty reminder.
    
- **list_bills** — List shared bills (documents with `category: bill`), oldest first.

    `status` defaults to "open" (someone is still unpaid); pass "settled" or
    "all". `person` filters to bills naming that person. Each result carries the
    per-person breakdown plus a derived `outstanding` balance and `age_days`.
    Use this to find a specific bill; use `who_owes` for the reminder summary.
    
- **who_owes_me** — Who owes the user an ACTION, rolled up by person — the delegated-work view.

    The actions analog of `who_owes` (which is money): open `waiting` items —
    things the user delegated or is blocked on (a review, a reply, a deliverable) —
    grouped per person you've waited on longest first: {person, count,
    oldest_age_days, items}. An empty list means nothing is outstanding — stay
    quiet rather than nudge. Add items with `add_waiting`; close with `mark_received`.
    
- **list_waiting** — List waiting-on items (things others owe the user), longest wait first.

    A `waiting` note is one person owing one action. `state` is "open" (still
    waiting, default), "closed" (received/dropped), or "all". `person` filters
    case-insensitively. Each record carries {person, title, status, since,
    age_days, due, overdue}. These also surface in `attention`/`reminder_digest`
    once they've been waiting past the kind's staleness threshold.
    
- **attention** — Everything across the workspace that is waiting on the user right now.

    The one reminder primitive spanning every lifecycle kind — tasks, bills,
    papers, and any future kind — not one query per kind. Sweeps all OPEN items
    and returns those that are `overdue`, `due_today`, `upcoming` (within
    `upcoming_days`), or `stale` (open past their kind's staleness threshold
    without a status change). `kinds` restricts to specific categories (e.g.
    ["task","bill"]); omit for all.

    Returns {as_of, count, buckets, items}: `buckets` groups items by urgency
    (most pressing first), each item carrying its `kind`, `due`, `age_days`, and
    the `reasons` it was flagged. A `count` of 0 means nothing needs the user —
    the signal to stay quiet rather than send an empty reminder.
    
- **reminder_digest** — The daily reminder to send: only what is DUE to be re-surfaced today.

    Like `attention`, but cadence-filtered — an item reappears only when its own
    reminder interval has elapsed since it was last sent (a per-note `remind_every`
    frontmatter field, else the kind default of daily), with `overdue`/`due_today`
    items escalated to daily whatever their cadence. This is the tool a reminder
    cron calls; it records what it sent to a workspace ledger so the next run's
    cadence is right (a WRITE, hence the annotation). Pass preview=true to see the
    due set WITHOUT recording (leaves cadence untouched).

    Returns {as_of, count, buckets, items}. A `count` of 0 means send nothing —
    the signal to stay quiet rather than deliver an empty reminder.
    
- **project_pulse** — Per-project momentum/health — the project-manager view of the workspace.

    Where `attention` surfaces individual items, this steps up to the PROJECT:
    for every `project:` value it derives open/overdue/in-progress/blocked task
    counts, the next deadline, and days since anything in that project was last
    touched (`days_since_activity`), flagging `stale` past `stale_after_days` and
    `has_overdue`. Use it to answer "which projects are moving and which have
    stalled?" without reading every note. Pass a `project` to get just that one.

    Returns {as_of, stale_after_days, projects: [...]} sorted longest-idle first.
    
- **stale_projects** — Just the stalled projects — a lean call for a daily-digest line.

    Returns [{project, days_since_activity, tasks_open, tasks_overdue}] for every
    project idle longer than `threshold_days`, longest-idle first. Empty list means
    nothing has gone quiet — the signal to add no stale-projects line at all.
    
- **refresh_project_dashboard** — Regenerate the computed Pulse block in a project's `projects/<name>.md`.

    Writes momentum + open-task numbers into the dashboard between HTML-comment
    markers, leaving every hand-written section untouched — so the "Last updated"
    line stops going stale by hand. Pass a single `project`, or `all=true` to
    refresh every existing `projects/*.md`. Never creates a dashboard: a missing
    file is reported as `updated: false`, not an error.

    Returns the per-project {project, path, updated, inserted, block}.
    
- **weekly_review** — The weekly review: accomplishments, project health, the week ahead, focus.

    The once-a-week synthesis above the daily reminder digest — pure composition,
    no side effects. Returns {as_of, since, horizon, closed, closed_count,
    projects, stalled, due_next_week, focus}: `closed` is every lifecycle item
    finished in the last `window_days` (tasks done, papers read, bills settled);
    `projects`/`stalled` is the per-project pulse; `due_next_week` is dated items
    needing attention within `horizon_days` (overdue + due-today + upcoming); and
    `focus` is the top `focus_limit` next-actions to lead the week with. This is
    the tool a weekly-review cron calls.
    
- **set_status** — Set a note's lifecycle status, stamping when it changed.

    The kind-agnostic way to move any lifecycle note between states — mark a
    paper `read`, a task `doing`, reopen a bill. Validates `status` against the
    note's kind (rejecting a value the kind doesn't define) and records
    `status_changed` so staleness is measured from this moment. For tasks and
    bills the kind-specific tools (complete_task, settle_bill) carry extra domain
    logic; prefer those when they fit, and this for everything else.

    Returns {path, kind, status, state, status_changed}.
    
- **add_bill** — Record a bill the user paid and is owed for, splitting it across `people`.

    `people` are the OTHERS on the bill — never the user. By default `total`
    splits evenly across them plus the user; pass include_self=false when the
    user was only fronting the money and owes no share. `shares` pins exact
    amounts for specific people ({"alex": "52.30"}) and the rest split what
    remains; rounding remainders fall on the user, never on a guest. `date` is
    YYYY-MM-DD (default today).
    
- **settle_bill** — Stop tracking what `person` owes — because they paid, or the user waived it.

    With `path` omitted this settles that person across EVERY open bill, which
    is what "Alex paid me back" usually means; pass `path` to settle just one.
    `state` is "paid" when the money actually arrived and "waived" when the user
    has decided to stop chasing it — both end the reminders, but only "paid"
    claims repayment, so do not substitute one for the other. A bill closes
    itself once nobody on it is unpaid.
    
- **add_person_to_bill** — Add someone to an existing bill for an explicit amount.

    Does not re-split the bill: the others have already been told what they owe.
    
- **add_waiting** — Start tracking something the user is waiting on `person` for (a delegated action).

    `what` is the thing owed (a review, a reply, a deliverable); `person` is who
    owes it. `since` defaults to today (when the wait began); `due` is an optional
    "need it by" (YYYY-MM-DD) that makes it overdue past that date; `remind_every`
    overrides the nudge cadence in days. The item ages from `since` and surfaces in
    the daily digest once it's been outstanding a few days.
    
- **mark_received** — Close a waiting item because they delivered — stamps `received` (today by default).
- **drop_waiting** — Stop waiting on something — close the item as `dropped` (the user gave up on it).
- **update_file_tags** — Replace a document's tags — in a .uni's tags array or a text file's YAML frontmatter.
- **import_document** — Convert a docx/pdf/pptx/csv/xlsx/md/text file into an editable .uni doc.

    The original file is kept. Returns the new .uni item.
    
- **import_folder** — Import every convertible (non-.uni) file under a folder into .uni docs.

    Returns a summary with counts and per-file results (including skips).
    
- **reindex** — Build/refresh the embedding index (no-op if no embedder is configured).
- **recommend_papers** — Recommend + FILE the top unseen paper(s) for one project as to-read notes.

    Picks the highest relevance×impact paper the project hasn't seen, writes it
    into the papers folder as a `paper` note (status: to-read), and records it so
    it never repeats. Returns the picks (title, why, citations, path). Run daily
    for a steady walk through a field's canon, one paper per project per day.
    Set `refresh` to re-pull the ranked pool instead of using the cached one.
    
- **recommend_papers_all_projects** — Recommend + file the top unseen paper(s) for EVERY configured project.

    The daily-driver: one call yields one new to-read paper note per project.
    Set `refresh` to re-pull each ranked pool instead of using the cached one.
    
- **multi_edit** — Replace a single, unique occurrence of `old_string` with `new_string` in a file.
- **rename_item** — Rename a file or folder in place (bare name, not a path).
- **move_item** — Move a file or folder into `target_dir`.
- **delete_item** — Delete a file or folder (recursive for folders).

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "cairn": {
    "command": "uvx",
    "args": ["cairn-mcp-server"]
  }
}
```

## Documentation

## What Cairn MCP server does

Cairn MCP server connects an MCP client to a folder on the local filesystem and exposes a file-organization toolset. Its documented capabilities include listing and reading files, text search, grep, editing, moving, tagging, deleting, importing documents, and semantic retrieval. The package is intended to supply tools rather than an agent loop; Claude Code, Codex, Cursor, or another MCP client handles the conversation and approvals.

A workspace is an ordinary directory. Cairn can work with its `.uni` document format, where each document is represented as JSON containing a UUID, HTML content, metadata, and tags. Tags are stored inside the file, and the filesystem remains the source of truth. Imported source documents are kept by default while Cairn creates editable `.uni` documents from supported formats.

## How it works

The MCP server is a thin adapter over Cairn’s local core. It exposes 26 tools, along with MCP resources and prompts, and marks operations according to their risk. Listing, reading, searching, grepping, and retrieving are read-only operations. Moving, deleting, or editing files are destructive operations, allowing compatible clients to request confirmation before making changes.

The default retrieval method is lexical and requires no model or API key. Embeddings-based retrieval is optional. When enabled, it can use an OpenAI-compatible endpoint, including local services such as Ollama or LM Studio. Vectors are stored in a SQLite index under `<workspace>/.cairn/`, so the index remains on the machine.

This makes the Cairn MCP server suitable for organizing a notes directory, applying tags across documents, locating related content, or importing a collection for agent-assisted cleanup. Because the tool can rename, move, edit, and delete files, testing against a copy of important material is appropriate.

## Setup and configuration

The server can be launched with `uvx`, which requires `uv`. A Claude Code configuration uses the form:

```bash
claude mcp add cairn -- uvx cairn-mcp-server --workspace ~/Documents/notes
```

Codex uses the equivalent `codex mcp add` command. Other MCP clients can use a JSON server entry with `uvx` as the command, `cairn-mcp-server` as the package argument, and `--workspace` followed by the target directory. Cairn expands `~` in both command-line and configuration paths.

The workspace is supplied as a command-line option rather than an environment variable. A separate `cairn-cli` package is available for direct commands, including tree inspection and retrieval, but it is not required for MCP use.

## Limitations and notes

Embeddings are not enabled by default and require a compatible endpoint when used. The project is described as young, with richer document round-tripping, saved views, additional retrieval backends, and broader client recipes listed as future work.

The optional web interface is separate from the MCP server and runs locally through `cairn-cli serve`; it is not required for agent access. The project is licensed under MIT.

_Full upstream README: https://allmcps.com/mcp/cairn-4/readme_

