Persistent memory for coding agents: an MCP server for Claude Code, Claude Desktop, Cursor and VS Code Copilot. Install once from npm or PyPI, then it runs offline.
Overview
bantamkit is an MCP server: the agent saves what is worth keeping — a preference you stated, a decision, the fix that worked — and recalls it next session instead of asking you again. It works with , , , and any stdio MCP client. Install it once from or ; after that it starts . Then restart the host (in Claude Code, open a new session) and ask the agent to call bantamkit_status. Prefer Python? pip install "bantamkit[mcp]" into a venv you keep, then bantamkit-mcp --install claude. Every route and host is below. - Facts are plain Markdown files under .bantamkit/memory, deduped and held to a byte budget. memory_save and memory_recall do the work; memory_compact and memory_dream keep the store tidy. - Recall reads the project store, any stores you grant in .bantamkit/config.yaml, and your profile store ~/.bantamkit/memory. Saves go to the project store. - --install writes the entry for Claude Code, Claude Desktop, Cursor or VS Code Copilot, backs up any file it edits, and never prompts.
README
bantamkit — memory MCP server for Claude Code, Cursor, VS Code Copilot and Claude Desktop
Give your coding agent a memory that outlasts the session. bantamkit is an MCP server: the agent saves what is worth keeping — a preference you stated, a decision, the fix that worked — and recalls it next session instead of asking you again. It works with Claude Code, Claude Desktop, Cursor, GitHub Copilot in VS Code and any stdio MCP client. Install it once from npm or PyPI; after that it starts offline.
🚀 Quick start
npx -y bantamkit-mcp@latest --install claude # or claude-desktop, copilot, cursor
Then restart the host (in Claude Code, open a new session) and ask the agent to call
bantamkit_status. Prefer Python? pip install "bantamkit[mcp]" into a venv you keep, then
bantamkit-mcp --install claude. Every route and host is below.
✨ What you get
- Memory that persists. Facts are plain Markdown files under
.bantamkit/memory, deduped and held to a byte budget.memory_saveandmemory_recalldo the work;memory_compactandmemory_dreamkeep the store tidy. - Layered by default. Recall reads the project store, any stores you grant in
.bantamkit/config.yaml, and your profile store~/.bantamkit/memory. Saves go to the project store. - One command per host.
--installwrites the entry for Claude Code, Claude Desktop, Cursor or VS Code Copilot, backs up any file it edits, and never prompts. - Offline after one install. Both install routes record the server by absolute path, so no launch needs the network or your shell’s PATH.
- Claude Code hooks, if you want them.
--install-hooksputs the memory index in front of each new session, surfaces matching facts on each prompt, and nudges a save at the end of a long session that saved nothing (docs/hooks.md). - More than memory. JSON Schema validation, a token ledger read off the host’s transcripts, a skill-catalogue audit, and shift-work tools that plan and hand off multi-step jobs — the fourteen tools.
- Two runtimes, one store. Pure Node on npm and Python on PyPI read and write the same
files, and every surface is compared between both runtimes by a conformance suite
(
node tools/conformance/run.mjs --all). - A Python library for small models, too.
pip install bantamkitlifts small-model agents (~1B–8B, any OpenAI-compatible endpoint): malformed output, unreviewed answers, forgotten context and runaway loops are absorbed by code, and a bundled eval suite measures the uplift.
📑 Contents
| Topic | What you’ll find |
|---|---|
| Install the MCP server | Three ways to set it up — pick one |
| Install once, run offline (recommended) | One command; later launches need no network |
| Run with npx at every launch | The online form, and why it hangs offline |
| Install with Python (PyPI) | A venv you keep; a wheelhouse for no-network machines |
| Connect to a host | The same five steps for every host |
| Connect to Claude Code | --install claude, claude mcp list, claude mcp remove |
| Connect to Claude Desktop | claude_desktop_config.json per OS |
| Connect to Cursor | ~/.cursor/mcp.json |
| Connect to VS Code (GitHub Copilot) | mcp.json with the servers key |
| Connect other MCP clients | Codex and any stdio host |
| Configuration | Every flag and environment variable, with its default |
| Update | --update, then restart the server |
| Troubleshooting | Timeouts, Connection closed, refusals, the wrong store |
| What it serves | 14 tools, one prompt, two resource templates |
| Use it as a Python library | pip install bantamkit and a minimal agent |
| Recommended defaults | Which components to attach, measured on four models |
| Documentation | Every page under docs/ |
| Repo layout | What lives where |
📥 Install the MCP server
Two implementations of one server — Node on npm, Python on PyPI — share one memory store on disk. To just try it:
npx -y bantamkit-mcp --assets-root # Node, no Python required
pipx run --spec "bantamkit[mcp]" bantamkit-mcp --assets-root # Python
A host launches the server every session, so what matters is whether each launch needs the network. Pick one of the three ways below.
Install once, run offline (recommended)
npx -y bantamkit-mcp@latest --install claude # or claude-desktop, copilot, cursor
This runs npm install --prefix ~/.bantamkit/mcp once and records
~/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js, both absolute.
No later launch needs npx, the registry or your PATH, and it never downgrades a newer kept
install.
- The recorded node is one version of node. Switch away from it and re-run with
--force. - Replacing an old
npxentry needs--force(Claude Code:claude mcp removefirst). - Installing into another host while offline: plain
npx -yhangs before bantamkit starts. Usenpx --offline -y bantamkit-mcp@ --install, or the kept install’s own CLI:~/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js --install.
Measurements: docs/install.md → MCP server: measured install detail.
Run with npx at every launch
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}
This asks the registry on every launch. Offline it fails silently: with a warm cache,
npx -y bantamkit-mcp, npx -y bantamkit-mcp@latest and a pinned version each hung to the 45 s
bound with 0 bytes on stdout, and the host reports only its own handshake timeout.
npx also caches what latest resolved to, so add @latest or pin a version
(why).
Install with Python (PyPI)
pip install "bantamkit[mcp]" # into a venv you keep, not a pipx run
bantamkit-mcp --install claude # or claude-desktop, copilot, cursor
--install records the venv’s console script by absolute path with "args": [], so no launch
needs the network. With no network at all, pip download a wheelhouse on a machine with the
same OS, CPU architecture and Python version, then pip install --no-index --find-links:
steps.
🔌 Connect to a host
--install (claude, claude-desktop, copilot, cursor) writes the entry. It backs
the file up first, refuses an entry that differs unless you pass --force, and never prompts —
so it behaves the same in a terminal, in CI and inside another agent. With Python, run
bantamkit-mcp --install from your venv instead of the npx line.
Each host below has the same steps: 1 command, 2 file, 3 entry, 4 confirm,
5 undo or re-run. The entry’s command and args depend on the install route:
| Route | command |
args |
|---|---|---|
| npm, install once | /absolute/path/to/node |
["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"] |
| Python venv | /absolute/path/to/env/bin/bantamkit-mcp |
[] |
| npx every launch | npx |
["-y", "bantamkit-mcp"] |
For JSON hosts, a quick check of the recorded command: run it in a terminal — with nothing on
stdin it prints usage: bantamkit-mcp … and exits 0.
Connect to Claude Code
-
Command:
npx -y bantamkit-mcp@latest --install claude -
File: none edited directly — it runs
claude mcp add bantamkit -s user --(user scope, every project), because~/.claude.jsonalso holds host state that is not MCP config. -
Entry: printed as
ran : claude mcp add bantamkit -s user --. -
Confirm:
claude mcp listprintsbantamkit: - ✔ Connected(Claude Code 2.1.272; run it outside a project whose.mcp.jsonalso names bantamkit, or it prints[Conflicting scopes]). In a session, ask the agent to callbantamkit_status. -
Undo / re-run:
--forcedoes not reach Claude Code, and a second add fails withMCP server bantamkit already exists in user config. Remove first:claude mcp remove bantamkit -s user npx -y bantamkit-mcp@latest --install claude
Connect to Claude Desktop
-
Command:
npx -y bantamkit-mcp@latest --install claude-desktop -
File: macOS
~/Library/Application Support/Claude/claude_desktop_config.json· Windows%APPDATA%\Claude\claude_desktop_config.json· Linux~/.config/Claude/claude_desktop_config.json -
Entry (key
mcpServers):{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}} -
Confirm: it prints
installed bantamkit into claude-desktopwith file, key and command. Fully quit and reopen Claude Desktop, then ask it to callbantamkit_status. -
Undo / re-run: there is no uninstall flag — delete the
bantamkitentry or restoreclaude_desktop_config.json.backup-. A matching re-run printsbantamkit is already installed in claude-desktop and matches; a differing entry needs--force.
Connect to Cursor
-
Command:
npx -y bantamkit-mcp@latest --install cursor -
File:
~/.cursor/mcp.jsonon every OS (%USERPROFILE%\.cursor\mcp.jsonon Windows);.cursor/mcp.jsonfor one project, by hand. -
Entry (key
mcpServers):{"mcpServers": {"bantamkit": {"command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}} -
Confirm: it prints
installed bantamkit into cursorandkey : mcpServers. Restart Cursor and ask the agent to callbantamkit_status. -
Undo / re-run: delete the entry or restore
mcp.json.backup-. To replace a differing entry, such as an oldnpxone:npx -y bantamkit-mcp@latest --install cursor --force
Connect to VS Code (GitHub Copilot)
-
Command:
npx -y bantamkit-mcp@latest --install copilot -
File: macOS
~/Library/Application Support/Code/User/mcp.json· Windows%APPDATA%\Code\User\mcp.json· Linux~/.config/Code/User/mcp.json;.vscode/mcp.jsonfor one workspace, or MCP: Open User Configuration, by hand. -
Entry — the key is
servers, notmcpServers, plus"type": "stdio". This is the detail that catches people out:{"servers": {"bantamkit": {"type": "stdio", "command": "/absolute/path/to/node", "args": ["/Users/you/.bantamkit/mcp/node_modules/bantamkit-mcp/dist/cli.js"]}}} -
Confirm: it prints
installed bantamkit into copilotandkey : servers. Restart VS Code and ask Copilot to callbantamkit_status. -
Undo / re-run: delete the entry or restore
mcp.json.backup-;--forcereplaces a differing entry.
Connect other MCP clients
Any stdio MCP client runs the same command/args; nothing is host-specific. Codex and a
generic JSON config: docs/mcp.md → Client setup. Hand-written forms
for every host: npm README ·
Python README.
🔧 Configuration
Flags go in the entry’s args; environment variables in its env block (or
claude mcp add -e NAME=value). Both runtimes print the same --help.
| Setting | What it does | Default | Example |
|---|---|---|---|
BANTAMKIT_MEMORY_DIR |
Pins the store to one absolute path; a missing or relative path refuses at startup | unset: nearest existing .bantamkit/memory at or above the start directory |
"env": {"BANTAMKIT_MEMORY_DIR": "/abs/project/.bantamkit/memory"} |
--store STORE |
One store, layering off; outranks BANTAMKIT_MEMORY_DIR |
off (layered) | "--store", "/abs/store" |
--start START |
Where store discovery starts; not with --store |
cwd | "--start", "/abs/project" |
| Layered memory | Recall reads the project store, stores granted in .bantamkit/config.yaml, and ~/.bantamkit/memory; saves go to the project store |
on | docs/memory.md → Layers |
--k K |
Default recall budget | 3 |
"--k", "5" |
--index-budget BYTES |
Memory index byte budget | 24000 |
"--index-budget", "32000" |
BANTAMKIT_EVENT_LOG |
Logs tool outcomes as JSONL | off; on → /events/mcp.jsonl; other values are a path |
"env": {"BANTAMKIT_EVENT_LOG": "on"} |
BANTAMKIT_RETENTION |
The daily Retention job: deletes session read ledgers older than 7 days, folds log lines older than 30 days, archives closed .shiftwork jobs 7 days after they close (verified before delete) |
on; off (or 0/false/no) turns it off |
"env": {"BANTAMKIT_RETENTION": "off"} — docs/storage.md |
BANTAMKIT_INDEX_DIR |
Where the derived recall indexes live (hot and cold); deleting them loses nothing | ~/.bantamkit/index |
"env": {"BANTAMKIT_INDEX_DIR": "/abs/scratch/index"} |
BANTAMKIT_ASSETS |
Your own asset pack (skills, rubrics, schemas) | the pack inside the package | "env": {"BANTAMKIT_ASSETS": "/abs/my-assets"} |
BANTAMKIT_HOST_LOG_ROOT |
Where --mcp-report finds the host’s MCP logs |
macOS ~/Library/Caches/claude-cli-nodejs; elsewhere unset |
BANTAMKIT_HOST_LOG_ROOT=/abs/logs bantamkit-mcp --mcp-report |
BANTAMKIT_PRICES |
Price table for the token ledger | pricing/default.json in the asset pack |
"env": {"BANTAMKIT_PRICES": "/abs/prices.json"} |
--which |
Where a checkout launcher resolved its halves — only tools/bantamkit-mcp and tools/bantamkit-mcp-node, not the npm/PyPI package |
— | tools/bantamkit-mcp --which |
Don’t add --store by reflex: the layering is most of the value. One-shot commands that print
and exit: --install {claude,claude-desktop,copilot,cursor} (with --force),
--install-hooks / --remove-hooks (with --yes), --hook, --update,
--assets-root, --mcp-report, --statusline.
More: store binding ·
pinning ·
event log · prices.
🔄 Update
npx -y bantamkit-mcp@latest --update # patches the kept install at ~/.bantamkit/mcp
npx -y bantamkit-mcp@latest --assets-root # npx CACHES; without @latest you get an old resolve
npm i -g bantamkit-mcp@latest # global npm install
pip install -U "bantamkit[mcp]" # PyPI (pipx upgrade bantamkit · uv tool upgrade bantamkit)
git pull && npm ci --prefix runtime-ts && npm run build --prefix runtime-ts # a checkout: dist/ is build output
--update (check the package index and update this install if it differs, then exit) patches a
registry install or a kept install to exactly the version it compared, and reports success only
after the install says so; any other shape it refuses with exit 1 and names the manual route.
It is the only network access here, and only when you type it.
Then restart the server in the host (/mcp → reconnect in Claude Code; a full restart of
Claude Desktop) — a running server keeps the code it started with. bantamkit_status prints the
version and the build_id of the code answering you; a new version with an old build_id
means an old process. Per-install table: npm README → Updating.
🩺 Troubleshooting
| Symptom | Fix |
|---|---|
| The host times out; the server never answers | The entry uses npx with a registry spec and the network is down. Use Install once, run offline |
ENOENT from the host |
A GUI host does not read your shell rc, so npx/node is not on its PATH. --install records absolute paths |
| Connection closed at startup | Older builds crashed when a GUI host started them in /. Update; see docs/mcp.md |
already has a bantamkit entry with different settings … re-run with --force to replace it |
Re-run with --force; the old file is kept as .backup- (.backup-.1 and on for a later write the same day) |
MCP server bantamkit already exists in user config |
claude mcp remove bantamkit -s user, then install again |
| The server stopped launching after a node change | npx -y bantamkit-mcp@latest --install --force with the node you have now |
| Recall finds nothing, or the wrong store | Set BANTAMKIT_MEMORY_DIR; the reply names the store it searched (the three states) |
🧰 What it serves
Both servers serve the same 14 tools, the bantamkit_status prompt and two resource templates
(bantamkit://skills/{name}, bantamkit://rubrics/{name}):
| Tool | What it does |
|---|---|
memory_save |
store one durable fact, deduped and budgeted |
memory_recall |
retrieve facts matching a query |
memory_compact |
archive the stalest facts to fit the index budget |
memory_dream |
consolidate facts the project and profile layers hold under the same name |
validate_json |
validate a document against a JSON Schema |
skill_audit |
audit a skill catalogue for findings |
shiftwork_clock_in |
open a unit of work and get its brief |
shiftwork_clock_out |
close a unit with status and accounting |
shiftwork_status |
read-only progress summary of a checkpoint |
shiftwork_plan |
read-only: which units of a checkpoint its depends_on graph permits to run at once. Never moves the cursor |
work_plan |
turn any {id, depends_on, priority} graph into the batches that may run in parallel, plus the widest fan-out |
token_ledger |
what a session cost, read off the host’s transcripts |
bantamkit_status |
is bantamkit working, and which build: version, build_id, store health against its budget |
build_identity |
report the fingerprint of the source on disk, not the executing code — useful when a machine carries two installs under one name |
🐍 Use it as a Python library
pip install bantamkit
Editable install and runtime differences: docs/install.md,
docs/porting.md. Copy-paste start: examples/.
from bantamkit import Agent, CritiqueGate, Memory, OpenAICompatible, Tool, ToolDef
client = OpenAICompatible(base_url="http://localhost:11434/v1", model="qwen2.5:7b-instruct")
price_lookup = ToolDef(
tool=Tool(
name="price_lookup",
description="Get the unit price of an item",
parameters={
"type": "object",
"required": ["item"],
"properties": {"item": {"type": "string"}},
},
),
handler=lambda item: f"{item} price: 25",
)
agent = Agent(client=client, tools=[price_lookup]).use(
Memory(store="./.bantam-memory"),
CritiqueGate("task-completion"),
)
result = agent.run("What does a widget cost? Remember it for next time.")
print(result.output, result.usage.total)
📊 Recommended defaults
Measured on the bundled 22-task suite across four models, 528 runs each. Numbers and caveats: docs/usage.md → Recommended defaults.
- Always attach
Memory— the biggest single mover on every model measured. - Skip the blind
CritiqueGateon small instruct models — ≤6 passes at 2–3.5× bare’s tokens. - Don’t credit a rubric edit without a bar — the non-fragile anchor set is the floor.
- Use
structured()for schema’d output — zero schema retries in 2,112 runs. - Attach
FileAccessGraphwhen the agent reads files, on ~4B-class models. full(memory + schema + grounded critique) is a 4b-reference result — 66/66 there only.- Prefer
GroundedCritiqueGateoverCritiqueGatewhen the agent has tools — same 4b scope.
📚 Documentation
| Page | Covers |
|---|---|
| Install | Requirements, editable install, endpoints, BANTAMKIT_ASSETS, measured MCP install detail |
| Architecture | The 5-layer model and the no-mixing rule |
| Usage | Client, agent, tools, components, structured(), errors, recommended defaults |
| Memory | Store layout, the four ops, dedupe and budget, layers, the operator CLI (python -m bantamkit.memory / bantamkit-memory) |
| File-access graph | The read ledger and the file_graph query tool |
| Eval | Running the suite, the config matrix, current results |
| MCP | bantamkit-mcp for Claude Code, Codex and any MCP client |
| Event log | The JSONL outcome log, its vocabulary and the 1 MiB cap |
| MCP report | --mcp-report: the host’s MCP log joined with the event log |
| Status line | bantamkit-mcp --statusline and the Claude Code statusLine adapter |
| Hooks | --install-hooks: what each Claude Code hook entry does and what it costs |
| Status | bantamkit_status, line by line, and the degraded footer |
| Token ledger | token_ledger: what a session cost, and the price table |
| Skill audit | skill_audit: what the skill catalogue costs every session |
| Shift-work | Checkpoint contract and clock-in/clock-out driver (experimental) |
| Porting | The Node port, PyScalar, and where the two runtimes deliberately differ |
| Conformance | The two-runtime diff harness and what a ruling: pins |
| Releasing to npm | What ships and the pre-publish checklist |
📁 Repo layout
| Path | What |
|---|---|
runtime-py/ |
The Python runtime (bantamkit package) and its test suite |
runtime-ts/ |
The pure-Node MCP server (bantamkit-mcp on npm) |
assets/ |
Language-agnostic asset pack: skills, rubrics, tool schemas, eval tasks |
examples/ |
Runnable starter scripts (quickstart, structured output, layered memory) |
tools/ |
Repo tools that ship outside the wheel (e.g. the shift-work driver) |
docs/ |
This runbook |
Design notes live in docs/superpowers/specs/.
Install
npx -y bantamkit-mcpConfiguration
{"mcpServers": {"bantamkit": {"command": "npx", "args": ["-y", "bantamkit-mcp"]}}}