willow-mcp
Agent-neutral MCP server with persistent memory (SOIL + Postgres KB) and a sandboxed task queue. Manifest-based ACL; works with any stdio MCP client.
Install / Use
claude mcp add willow-memory -- npx -y github:willow-memory/willow-mcpIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Data & AnalyticsSupported Platforms
Skill content
View source on GitHubwillow-mcp
Agent-neutral MCP server with persistent memory and task execution. Works with any MCP client: Claude Code, Claude Desktop, Cursor, or any custom agent that speaks stdio MCP.
Corpus memory: the whole Willow constellation — the code, human, and collaboration corpora assembled and queryable — lives in the sovereign
willow-composerepo. The hub calls it; it doesn't live here (keeping the hub lean).
Three storage backends in one server:
- SOIL store — SQLite-backed local key/value store with full-text search and soft delete
- Postgres knowledge base — multi-keyword searchable knowledge graph
- Kart task queue — sandboxed task executor for shell commands and scripts
Every tool call is authorized via a filesystem-based manifest ACL — no ACL database, no external auth service. See Authorization.
Install
pip install willow-mcp
Requires Python 3.11+. Postgres is optional — SOIL store works standalone.
willow-mcp-init # scaffold $WILLOW_HOME (idempotent)
willow-mcp-compile --force # compile manifests (use product venv — see below)
willow-mcp-sign-seed hanuman # ratify home seed + detach-sign (operator terminal only)
willow-mcp-compile-persona hanuman # seed → personas/hanuman.md (AS-7)
Local sandbox (one command)
To take a fresh clone to a working stdio server — venv, editable install,
scaffolded $WILLOW_HOME, compiled manifests, and (best-effort) a local
Postgres with every table created — run:
bash scripts/sandbox-bootstrap.sh # idempotent; ends with a live diagnostic_summary
On a bootstrapped sandbox the schema mappings for the tables the script itself
just created are auto-confirmed (so task_* and knowledge writes work
immediately), behind three guards: existing mapping artifacts are never
touched, every field must resolve exact, and the live columns must equal the
repo's own DDL — an adopted/foreign database always falls through to the
human schema_confirm_mapping path (see src/willow_mcp/sandbox_confirm.py).
It scaffolds a repo-local, gitignored .willow/ so the sandbox never touches
your real fleet state. Postgres is optional and handled best-effort (the SOIL
store stands alone); pass WILLOW_SKIP_PG=1 for a SOIL-only stand-up, or
WILLOW_PG_BOOTSTRAP_ROLE=1 on a bare cluster where your OS user has no
Postgres role yet.
A fresh Postgres database needs willow-mcp's tables. On a shared fleet DB they
already exist; on a standalone install, apply the DDL in
docs/schema/ (knowledge, agents, routing_decisions,
tasks — the four diagnostic_summary checks for, plus frank_ledger for the
FRANK governance chain). The bootstrap script applies all of them for you. Each
knowledge/tasks write path stays locked behind schema_confirm_mapping
until you confirm the mapping once.
The fleet (one command up)
sandbox-bootstrap.sh proves this server works alone. Two sibling packages
attach to it — jeles, the verified-corpus
organ this package already depends on for institutional search, and
nestor, which mirrors its hash-chained
ledger into FRANK — and standing all three up together is a different claim:
bash scripts/fleet-standup.sh # idempotent; ends with six seam checks
It runs the sandbox bootstrap, installs the jeles and nestor checkouts
editable into that same venv (across two venvs their imports silently
resolve to whatever PyPI last published), seats nestor in the gate, writes
$WILLOW_HOME/fleet.env, and then checks that the seams actually join:
| Seam | What crosses |
|------|--------------|
| co-install | one venv, all three resolving to the checkouts |
| shared SOIL store | jeles' corpus and this server's Store on one SQLite file |
| gap forward | a jeles corpus miss → gap_log, through the manifest ACL |
| institutional search | this server's willow_institutional_search → jeles' ~60 collections |
| FRANK mirror | a nestor ledger entry → frank_append → the hash chain |
| nugget bridge | a jeles nugget → nestor, as a draft — never a seal |
Point JELES_REPO / NESTOR_REPO at the checkouts if they are not siblings of
this one. Re-check any time with .venv/bin/python scripts/fleet_seams.py
(--json for machine output); every seam it reports as passing was exercised
by writing real data through the real path, because a seam that is only
imported is a seam that has not been tested.
PATH note:
~/.local/bin/willow-mcpis often the fleet shim (sap_mcp.py), not this product. Use the venv binary from wherever you ranpip install willow-mcp(orpip install -e .in a clone) — e.g..venv/bin/willow-mcp-compile --forceor.venv/bin/willow-mcp compile-agents --force— not a barewillow-mcponPATH.
Runtime layout: docs/design/product-layout.md (LOCKED).
Tools
| Tool | Description |
|------|-------------|
| store_put | Write record (JSON object) to SQLite store |
| store_get | Read record by record_id |
| store_list | List all records in a collection |
| store_update | Update an existing record |
| store_search | Multi-keyword AND search in a collection |
| store_delete | Soft-delete a record by record_id |
| store_search_all | Search across all collections |
| store_collections | List the SOIL collections you can see (narrowed to your store_scope) — learn the collection names without running a search |
| store_purge_collection | Bulk soft-delete every record in a collection (e.g. leftover test/scratch data). Reversible (archive-don't-delete — the store.db is kept); requires confirm=<collection name> and stays within your store_scope |
| store_stats | Per-collection live-record counts (within your store_scope), largest first, plus store-wide totals — the numeric companion to store_collections for spotting a bloated or polluted collection |
| knowledge_ingest | Add a knowledge atom (requires a confirmed schema mapping — see schema_confirm_mapping) |
| knowledge_search | Multi-keyword search in the Postgres knowledge base |
| kb_at | Fetch a single knowledge atom by ID |
| kb_promote | Change an atom's domain (requires a confirmed schema mapping) |
| knowledge_flag | Attach an integrity flag to an existing atom (knowledge_curate; tags-based, idempotent) |
| knowledge_retract | Tombstone an atom in place — hidden from default search, still readable via kb_at (knowledge_curate) |
| kb_journal | Add a journal-domain knowledge atom (requires a confirmed schema mapping) |
| kb_startup_continuity | Fetch atoms tagged/domained for startup continuity |
| schema_confirm_mapping | Confirm (optionally correct) a table's column mapping, unlocking its write tools. preview=True dry-runs it and renders a sample row so you can see what each field actually resolves to before trusting a name match — see docs/design/schema-adaptation.md |
| gap_log | Log or bump a "we don't know this yet" entry (fleet-wide backlog, SOIL-only, no Postgres needed) — see docs/design/gap-backlog.md |
| gap_list | List gaps, most-asked first — filter by topic and/or status (open/resolved/promoted) |
| gap_resolve | Mark a gap as being worked or answered — bookkeeping only, does not write to the knowledge base |
| gap_delete | Soft-delete a single gap by id — clear junk/test entries without disturbing real gaps. Reversible (archive-don't-delete) |
| gap_purge_topic | Soft-delete every gap under an exact topic in one call — bulk cleanup without the per-call rate limit. Promoted gaps (they point at a landed atom) are left intact; requires confirm=<topic> |
| gap_promote | Turn a resolved gap into a knowledge atom. Requires answer, at least one source, and confirmed_by; writes through the same schema-confirmation gate as knowledge_ingest and closes the gap out |
| nest_scan | Walk a drop folder, extract + classify its files by meaning, and write a canonical SQLite Nest DB. Returns counts only; dry_run=True (default) reports without writing — see docs/NEST.md |
| nest_status | Counts for a seeded Nest DB — sources by status, fragments by type, topical categories by size. Structure only; filename-labels are walled and counted as uncategorised |
| nest_digest | A one-page Markdown map of a Nest DB — the walled view (person names, the date timeline, and filenames suppressed). The full digest is a local-CLI affordance only, never returned over MCP |
| nest_promote | Promote a Nest's structure — counts, curated category names, redacted secret kinds, never content — into the knowledge base via the same core write as knowledge_ingest. dry_run=True returns the atoms that would be promoted |
| nest_intake_scan | Live drop-folder router: classify new files in a drop zone by filename into a track and stage a review queue. Non-destructive — nothing moves until nest_intake_file |
| nest_intake_queue | List the pending review queue with the track the classifier predicted for each file |
| nest_intake_file | File a staged item: move the file to its predicted track's destination, or override_dest to correct it. An override feeds the correction counter |
| nest_intake_skip | Skip a staged item — leave the file, record the decision |
| nest_intake_flags | List open rule-delta flags — patterns overridden often enough that the classifier proposes a rules change (a human ratifies) |
| task_submit | Submit task to Kart queue |
| task_status | Check task status |
| task_list | List pending tasks |
| agent_route | Route a task to a target agent, recording the decision |
| agent_dispatch_result | Record the result of a dispatched agent task |
| dispatch_send | Create dispatch packet (meta.json + assignment.md) |
| dispatch_read | Read dispatch assignment and status |
| dispatch_list | List dispatch packets |
| dispatch_accept | Specialist accepts packet (pending → working) |
| handoff_write_v4 | Complete work — handoff.json + closeout.md |
| handoff_read | Read handoff for a dispatch |
| verify_handoff | Orchestrator verifies completion |
| agent_clear | Clear specialist for next packet |
| session_read | Read thin session state file |
| fleet_status | Return the canonical charter fleet.json roster plus Postgres drift diagnostics |
| fleet_health | Task queue counts by status, live worker heartbeats, and whether the queue is stranded |
| frank_read / frank_verify | Read and verify the existing Postgres FRANK hash chain |
| frank_append | Append an established-shape FRANK event (separately gated) |
| envelope_apply | Match an active constitutional grant and write its FRANK citation before returning authority |
| grove_list_channels | List active Grove channels (name, type, description) |
| grove_get_history | Message history from a channel, with since_id polling and limit (max 200) |
| grove_search | Case-insensitive substring search across Grove messages, optionally scoped to one channel |
| grove_watch / grove_watch_all | Non-blocking poll for new messages in one channel, or many at once via a {channel: since_id} cursor map |
| grove_get_thread | A message plus its flags and all its replies |
| grove_bus_receive | Structured bus messages addressed to an agent (or broadcast), priority-ordered |
| grove_inbox | Fleet inbox: @mentions, bus messages addressed to you, and your de
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
82.0kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
ruflo
72.5k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
headroom
72.3kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
CowAgent
47.0kOpen-source super AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install. (formerly chatgpt-on-wechat)
