Lectern MCP server
Commit Oct 29, 2026A developer notebook that verifies AI citations against actual files and line numbers to ensure documentation and code accuracy.
Also known as DizzyMii/lectern
- Stars
- 0
- Tools
- —
- Downloads, 30 days
- —
- Latest version
- —
- Last commit
- Oct 29, 2026
- License
- Apache-2.0
What is Lectern MCP?
Lectern is a developer notebook that verifies AI citations against actual files and line numbers to ensure documentation and code accuracy.
Summary generated from the project's README
About Lectern MCP server
Developers who need to ensure their documentation and code remain accurate can use this tool to verify AI-generated citations against actual files and line numbers. By pinning trusted documentation and pointing the system at local source folders or git repositories, users can ask questions and receive answers where every citation is automatically checked for validity. The system tracks whether a quote is verified, moved to a new line, or unverified due to code rewrites.
This tool runs locally on your machine, listening on 127.0.0.1, and requires an Anthropic API key to function. It can be used as a desktop application for Windows, via npm for Node 20 or newer, or as an MCP server to allow Claude Code or Cursor to search your notebooks. It provides specialized integration through a Claude Code Stop hook and a CLI command to run checks in CI environments, ensuring that documentation like CLAUDE.md remains synchronized with your evolving codebase.
What you can do with it
- 1Verify documentation accuracyAsk questions about your codebase and ensure every cited line number or quote matches the current state of your files.
- 2Detect code drift in old answersReopen a conversation from a month ago to see if recent code changes have invalidated previous AI citations.
- 3Prevent broken citations in CIRun automated checks during your continuous integration process to fail builds if documentation cites lines that no longer exist.
- 4Integrate with AI coding agentsAllow Claude Code or Cursor to access your curated notebooks and documentation for more accurate context.
Written from the project's README. Every use case is checked against a quote from it.
README
View on GitHubQuick start
Pick one.
Desktop app (Windows)
git clone https://github.com/DizzyMii/lectern.git
cd lectern
npm install
npm run build:exe
That leaves two files in dist/:
| File | What it is |
|---|---|
Lectern Setup.exe |
Installs for your user, no admin needed. Starts in a couple of seconds. This is the one to hand to people. |
Lectern.exe |
Portable, runs from anywhere. It unpacks itself on every launch so it takes about 30 seconds to open. |
Neither needs Node on the machine it runs on. Neither is code signed yet either, so SmartScreen asks the first time (More info, Run anyway).
Closing the window leaves Lectern in the system tray (the Quit when the window closes switch in Settings turns that off). While it sits there it watches your code roots, and after a git pull or a save moves the citations in a saved answer you get a notification with the question number, click it to land on that answer.
Quick ask is off until you switch it on in Settings. With it on, Ctrl+Alt+Space in any app opens a small Lectern window with your clipboard text already in the palette. Enter asks your last-used notebook on the fast preset (Haiku, low effort), and Alt+Enter opens that question in the main window. Clipboard text is cut at 8,000 characters.
npm
Needs Node 20 or newer.
npm install -g @dizzymii/lectern
lectern serve --open
npx @dizzymii/lectern serve works too if you don't want it installed. Either way it's on http://127.0.0.1:4317.
From a clone
npm install
npm start # the web app on http://127.0.0.1:4317
npm run app # the same thing in the desktop window
docs/SETUP.md walks through a fresh machine step by step, including phone access over Tailscale and starting it at logon.
Your first notebook
- Add an API key. Click the cog in the top bar, paste a key from console.anthropic.com, Save. The engine label next to it turns green.
- Make a notebook. First run walks you through it, or try the ready-made one:
That pulls three pages of the Node.js 22 API docs into a new notebook.lectern example node-docs - Add sources. Press A. A page URL gets pinned as markdown, a folder or git repo becomes a code root the model can search.
- Ask. Press /, type, Enter. Click any
[n]to open the file at that line.
What it does
- Checked citations. Every
[n]points at a file with a quote, a line range or both, and Lectern opens the file and looks. Code citations save the lines they cite and compare them again on every re-check. Each one comes back verified, moved (found elsewhere in the file, with the new line), unverified (the quote is gone, or the saved code lines were rewritten) or missing, and they get re-checked whenever you open an old conversation, so if the docs or the code changed under you, it shows. Each answer also records the git commit of every code root it read, so you can open the file as it was. - Checks in Claude Code and CI.
lectern hook stopis a Claude Code Stop hook. When a citation in the agent's final message is broken it blocks the finish and sends the agent back to fix it (details).lectern check --fail-on unverifiedre-checks a whole notebook and exits 1 when a citation went unverified or missing, so CI goes red when a CLAUDE.md written from the notebook cites lines that have since changed (CLI). Neither calls a model. - Code roots. A notebook holds pinned docs (the shelf) plus code roots, which are folders or git repos on your disk. The model can search and read any text file under a root while it answers, so it quotes the real source of the library you're using.
- Studio. 24 recipes that turn a notebook into a saved artifact (specs, code maps, a CLAUDE.md, flashcards, a diff review...) with the same citation checks.
- MCP.
lectern mcplets Claude Code or Cursor search your notebook for free and ask it questions while they work.
Search, file reads, citation checks and the free MCP tools run on your machine, and the server only listens on 127.0.0.1. Your questions, the pinned docs and the files the model reads while it answers go to Anthropic (the full list is under What leaves your machine, further down).
How a citation gets checked
Behind every [n] is a file plus a short verbatim quote, a line range or both (docs mostly get a quote, code gets line numbers). A line-only citation also saves a copy of the lines it points at when the answer is saved. Lectern opens the file as it is on disk right now and looks, and does it again every time you open an old conversation.
flowchart LR
A["[n] in the answer"] --> B{"File in the notebook,<br>2 MB or under?"}
B -->|no| M["missing"]
B -->|yes| Q{"Has a quote?"}
Q -->|yes| F{"Where is<br>the quote?"}
F -->|"at the cited lines"| V["verified"]
F -->|"elsewhere in the file"| MV["moved<br>(new line given)"]
F -->|"not in the file"| U["unverified"]
Q -->|"no, lines only"| L{"Where are the<br>saved lines?"}
L -->|"at the cited lines"| V
L -->|"elsewhere in the file"| MV
L -->|"rewritten or gone"| U
| Status | Means |
|---|---|
| verified | The quote is within two lines of the cited range (anywhere in the file if no range was given), or the saved lines are still at the cited range. Whitespace and blank lines don't count as a change. |
| moved | The quote or the saved lines are in the file at different lines. The card says where, like "Cited L9, found at L15". |
| unverified | The quote isn't in the file, or the saved lines were rewritten. The hover card shows the saved lines over today's with the changed words marked. |
| missing | No such file inside the notebook or its code roots, or it's over 2 MB. |
Verified means the cited text is still in that file at those lines. The sentence it backs can still be wrong: on the 5 graded questions under How well it works, all 53 citations verified and the answers got 17.5 of 21 key facts.
When a code citation drifts, E in the drawer shows the file as it was at the answer's commit beside today's version, and D lists the commits since then that touched those lines. Answers saved before Lectern kept these copies get one the first time they're re-checked, and the card says so.
Demos
Every clip is the web UI on one notebook: the Fastify docs pinned (41 files), with the Fastify 5.12.7 source and an 11-file orders service as code roots. Each caption links the MP4 if the GIF is too soft.
Walk the claims, open the source
J / K move the claim cursor and the matching margin card lights up. Hover a citation for the excerpt, O opens the drawer at the cited lines (here service/src/app.ts 14 to 16), ] steps to the next one. Full quality (MP4)
Proof ribbons
V on the app.db answer widens the margin and turns every citation card into an excerpt of its file, with a ribbon from each claim to its lines. J, J, K move the cursor and the ribbons for the other claims thin out, Esc puts the margin back. Full quality (MP4)
When the files change under an answer
db.ts got shorter and Plugins.md grew four lines at the top. The clip opens on the app.close() answer (its banner already says 3 of 17 citations got worse), then reopens the app.db answer from history. Its receipt has a Written line (08:06, 10 verified) over a Today line (5 verified, 4 moved, 1 unverified), the changed marks stamp in, and the Plugins.md mark rolls from L9 to L13. Hovering citation 1 shows Saved L8-14 over Now L8-11 with the changed words marked, above a History row of earlier checks. The banner reads 5 of 10 citations got worse since 08:06. Full quality (MP4)
Where a file is cited from
db.ts in the drawer. Every cited line is marked in the gutter: a status glyph where a range starts (lines 4, 8, 9, 10, 12 and 13) and a stem down the rest. Cited by 5 (16 citations) in the header opens the list: the orders-service code map, the flashcards sheet and questions 001, 004 and 006, each row with its status and lines.
What the trail read
L opens the trail on the onRequest answer, map on top, one row per source. On the fastify row (the code root) the square is fastify/lib, grepped twice (first for onRequest, then for hookIterator and runPreParsing), and the line runs on to route.js (read at lines 490 to 619) and hooks.js (read at lines 225 to 284). Citations 1, 2, 3, 4 and 8 are in route.js and 5, 6 and 7 in hooks.js (7 and 8 sit past where the reads ended, the second grep found them). The two marks on the Fastify row (the pinned docs) are Lifecycle.md and Hooks.md, cited as 9 and 10.
Studio
P opens the sheet index (24 recipes, 3 printed in this notebook). The code map has 39 verified citations and 36 nodes, search finds the db plugin node, and Open at line drops you in db.ts at line 8. Full quality (MP4)
Same sheet with Follow code ticked. Play starts at step 1, a packet runs along the first arrows, then the drawer follows each cited step (route.js 561 and 573, orders.ts 7 and 8, route.js 656 and 658). Esc stops it. The drawer covers the right-hand lanes at this window width. Full quality (MP4)
Asked before
Type "Why is app.db undefined in my orders routes after I decorate it in one plugin?" into a new question and a hint shows up under the text: Asked before, Question 001, 10 citations, all still verified. Tab lands on its Open button (Enter there would open Question 001). Nothing gets submitted in the clip. Full quality (MP4)
Command palette
Ctrl+K, type orders, and files, questions and sheets filter as you type. Four Down presses and Enter open orders-store.ts in the drawer. Full quality (MP4)
How well it works
Measured on one notebook (NeoForge 1.21.1: 18 docs, 68 files, 3 code roots, about 350k tokens of pinned shelf). Yours will be different.
| Result | |
|---|---|
| 5 graded questions | 53 of 53 citations verified, 17.5 of 21 key facts |
| Fast ask through MCP | about 2 cents, 8 seconds |
| Deep ask | about 43 cents, 30 seconds |
| New conversation on Opus, shelf cached | about 30 cents |
| Cold shelf load | about $3 |
[!WARNING] That $3 is the one to watch. The first ask per notebook and model loads the whole shelf into the cache and pays for it, after that it stays warm as long as you ask something within the hour (on the API engine that's a one-hour cache entry, which costs 2x input to write and a twentieth to read). Use fast mode (Haiku) for the "where is X" kind of lookups.
Settings
The cog in the top bar (or the engine label, or Settings in the Ctrl+K palette). Everything saves to settings.json in the home folder and applies straight away, except the two marked restart.
| Setting | Env var | What it's for |
|---|---|---|
| Anthropic API key | ANTHROPIC_API_KEY |
What Lectern answers with. Only ever shown back as its last four characters. |
| Workspace id | ANTHROPIC_WORKSPACE_ID |
Only for a key made outside a workspace (starts with wrkspc_). Without it those keys get a 400. |
| Claude Code binary | CLAUDE_BIN |
Path to claude when it isn't on PATH. Restart. |
| Projects folder | LECTERN_PROJECTS_DIR |
Where the first-run screen looks for projects. Your home folder when empty. |
| Clone size cap (MB) | LECTERN_CLONE_MAX_MB |
A git checkout over this gets deleted again. 1024 when empty. |
| Allow private URLs | LECTERN_ALLOW_PRIVATE_URLS |
Lets Add URL fetch intranet and localhost pages. |
| Port | PORT |
4317 when empty. Restart. |
| Use my Claude Code login | LECTERN_PREFER_CLAUDE_CODE |
Off by default. Answers questions asked on this machine through the claude you're already signed in to, on your own account. Questions from another device use the API key. |
| Quit when the window closes | LECTERN_QUIT_ON_CLOSE |
Desktop app. Off means closing the window leaves Lectern in the tray, watching your code roots. |
| Quick ask hotkey | LECTERN_QUICK_ASK |
Desktop app. Ctrl+Alt+Space from any app. Off by default because another app may already own that shortcut. |
Each one is also an environment variable, and a value saved in Settings wins over the environment. Clear the field and the environment's value comes back. Over Tailscale the page can show settings but only the machine Lectern runs on can change them.
Engines
API key. This is how you run Lectern. It calls the Anthropic API directly and you pay per token on your own key. It answers from every device that can reach it, including a phone over Tailscale.
Your Claude Code login (off by default). If you use Claude Code yourself, you can switch on Use my Claude Code login in Settings (or set LECTERN_PREFER_CLAUDE_CODE=1) and Lectern drives your own unmodified claude -p headless for the questions you ask on this machine. It runs on your account under your plan's terms, so check those. Lectern starts the claude you already signed in to and never reads or stores Claude credentials. It only answers on this machine: a question from another device (a phone over Tailscale, say) uses the API key, and a conversation that started on the login refuses follow-ups from there with a 403. The login is never picked for you, with no API key and no switch Lectern has no engine and asks for a key. A hook keeps claude's Read, Grep and Glob inside the notebook and its code roots.
With the switch on, this machine uses the login and everything else uses the API key. With it off, a set key is used everywhere. --engine api or --engine claude-code on the CLI picks one and errors out if it isn't set up, and lectern mcp follows the switch. A follow-up stays on the engine its conversation started on.
Use it from Claude Code or Cursor (MCP)
Install globally first so lectern is on your PATH.
[!TIP] Installed the desktop app with Lectern Setup.exe? Settings has a Connect Claude Code and a Connect Cursor button that register
lectern mcpto run through the installed exe, so you don't need Node or npm. Connect Cursor shows what it will add tomcp.jsonbefore writing it and keeps the old file asmcp.json.bak. The portable Lectern.exe can't do this because it unpacks to a new temp folder on every start, so Settings shows the npm commands to copy instead.
Claude Code:
claude mcp add lectern --scope user -- lectern mcp
Cursor, in ~/.cursor/mcp.json:
{
"mcpServers": {
"lectern": { "command": "lectern", "args": ["mcp"] }
}
}
list_notebooks, recall, search, read_source, verify, list_artifacts, get_artifact, check_notebook and submit_artifact never call a model and come back in well under a second. ask and generate do and cost money. recall looks through the answers, notes and sheets you already saved, in every notebook, so Claude Code can check them before it pays for an ask. The 24 Studio recipes are also slash commands in Claude Code (/mcp__lectern__diff-review): the agent reads the notebook with the free tools and writes the sheet, and submit_artifact checks it and saves it, so it costs nothing. The web server doesn't need to be running. Arguments and protocol details are in docs/mcp.md.
Lectern MCP questions
How does Lectern verify citations?
It checks every citation against the actual file and line number, comparing the saved quote or line range to the current state of the file on disk.
Can I use Lectern with Claude Code?
Yes, it can run as a Claude Code Stop hook to block an agent from finishing if a citation is broken.
Does Lectern work in CI/CD?
Yes, you can use the CLI to re-check a notebook in your CI pipeline and fail the build if citations become unverified or missing.