Skip to main content
Glama
freyr
by freyr

ragnarok

Local RAG search over Obsidian vaults for Claude Code.

ragnarok indexes the Markdown notes of one or more Obsidian vaults on your computer. A local MCP server gives Claude Code search tools over the index. No note leaves the computer: the embeddings come from a local Ollama model, and the index is one SQLite file.

Features

  • Hybrid search. Each query runs a dense search (embeddings in sqlite-vec) and a keyword search (SQLite FTS5 with BM25). Reciprocal rank fusion joins the two lists. The unit of rank is the note, with its best section.

  • Heading chunks. The splitter cuts each note at its headings and joins very short sections.

  • Metadata from frontmatter or path. Each note gets a vault, a project, an area, a type, a status and ticket keys. The frontmatter gives these values first. For a note without them, path rules in the configuration give them.

  • Project search. find_projects finds the earlier projects that a prompt continues or resembles, also when the prompt does not name the project. list_project gives all notes of a project.

  • Always current. Each tool call first scans the vaults for changed notes (usually less than 100 ms) and embeds them. There is no watcher process.

  • Private notes. Notes under the configured private paths are in the index, but the server does not return them. Only the user can open them, with allow_private = true in the configuration.

  • Credential redaction. The indexer and open_note replace literal passwords, tokens and keys with [REDACTED]. The vault files do not change.

  • Frontmatter backfill. ragnarok backfill propose writes a proposal of the missing frontmatter keys for a vault. ragnarok backfill export writes a JSON file with the title and the first lines of each public note that needs a description (credentials removed). Claude writes the descriptions into one or more JSON files, {path: {"description": "...", "type": "..."}}. ragnarok backfill merge <vault> <file>... puts them into the proposal, removes credentials, reports each description of more than 25 words and each row with no description, and replaces a default type with a valid type from Claude. You examine the proposal, then ragnarok backfill apply makes a backup archive of the vault and adds only the missing keys.

  • Evaluation. ragnarok eval compares grep, keyword, dense and hybrid search on your own question sets. ragnarok eval agent compares a Claude Code agent with grep and an agent with the MCP tools.

  • One-command setup. ./setup.sh installs the tools, the model and the index, and registers the MCP server in Claude Code. ragnarok doctor checks the setup.

Related MCP server: obsidian-mcp

Requirements

  • macOS with Homebrew. The setup uses brew services for Ollama.

  • Ollama: brew install ollama.

  • Claude Code.

  • setup.sh installs uv if it is missing. uv installs Python 3.12.

Setup

git clone https://github.com/freyr/ragnarok.git
cd ragnarok
./setup.sh                      # installs uv if needed, then runs `ragnarok init`

ragnarok init does six steps. It skips each step that is already done:

  1. It writes config.toml from config.example.toml. It asks for the vault root, the folder that holds your vault folders, and adds each subfolder as a vault.

  2. It checks that Ollama is installed.

  3. It runs Ollama as a login service with brew services start ollama (it asks first). If Ollama runs outside brew services, for example ollama serve in a terminal, init stops it and starts the service.

  4. It pulls the embedding model.

  5. It builds the index. A vault with 1,500 notes takes approximately 12 minutes on an Apple Silicon Mac.

  6. It registers the MCP server ragnarok in Claude Code at the user scope (it asks before it replaces another registration).

Restart Claude Code after step 6. uv run ragnarok doctor checks the same six parts and prints the fix for each failure.

Before step 5, examine config.toml: remove a folder that is not a vault, and add your private paths. A later change of the configuration applies at the next ragnarok index or MCP tool call, with no restart.

Use in Claude Code

The server gives five tools:

Tool

What it does

search

Hybrid search over the notes. Filters: vault, project, area, type, archived.

find_projects

The projects that match a prompt, with the summary and the matching notes of each project.

list_project

All notes of one project.

open_note

The text of a note or of one section, with its links and backlinks.

find_by_jira

The notes that contain a ticket key, for example ABC-123.

Claude Code loads MCP tools on demand. To make Claude use them before grep, add a short instruction to your ~/.claude/CLAUDE.md file, for example:

## Finding notes: ragnarok first

The `ragnarok` MCP server indexes my Obsidian vaults. Use it before Grep or Glob whenever you look for
notes, earlier work or context:

- `find_projects`: the prompt continues or resembles earlier work and names no project. Then call
  `list_project` on the best match (look at the top 3).
- `search`: facts, decisions, how something was done. Filters: vault, project, area, type.
- `open_note`: read a note or one section, with its links and backlinks.
- `find_by_jira`: a ticket key such as `OPS-77`.

The tools are deferred. Load them in one call before the first use:
`ToolSearch` with `select:mcp__ragnarok__search,mcp__ragnarok__find_projects,mcp__ragnarok__list_project,mcp__ragnarok__open_note,mcp__ragnarok__find_by_jira`.

If the tools are absent (for example on a computer without ragnarok), fall back to Grep and say so.
Results can be unrelated: read the text before you rely on it, and cite note paths. Private notes are
refused by design; do not work around the refusal with Read or Grep.

Adapting to your vaults

docs/vault-requirements.md tells how a vault must look to get the most from ragnarok: headings, project folders, SUMMARY.md, frontmatter and private folders.

The default path rules expect <vault>/<area>/<project>/note.md. If your vaults look different, the repo skill .claude/skills/adapt-vault/ guides Claude Code through the changes. Open Claude Code in the checkout and ask it to adapt ragnarok to your vaults. The skill:

  1. runs ragnarok survey on each vault;

  2. agrees the private folders with you, before any other change and before a new vault goes into vaults;

  3. writes the path rules into config.toml, checked with ragnarok inspect;

  4. runs the frontmatter backfill, if you agree, with your review before apply;

  5. writes a small evaluation set from your notes and runs ragnarok eval mechanical;

  6. adds the guidance above to your ~/.claude/CLAUDE.md, after it asks you.

It changes only config.toml and adds frontmatter keys. It never moves, renames or deletes a note or a folder.

Configuration

config.toml is in the checkout. A relative path in it is relative to the checkout. config.example.toml explains each key. The most important keys:

Key

What

root, vaults

The folder that holds the vaults, and the vault folders to index.

private_patterns

Glob patterns of private notes, for example "Notes/Journal/**".

model, dimension

The Ollama embedding model and its vector size. A change needs ragnarok index --rebuild.

min_words, max_words

The chunk size limits of the splitter. A change needs ragnarok index --rebuild.

project_markers

A folder that holds one of these files is a project folder (default DRIVERS.md, SUMMARY.md).

jira_prefixes

The ticket prefixes that find_by_jira knows.

[vault_rules.<vault>]

The path rules of one vault: which folder gives the area and the project.

Note metadata

ragnarok reads these frontmatter keys. Each key is optional:

---
project: heating-upgrade     # the project slug; default: from the path rules
area: home                   # a wide subject; default: from the path rules
type: plan                   # drivers, summary, research, spec, plan, brainstorm, review, decision,
                             # guide, reference, meeting, log, template or note
status: active               # active or archived; a note in an _archive folder, or in a project
                             # whose SUMMARY.md has stage: DONE, is archived
description: One sentence about the note, which improves find_projects.
jira: [ABC-123]              # ticket keys, in addition to the keys in the text
---

Without frontmatter, the path rules give the metadata. The default rules work for a vault with the layout <vault>/<area>/<project>/note.md. For a different layout, add a [vault_rules.<vault>] table. Use ragnarok inspect <note path> to see the metadata of a note.

Commands

Command

What it does

ragnarok init

Sets up this computer (see Setup).

ragnarok doctor

Checks the setup.

ragnarok index [--rebuild]

Adds, changes and removes notes in the index. After a change of the path rules, the private paths or the markers, it derives the metadata of all notes again, with no new embeddings. When a .md marker file is added or removed, it does the same for the notes under the folder of that file. --rebuild is needed only after a change of model, dimension, min_words or max_words.

ragnarok status

Shows the size and the state of the index.

ragnarok search "<query>"

Searches from the terminal.

ragnarok inspect <path>...

Shows the metadata of notes.

ragnarok chunks <path>... | --stats

Shows the chunks of notes, or the totals.

ragnarok serve

Runs the MCP server on stdio. Claude Code starts it.

ragnarok backfill propose|export|merge|apply <vault> [file...]

Proposes, describes and applies missing frontmatter keys. The order is propose, export, Claude writes descriptions, merge <vault> <file>..., you examine the proposal, apply.

