Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
MCP server for skill library lookup
The librarian keeps a large skill collection out of agent context and serves only the few skills that fit the task. It uses Ollama embeddings, SQLite, and optional Apple Intelligence reranking, then logs query and outcome data so the collection can curate itself.
Builders who use Claude Code, Cursor, or another MCP client and want their agent to pull from a large skill collection on demand.
You can keep hundreds or thousands of skills off the prompt and still have your agent find the right one for the task.
What it does
Semantic skill lookup
Finds matching skills from plain-language intent instead of keyword search.
Diverse shortlist ranking
Uses MMR and recency penalties to avoid returning the same few skills over and over.
Outcome logging
Lets the agent report whether a skill worked, so the library can be curated from real use.
Optional on-device rerank
Can pass finalists through an Apple Intelligence reranker for a final fit score and short why/why-not notes.
Local-only storage and indexing
Uses Ollama embeddings and SQLite locally, with no cloud service required.
How to get it
- 1Run
cd the_librarian uv venv --python 3.12 .venv uv pip install --python .venv/bin/python "mcp[cli]>=2" httpx pydantic # embedding model on whichever node you point at: ollama pull nomic-embed-text
README
the_librarian
A skill librarian MCP server — your agents stop carrying the whole skill collection in context and start asking for the one right book.

