loading…
Search for a command to run...
loading…
scratchpad-mcp is an MCP server that gives AI agents persistent, token-efficient storage. Eight tools versioned file writes, structured line-diffs since a prior
scratchpad-mcp is an MCP server that gives AI agents persistent, token-efficient storage. Eight tools versioned file writes, structured line-diffs since a prior version, append-only logs with cursor pagination, on-demand summaries with per-version caching, and per-agent quotas. The point is to stop agents from re-reading files they've already seen and re-summarizing documents.
Persistent, token-efficient storage for AI agents. An MCP server that stops your agents from re-reading the same files and re-loading the same context every turn.
agent: "what changed in this file since I last read it?"
server: { diff: [...], current_version: 14 } ← not the whole file
Agents waste tokens. They re-read files they've already seen, re-summarize documents they've already processed, and re-discover state they've already computed. This server gives them a place to put that work and pick it up later in a way the model can reason about cheaply.
Concretely:
All tools take agent_id as their first argument. Operations are scoped to
that agent — agents cannot read each other's files or logs.
| Tool | What it does |
|---|---|
write_file(agent_id, path, content) |
Store content at a path. Auto-versions on every write. Keeps the 10 most recent versions. |
read_file(agent_id, path, since_version?) |
Read full content, or a JSON line-diff against a prior version. If since_version has been pruned, returns full content with version_too_old: true. |
append_log(agent_id, path, entry) |
Append one entry to an append-only log. Returns the new entry ID. |
read_log(agent_id, path, since_entry?) |
Read log entries with cursor pagination. 100 entries per page, has_more flag plus last_entry_id cursor. |
list_files(agent_id, prefix?) |
List files (metadata only) optionally filtered by path prefix. |
delete_file(agent_id, path) |
Delete a file and all its versions and any cached summary. |
summarize_file(agent_id, path) |
LLM-summarize a long file (>8000 chars). Cached per version, so repeat calls on an unchanged file cost nothing. |
get_usage_stats(agent_id) |
Return total bytes, file count, log count, and total operations for an agent. |
read_file with since_version returns a JSON array of chunks:
{
"diff": [
{ "op": "equal", "lines": ["line that didn't change"] },
{ "op": "remove", "lines": ["line that was deleted"] },
{ "op": "add", "lines": ["line that was added"] }
]
}
Line-level diffing is intentional — it's the format agents handle most reliably, and it lets the agent reason about what changed rather than re-processing the whole file.
Paths must match [a-zA-Z0-9/_.-]+, max 255 chars, no leading /, no ..
sequences. Errors name the violated rule.
read_log pageRequires Node 20+ and an Anthropic API key (only for summarize_file).
git clone <this repo>
cd scratchpad-mcp
npm install
npm run build
That produces dist/index.js, the runnable server.
Add to %APPDATA%\Claude\claude_desktop_config.json (Windows) or
~/Library/Application Support/Claude/claude_desktop_config.json (macOS):
{
"mcpServers": {
"scratchpad": {
"command": "node",
"args": ["C:\\path\\to\\scratchpad-mcp\\dist\\index.js"],
"env": {
"ANTHROPIC_API_KEY": "sk-ant-..."
}
}
}
}
ANTHROPIC_API_KEY is only required if you intend to call summarize_file.
The other seven tools work without it.
Optional: set SCRATCHPAD_DB_PATH to override the SQLite location. Defaults
to scratchpad.db in the project root.
Restart Claude Desktop. The server should appear in the MCP servers list with 8 tools.
agent_id is a plaintext tool parameter. There is no authentication: a
caller can claim to be any agent_id, and the server will trust it. This is
deliberate for V1 and works fine for the intended deployment shape, which is:
It is not safe for:
agent_id and read or overwrite their data.If you want multi-tenant, derive agent_id from the caller's API key in a
wrapper layer (this is the V2 plan) or run one process per tenant.
.., leading /, spaces, and any character
outside [a-zA-Z0-9/_.-].list_files prefix matching uses SUBSTR equality (not LIKE) so the SQL
wildcards _ and % never apply, and matching is case-sensitive.err.message — no stack traces, no SQLite paths, no
API keys.summarize_file?The caller. Always.
ANTHROPIC_API_KEY in their config. Their machine, their key,
their bill.anthropicApiKey from its per-run
input. A .actor/entrypoint.sh launcher maps that into the env before
starting the server. Each caller pays Anthropic for their own summaries;
the Actor publisher only collects Apify's per-call fee.If you fork this and intend to host it, do not hardcode an API key into the Dockerfile, the Apify Actor environment, or any config that gets shipped publicly. The other seven tools work without a key, so leaving it unset is a safe default.
This matters — different ways to run the server have different persistence guarantees. Pick the shape that matches your workload.
| Deployment | Persistence | Lost when |
|---|---|---|
| Claude Desktop / Smithery local / direct stdio | Fully persistent on local disk. SQLite file lives at scratchpad.db next to the project. State survives reboots, crashes, anything short of you deleting the file. |
You delete the file. |
| Apify hosted (standby mode) | Session-scoped. State persists across requests within a hot Actor instance. Lost on cold start. | Actor instance recycles: idle for >Idle timeout seconds, hits Max requests per run budget, or you redeploy. |
| Smithery hosted (planned) | TBD — pending Smithery's persistent volume support. |
The Apify shape is great for single-task agent sessions (agent runs for a few minutes, makes dozens of tool calls, scratchpad persists across all of them). It's not the right fit for long-term cross-session memory (agent wants to read back something it wrote yesterday). For that, use the local install today, or wait for v0.2.0 — the roadmap below tracks that work.
A single SQLite file holds everything:
files — one row per (agent_id, path), tracks the current version.file_versions — full content per version, capped at 10 most recent per
file. Pruning happens on every write_file.log_entries — append-only entries, never modified.summaries — per-file summary cache, invalidated by version mismatch.agent_usage — per-agent operation counter for get_usage_stats.Versioning stores full content per version (not deltas) because writes need to be fast and reads need to be unambiguous. Diffs are computed on read by running the two versions through line-level diffing — the cost is paid by the caller asking for the diff, not by every writer.
agent_id from API key instead of taking it as a parameter.MIT — see LICENSE.
Добавь это в claude_desktop_config.json и перезапусти Claude Desktop.
{
"mcpServers": {
"scratchpad-mcp": {
"command": "npx",
"args": []
}
}
}