ragnarok survey <vault> [--json]

Prints the folders, frontmatter keys, marker files, name patterns and ticket prefixes of a vault folder. Run it before you write [vault_rules.<vault>]. It prints no note text.

ragnarok eval mechanical|pool|agent

Runs an evaluation on the question sets in data/eval/sets/.

Run each command with uv run in the checkout, for example uv run ragnarok search "boiler".

Where things are

Everything is in the checkout. Git ignores config.toml, data/ and logs/.

Path

What

config.toml

The configuration of this computer.

data/index.db

The SQLite index. Copy it to a second computer to skip the first index.

data/backups/

The vault archives that backfill apply makes before it writes.

data/proposals/

The output of backfill propose and backfill export.

data/eval/

Your question sets (sets/), the evaluation results and the mirror of the agent evaluation.

logs/server.log

The MCP server log, one line for each tool call with its time.

Ollama keeps the model in ~/.ollama. Set RAGNAROK_HOME to use a different home folder.

Development

uv run pytest
uv run ruff check . && uv run ruff format --check .

License

MIT. See LICENSE.

Available Tools

5 tools
find_by_jiraC

The notes that contain a Jira key, for example ABC-123.

NameRequiredDescriptionDefault
keyYes

TDQS

C2.9/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full behavioral burden. It identifies the filter condition but does not disclose read-only status, match semantics (exact/substring/case), permissions, pagination, or return behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is one sentence with no filler and includes a useful example. However, it reads as a sentence fragment without an explicit verb, so it is concise but not perfectly front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple one-parameter finder, the description adequately conveys the high-level result: notes containing a Jira key. With no annotations, no output schema, and 0% schema coverage, it still omits matching behavior and result completeness, leaving important gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate for the single key parameter. It adds meaningful format context by naming it a Jira key and giving ABC-123 as an example, but it does not clarify matching exactness, case sensitivity, or other constraints.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states the resource (notes) and the filtering condition (contains a Jira key), with a concrete example ABC-123. It is clear what the tool retrieves, but it does not explicitly differentiate itself from sibling tools such as search or open_note.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description gives no explicit when-to-use guidance, no alternatives, and no exclusions. The Jira key example implies the expected input, but it does not help the agent choose this tool over search or other siblings.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_projectsC

Find the earlier projects that a prompt continues or resembles, ranked by their matching notes.

Each project has its slug, vault, folder, description, stage, next action and matching notes.

NameRequiredDescriptionDefault
limitNo
queryYes
vaultNo

TDQS

C2.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are supplied, so the description carries the full burden; it does disclose that results are ranked by matching notes and enumerates the returned fields (slug, vault, folder, description, stage, next action, matching notes), which is valuable given there is no output schema. However, it says nothing about read-only nature, result limits beyond the default, or the ranking algorithm's behavior.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Only two sentences and front-loaded with the core action, but the wording is awkward ("ranked by their matching notes") and the second sentence is a field list that could be tightened.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 3-parameter tool with no annotations and no output schema, the description omits parameter semantics entirely and gives no usage context. It partially compensates by listing return fields, but an agent still lacks enough to call it correctly against alternatives.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description says nothing about `query` (format, natural language vs keyword), `limit` (default 5, max), or `vault` (filter scope). The word "vault" appears only as a returned field, which does not clarify the parameter.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

A verb and a resource appear (find + projects), but the phrase "earlier projects that a prompt continues or resembles" is vague — it's not clear whether this is a similarity search, a continuation lookup, or a keyword match. Nothing distinguishes it from the sibling `search` or `list_project`.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no statement of when to use this tool rather than `search`, `list_project`, or `find_by_jira`. The agent must infer the selection rule from the name alone.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_projectC

All notes of a project in any folder, with type, status and description, plus its stage and next action.

NameRequiredDescriptionDefault
vaultNo
projectYes

TDQS

C2.4/5.0
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full behavioral burden. It says nothing about permission/auth needs, whether an unknown project errors or returns empty, result size or pagination, or whether the call is purely read-only — only the field names hint at read semantics.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