How it started
One question in a chat:
"I'm sure you know better than the internet what you need to get better. What's the best workflow with Claude Code? Installing skills and just you pick the best? More the better? Less is more?"
The answer: less is more. Every installed skill costs tokens and adds triggering ambiguity — with 50 skills, descriptions overlap and the wrong one fires; with 8 sharp ones, triggering is nearly deterministic.
But the collection had ~3,000. So instead of installing any of them: give the collection a librarian.
find_skill(intent)→ librarian recommends- agent uses the skill, does the work
report_outcome(skill, worked: true/false, note)→ librarian logs it
"The poetic part: the librarian is itself the curation loop. Log every query and what got picked vs ignored — skills that never surface are your kill candidates, queries that match nothing are your gaps. The collection optimizes itself from its own usage data."
"So the full shape: SQLite (skills, embeddings, query log, outcome log) + FastMCP + two read tools + one write tool. Maybe 300 lines of Python. It's small, it's one thing, and it compounds."
It's ~600 lines now. Scope creep found even the librarian. The original conversation — typed poolside on a phone, typos preserved on purpose — is in ORIGIN.md.
What it is
A local-first MCP server that acts as a librarian between coding agents and a large skill collection. The collection stays raw markdown on disk — agents never load it into context. They describe what they're trying to do in plain language; the librarian finds the skills whose meaning matches (semantic search — no keyword guessing), makes sure the shortlist isn't three flavors of the same thing, avoids repeating what it just recommended, optionally lets Apple's on-device model deliberate over the finalists — and learns from what agents report back.
Core principle: agents read recommendations, write only outcomes. They never edit skills, weights, or rankings. Curation decisions stay with the human, informed by librarian_stats.
Every stage is local and free: Ollama embeddings, SQLite, and (optionally) Apple Intelligence.
→ In production since June: real usage numbers — 130 queries, 76 agent-filed outcome reports across two snapshots (latest 2026-08-04), what worked and what's queued next.
Pipeline (one find request, end to end)
In plain words: every skill's description is turned once into an embedding — a list of numbers that captures what the skill is about, so "package my server for distribution" can match a skill that never uses the word "package." A request goes through five steps:
intent ─→ Ollama embed (nomic-embed-text, /api/embed)
─→ cosine vs ~3,000 skill vectors (SQLite) ← "which skills mean the same thing?"
─→ MMR diversity + recency decay ← anti-monotony (see below)
─→ [opt-in] AFM rerank: Apple's on-device model scores fit 1–10,
why / why-not per candidate, final pick (bin/afm-rerank, ~6–12s)
─→ compact JSON shortlist
Setup (2 minutes)
cd the_librarian
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python "mcp[cli]>=2" httpx pydantic
# embedding model on whichever node you point at:
ollama pull nomic-embed-text
Claude Code config
Add to ~/.claude.json (or project .mcp.json), with paths adjusted to where you cloned this and where your skills live:
{
"mcpServers": {
"skill-librarian": {
"command": "/path/to/the_librarian/.venv/bin/python",
"args": ["/path/to/the_librarian/server.py"],
"env": {
"LIBRARIAN_SKILLS_DIR": "/path/to/your/skills-collection",
"OLLAMA_HOST": "http://localhost:11434",
"LIBRARIAN_EMBED_MODEL": "nomic-embed-text",
"LIBRARIAN_CANONICAL_PREFIXES": "categories",
"LIBRARIAN_RERANK_BIN": "/path/to/the_librarian/bin/afm-rerank"
}
}
}
}
The skills dir is scanned recursively for SKILL.md files (standard agent-skill format: YAML frontmatter with name + description, body below). OLLAMA_HOST can point at a remote node (e.g. over Tailscale) to offload embedding — though an M4 Max reindexes 3,000 skills in ~2 minutes locally.
First run
> use librarian_reindex
> use librarian_find with intent "package my ollama wrapper for distribution"
AFM reranker (optional, Apple Intelligence)
librarian_find can pass its shortlist through Apple's on-device Foundation Model for a deliberation pass — reorders by reasoned fit (1–10) and adds one-sentence why / why-not per candidate, plus a final pick. Fully local, free, ~5–12s. Build and enable:
swiftc -O -parse-as-library afm_rerank.swift -o bin/afm-rerank
# then set LIBRARIAN_RERANK_BIN to the binary path in the MCP env
Unset LIBRARIAN_RERANK_BIN (or any failure/timeout) falls back to pure embedding order. Brainstorm is never reranked — it wants divergence, not convergence. The reranker's output is validated against the real candidate set — small on-device models happily hallucinate skill names.
Tools
| Tool | What it does |
|---|---|
librarian_find | Ranked shortlist for an intent — varied picks, no repeats from recent queries, success rates shown. |
librarian_brainstorm | Wide diverse sweep + 2 random wildcards. For ideation, not convergence. |
librarian_report | Agent reports skill worked/failed. Append-only — agents can't touch rankings. |
librarian_reindex | Rescan + re-embed changed SKILL.md files (hash-checked, cheap to rerun). |
librarian_stats | Curation digest: hot skills, never-surfaced (kill candidates), low success rate (rewrite candidates). |
Teaching your agents to use it
Connecting the server is half the job — agents also need the habit of asking. The repo
ships one agent skill for that: skills/using-the-skill-librarian.
Install it in each agent's skills directory and it teaches the whole loop: find before
any non-trivial task, weigh the why/why-nots, read the winning skill in place, and
always file a librarian_report afterward — the reports are what make the collection
curate itself.
The joke writes itself, but it's real: the only skill you install is the one that teaches agents to ask the librarian. In eight weeks of production use, that habit produced outcome reports on ~59% of queries, unprompted.
Why it won't recommend the same 3 skills forever
The failure mode this design exists to kill: a naive retriever recommends the same handful of skills every time. Three mechanisms prevent it:
- MMR selection (maximal marginal relevance) — each next pick has to be relevant to the request and different from the picks already made, so the shortlist can't be three near-duplicates.
- Recency decay — the librarian remembers its own recent recommendations; anything suggested in the last 10 queries gets pushed down (
RECENCY_PENALTY = 0.15per appearance — tune at top of server.py). - Wildcards in brainstorm mode — 2 random skills from outside the relevant set, every time.
The AFM reranker runs after these — it reorders the already-diversified shortlist, so it can't reintroduce monotony.
Eight weeks of real data says it works: 302 distinct skills surfaced across 130 queries. See the usage report for the one sharp edge (recency decay also hides just-confirmed winners) and the fix queued for it.
The flywheel
Every librarian_find is logged. Every librarian_report is logged. Run librarian_stats weekly: never-surfaced skills → kill, low-success skills → rewrite descriptions, queries matching nothing → skills you should build. The collection curates itself from usage.
Tuning knobs (top of server.py)
RECENCY_WINDOW/RECENCY_PENALTY— how hard repeats get punishedMMR_LAMBDA_FIND(0.7) — relevance vs diversity for findMMR_LAMBDA_BRAINSTORM(0.45) — brainstorm leans diverseRERANK_TIMEOUT(30s) — AFM reranker budget before falling back to embed order
Env knobs: LIBRARIAN_CANONICAL_PREFIXES (which top-level dirs win duplicate-name races, e.g. categories), LIBRARIAN_RERANK_BIN (path to afm-rerank; empty disables rerank).
Hard rules the code keeps
- Never load full skill bodies into tool responses — descriptions + metadata only. The whole point is keeping the collection out of agent context.
- Agents get no write access beyond the append-only outcome log.
- DB is SQLite WAL at
~/.skill_librarian/librarian.db;query_logandoutcome_logare append-only — no tool deletes or rewrites log rows.
FAQ
What is a skill librarian? An MCP server that sits between AI agents and a skill collection: agents describe a task in plain language, the librarian recommends the few skills that fit, and the collection itself never enters agent context.
Why not just install all the skills? Every installed skill's description is loaded into context on every request — with a large collection that's a constant token cost, and overlapping descriptions make the wrong skill fire. The librarian reduces that to one tool call when a skill is actually needed.
Does it work with agents other than Claude Code? Yes — it's a standard stdio MCP server. Any MCP client (Claude Code, Claude Desktop, Cursor, Goose, and others) can use it; this one runs against five different agents daily.
Does my skill collection leave my machine? No. Indexing (Ollama), storage (SQLite), and the optional reranker (Apple's on-device model) all run locally. Nothing is sent anywhere.
See CHANGELOG.md for the full history of changes and the decisions behind them.
Files in the repo
- assets
- skills
- .gitignore
- afm_rerank.swift
- CHANGELOG.md
- LICENSE
- llms.txt
- ORIGIN.md
- README.md
- server.py
- USAGE-REPORT.md
Discussion (0)
Ask about usage, or say what you built with itSign in to join the discussion.
No comments yet. Be the first to say what this is good for.
More connectors
High-performance code intelligence MCP server. Indexes codebases into a persistent knowledge graph — average repo in milliseconds. 158 languages, sub-ms queries, 99% fewer tokens. Single static binary, zero dependencies.

Universal provider proxy for OpenAI Codex & Claude Code — use any LLM (Claude, Gemini, Grok, DeepSeek, Ollama…) with Codex CLI, App, SDK, and Claude Code
Git-native persistent memory for AI coding agents. Implements Google OKF v0.2 with sub-300µs in-memory BM25 search, embedded MCP server, and progressive disclosure. Slashes token bloat by 80% with zero external databases or dependencies. Built in pure Go.
Local-first code intelligence graph for MCP and CLI. Builds a persistent map of your codebase so AI coding tools read only what matters, with benchmarked context reductions on reviews and large-repo workflows.
Stop your AI from making things up — it proposes, deterministic tools decide, every claim checked against ground truth with evidence. Grounded facts and context survive resets. Reverse engineering is the proving ground. MCP server + CLI.