Constant-size memory for long-form AI writing. Chapter 1000 costs the same tokens as chapter 10.
311
Your AI writing assistant remembers chapter 3 when it writes chapter 300 — and the prompt never gets bigger.
One line in your MCP config. No account, no key, no sign-up.
Claude Desktop — claude_desktop_config.json
Cursor — ~/.cursor/mcp.json
Windsurf, Cline, Zed, Continue — same shape
{
"mcpServers": {
"longform-memory": {
"command": "npx",
"args": ["-y", "longform-memory-mcp"],
"env": { "LONGFORM_MEMORY_PROJECT": "my-novel" }
}
}
}
Claude Code
claude mcp add longform-memory -e LONGFORM_MEMORY_PROJECT=my-novel -- npx -y longform-memory-mcp
Restart your client. Then say: "remember this chapter" and "recall context for chapter 12".
Write anything long with an LLM — a novel, a manual, a course, a serialised story — and you hit the same wall twice.
Withhold the past and it contradicts itself. A character who died in chapter 12 speaks in chapter 30. The key planted in chapter 3 is never mentioned again.
Send the past and you cannot afford it. Pasting every prior summary is O(n): tens of thousands of tokens by chapter 100, and by chapter 1000 it does not fit at all. Filling the window also makes things worse — models skip the middle.
Both are the same problem wearing two hats: there is no budget ceiling.
memory in the prompt
│
61k ─┤ ╭──── just paste it all
│ ╭─────╯
30k ─┤ ╭─────────────╯
│ ╭─────────────╯
4k ─┤════════════╪═════════════╪═════════════╪════ longform-memory
└──────┬─────┴──────┬──────┴──────┬──────┴────
10 100 500 1000 chapter
Measured on a real 1000-chapter book: 61,331 tokens → 4,396, and going from chapter 500 to chapter 1000 grew the block by 2 tokens.
| tool | what it does |
|---|---|
recall_context | The main one. One paste-ready block: entity states, recent chapters, a sampled skeleton of the whole arc, and older material retrieved as relevant — at a fixed token size, with per-section accounting. |
remember_chapter | Folds a finished chapter in: summary, entity state changes, thread moves. Optionally stores the prose locally. |
list_open_threads | What the document promised the reader and has not delivered, most urgent first, overdue flagged. |
check_continuity | Characters who left the story and act again; threads past their deadline. Quotes the sentence it tripped on. |
entity_card | One character/place/object: current state plus the chapter-by-chapter timeline of how it got there. |
search_memory | Find chapters by what happened in them, reaching past the recent window. BM25 offline; true semantic search if you configure your own embedding endpoint. |
┌─ recall_context(12) ──────► paste into your drafting context
│
├─ list_open_threads(12) ───► what's still owed
│
├─ …write chapter 12…
│
└─ remember_chapter(12, …) ─► summary · entity states · thread moves
Step four is where the value is made. Your assistant is the model doing the extraction — it just read the chapter, so it already knows what changed.
This server has no LLM inside it. The client calling it already is one.
So remember_chapter does not run an extraction pass over your prose — it asks your assistant to hand over what it understood while reading. That single decision is why there is:
Everything lives in plain files under ~/.longform-memory/<project>/:
~/.longform-memory/my-novel/
├── events.jsonl # append-only: summaries, entity states, threads
└── chapters/
├── 000001.txt # your prose, only if you passed `text`
└── 000002.txt
Readable, greppable, rm-able, and yours. No telemetry. The only outbound request this package can ever make is to an embedding endpoint you configure yourself — and if you configure none, the code path never runs.
Why an append-only log rather than SQLite: this server is launched by npx inside someone else's editor, and a native module that fails to build there is not a degraded experience — it is a server that never starts, and you would never find out why.
| variable | default | meaning |
|---|---|---|
LONGFORM_MEMORY_PROJECT | default | Which document. One entry per book, or pass project per call. |
LONGFORM_MEMORY_HOME | ~/.longform-memory | Where memory is stored. |
LONGFORM_MEMORY_EMBED_URL | — | OpenAI-compatible /embeddings endpoint. Optional. |
LONGFORM_MEMORY_EMBED_KEY | — | Your key, for your endpoint. |
LONGFORM_MEMORY_EMBED_MODEL | — | e.g. text-embedding-3-small. |
All three embedding variables must be set together — a half-configured endpoint that quietly does nothing is worse than no feature. search_memory always states which mode actually ran.
check_continuity covers the part a model is bad at — remembering exactly, across a thousand chapters.The server is a thin adapter; everything is callable directly.
import { recallContext, rememberChapter } from 'longform-memory-mcp';
await rememberChapter({
project: 'my-novel',
chapter: 12,
summary: 'Ines burns the letter and lies to her brother about it.',
entities: [{ name: 'Ines', state: 'lying to Tomas', note: 'first outright lie' }],
threads: [{ summary: 'what the letter actually said', deadlineChapter: 30 }],
});
const { recall } = await recallContext({ project: 'my-novel', chapter: 13 });
console.log(recall.text); // paste-ready block
console.log(recall.sections); // { entity: { usedTokens, kept, dropped }, … }
The budgeting core is published separately, with no dependencies at all:
longform-memory (npm) · longform-memory (PyPI).
npm install
npm test # 54 tests, including a real stdio protocol round-trip
npm run build
The test suite spawns the built binary and speaks JSON-RPC to it, because the failures that only appear there are the expensive ones — a non-executable bin, a schema the SDK rejects, a stray write to stdout corrupting the transport.
MIT © Emberspun. Built for Emberspun, an AI book writer for self-publishers — this memory layer runs there on every chapter.
Tool descriptions tell a model what a call returns. They cannot tell it that
recalling after drafting is useless, or that a [T3] from one chapter must not
be quoted at another. That is sequencing and judgement, and it lives in a skill:
emberspun/longform-memory-skill
git clone https://github.com/emberspun/longform-memory-skill.git \
~/.claude/skills/longform-writing
Kept in its own repository so there is exactly one copy — the same text in two places drifts, and the stale one is the one somebody reads.
Content type
Image
Digest
sha256:d445a2a23…
Size
58.5 MB
Last updated
about 1 month ago
docker pull lenfenn/longform-memory-mcp