It is a single short clause with no filler words, but it is a sentence fragment rather than a front-loaded statement of the action. Brevity here comes partly from omission rather than efficient information density.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness2/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 2-parameter tool with undocumented schema fields, no annotations, and no output schema, the description should cover the identifier format and the vault scoping. It describes the return payload loosely but leaves the calling contract (what a valid 'project' and 'vault' look like) unresolved.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% for both parameters, and the description never mentions 'vault' at all nor clarifies whether 'project' is a name, path, or ID. The one thing it does imply — that the project identifier scopes the returned notes — is the minimum the agent could already infer from the parameter name.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose3/5

Does the description clearly state what the tool does and how it differs from similar tools?

The phrase 'All notes of a project in any folder' conveys the resource and scope, but there is no verb, so the operation (list/retrieve) is only inferred from the tool name. It also blends two things — the project's notes and the project's 'stage and next action' — without making the relation explicit.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

There is no indication of when to use this versus siblings like search, find_projects, or open_note. 'in any folder' hints at a broad-recall use case, but the agent gets no explicit selection rule or prerequisite (e.g., needs an existing project identifier).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

open_noteB

The text of a note (or of one section, by heading), its frontmatter, links and backlinks.

    Credentials in the text are replaced with [REDACTED]. Private notes are refused.
    
NameRequiredDescriptionDefault
pathYes
headingNo

TDQS

B3.1/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Without annotations, the description carries the full burden. It discloses two important behaviors: credential redaction and refusal of private notes. However, it does not explicitly state that the operation is read-only, nor does it describe error handling or permission requirements beyond private notes.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences with zero waste. It front-loads what the tool returns and follows with critical behavioral constraints. Every sentence earns its place.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of annotations and no output schema, the description does a decent job of describing return values and key constraints. However, it omits important details such as path format, error behavior if the note is not found, and explicit read-only status, leaving gaps for an agent to infer.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It hints at the 'heading' parameter ('or of one section, by heading'), but does not explain the required 'path' parameter or its expected format. The compensation is partial and insufficient for full clarity.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description specifies the resource (a note or section by heading) and the returned data (text, frontmatter, links, backlinks), making the tool's purpose clear. It does not explicitly differentiate from siblings like search or find_projects, but the scope is sufficiently distinct.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool versus alternatives such as search or find_projects is provided. The description implies usage (opening a note by path), but there are no when/when-not statements or named alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 5 tool updatesv1.0.0
    • First observedfind_by_jira
    • First observedfind_projects
    • First observedlist_project
    • First observedopen_note
    • First observedsearch

TDQS

B3.2/5.0

Scored across 5 tools

Disambiguation4/5

Each tool has a fairly clear niche: search is general hybrid retrieval, find_projects is prompt-driven project matching, list_project enumerates one project's notes, open_note reads full content, and find_by_jira is a keyed lookup. The only real friction is between search and find_by_jira (both retrieve notes) and between find_projects and list_project, though the descriptions make the intent distinguishable.

Naming Consistency4/5

Four of five tools follow a clean verb_noun snake_case pattern (find_projects, list_project, open_note, find_by_jira). The bare verb 'search' is a minor but reasonable deviation as the primary entry point.

Tool Count5/5

Five tools is well within a healthy range and each covers a distinct retrieval need (general search, project discovery, project detail, note reading, Jira lookup). Nothing feels redundant or bolted on.

Completeness4/5

For a read-only vault retrieval server, the surface covers the main workflows: find notes, drill into projects, open content, and resolve Jira keys. Minor gaps exist around enumerating projects/vaults/areas without a prompt (all project discovery routes through find_projects), which agents would have to work around via search.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    A
    quality
    B
    maintenance
    Enables Claude Code read/write access to an Obsidian vault, including creating, editing, searching, and browsing notes.
    8
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects Claude to a local Obsidian vault, enabling listing, reading, searching, and optionally editing notes via natural language, with all operations running locally.
    3,805 npm
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Lets Claude Code and Claude Desktop retrieve and explore an Obsidian vault through tools for semantic search, reading notes, following graph neighbors, and listing topics.
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Gives Claude Code read-only semantic search over an Obsidian vault by reading the embedding files the Smart Connections plugin already produces, so no API key or network is needed at query time and it works across the WSL/Windows boundary. Exposes tools for meaning-based note and block search with folder scoping, related-note discovery, note reading, and index health checks.
    37 npm
    MIT