hive-memory
This MCP server provides a human-gated, local-first memory store plus an agent coordination board.
Search the human's confirmed memory with natural-language queries, vault filters, limits, compact/full output, and vector search where supported.
Propose new memories for human approval; proposals queue and do not become confirmed until the human accepts them.
Manage memory lifecycle: list pending entries, read by id, forget/restore, and discard pending proposals.
Get a short digest of recent confirmed memory to seed a session.
Post status, results, data, or handoffs to the shared board with refs, TTL, stage, and task links.
Read and poll the shared board since a cursor, optionally including an on-duty agent roster.
Run against a local SQLite file with no dependencies, or route to the macOS app for richer ranking, encrypted vaults, and identity features.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@hive-memoryrecall what I decided about the Q3 roadmap"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Apiary Memory MCP
Also known as: Apiary Memory · 记忆蜂巢 · Memory Hive · 蜂巢 ·
apiary-memoryon PyPI andio.github.330899935/apiary-memoryon the MCP Registry (from v0.2.0) · old namesmemory-hive-mcp/hive-memory(v0.1.9 and earlier) still install and still work. Not affiliated with hive.com (team collaboration) or thehive-mcpClaude Code plugin.
Local-first personal memory for AI agents, over MCP. Your agents can search what you have confirmed and propose what they think you should keep; only you can confirm it. Everything lives in one file on your own disk, and nothing is sent anywhere.
It runs on its own. A working SQLite memory store ships inside this package — no account, no cloud, no daemon, no dependencies.
pip install apiary-memoryDesktop app, no terminal: download apiary-memory-0.2.0.mcpb and double-click it.
Measured on 2026-10-27, on one MacBook with the Hive running locally — script and raw output in bench/:
Measure | Result |
Search latency | p95 111 ms, p50 76 ms (warm, includes HTTP) |
Retrieval | correct entry in top-5 for 97.5% of 40 trials |
Corpus | 1,303 entries · 2.39 M chars · 45 days, plaintext only |
Retrieval used each entry's own title as the query — an easy set. It shows the index is complete and ranks correctly on exact terms, not how well it answers a question asked in your own words. Run bench/bench_search.py on your own Hive.
What you get without the app
A complete, if modest, memory server. On a machine with nothing else installed:
Call | What happens |
| answered locally, protocol |
| answered locally, six tools |
| writes to a real database on your disk |
| searches that database and returns ranked entries |
| a digest of what you confirmed most recently |
| read one entry, list what is pending, forget, restore |
| a shared message board for coordinating several agents |
Storage is SQLite at ~/.memory-hive/hive.db by default. Search is lexical — character bigrams
for Chinese, words for Latin script — so it ranks well when the words overlap and finds nothing
when they do not. There are no embeddings and no vector index. Every response says
"mode": "local" so you can always tell which engine answered.
Without the app, the database is plain SQLite: it is not encrypted. That is stated here rather than discovered later — see Honest limits.
Related MCP server: Lumena MCP Server
What the app adds
Apiary Memory for macOS is the same design with the expensive parts built: eight vaults with four of them locked behind a PIN (Argon2id-wrapped key, AES-256 at rest), a daily evolution log, multi-agent identity management, and a UI for reading and confirming. It also answers MCP itself, with richer ranking.
If the app is running, this package uses it and leaves the local file alone. If it is not, the local store answers. You do not have to choose up front:
| Behaviour |
| Ask the app. Use the local store only if the app is unreachable. |
| Never touch the network. Always use the local store. |
| Only the app. A connection failure is an error, not a reroute. |
One rule holds in every mode: if the app is running and answers with an error, that error is returned unchanged. Falling back on a refusal would write your memory into a second database while your client believed it had reached the app. Silent data forking is worse than an error message, so a reply from the app is final. The fallback fires on a connection failure, and on nothing else.
Install
pip install apiary-memory # the server: apiary-memory (was apiary-memory)
# the human's CLI: apiary-memory-cli (was apiary-memory-cli)Python 3.8 or newer. There is nothing else to install — the package uses only the standard
library, and sqlite3 is part of it.
From a checkout:
git clone https://github.com/330899935/apiary-memory
cd apiary-memory
PYTHONPATH=src python -m hive_mcp.stdioConnect a client
Any MCP host that can run a stdio command will work. The minimum is the command; everything else is optional.
Claude Desktop — ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"apiary-memory": {
"command": "apiary-memory",
"env": { "HIVE_MODE": "local" }
}
}
}Cursor — ~/.cursor/mcp.json, same mcpServers shape.
Any host that only speaks HTTP — start the app and point it at http://127.0.0.1:8768/mcp
with the headers X-Hive-Agent and X-Hive-Token. This package is the stdio path; the HTTP
endpoint belongs to the app.
Prerequisite
None, for the local store — install the package and it works. A running app is a prerequisite
only for the app's own features: encrypted vaults, the evolution log, and multi-agent identity.
If you want those, install the Hive app (macOS,
version 1.4.5 or newer) and leave HIVE_MODE at auto.
The six tools
The six tools are the whole surface. They are the same six whether the app or the local store
answers; only the ranking behind them differs — and, for two inputs, whether they exist at all.
The app accepts precomputed embeddings (recall.query_vector, propose.vector); the local
store has no embedder, so tools/list omits those two wherever the local store can answer,
including under auto where the app might stop answering mid-session. A field that would be
accepted and silently ignored is not advertised at all.
The same rule covers wording. recall.query is described as the lexical ranker it is wherever
the local store can answer — words and character bigrams, no embeddings — and as the app's
index-based ranking with query_vector for meaning wherever only the app can answer. A
description is a claim about what will happen to the input, so it is narrowed with the inputs.
Defaults are not narrowed, they are shared. Omit limit and you get 10 from recall and 8 from
get_context; omit compact and bodies come back trimmed; omit ttl on say and the card
lives 24 hours. Both engines answer those numbers identically, because a default is a number in
the schema rather than a capability one engine lacks. store.py holds each one as a named
constant, and the tests compare the answer against the advertised number instead of a second
hand-written copy of it.
Tool | Kind | What it is for |
| read | Search confirmed memory by topic. |
| write | Submit a memory for the human to approve. Lands in a queue; changes no confirmed memory. |
| read/write | Address one entry: |
| read | A short digest of recent confirmed memory, to seed a conversation. |
| write | Post to the shared board so other agents see what was done or handed over. |
| read | Read the board, optionally only what arrived since your last cursor. |
Two properties are worth stating plainly, because they are the product:
proposesucceeding means "queued", not "stored".recallwill not return it until a human confirms it.managehas noapproveaction. There is no path from an agent to a confirmed memory. That is not an omission; it is the design.
Response shapes
tools/list is one surface for both engines, and an answer should be too: a model that has
to branch on which engine replied will eventually branch wrong. board therefore answers
the app's shape, field for field — items, unread, count, cursor, reader — and
cursor is the id of the newest card, the same kind of value the app returns.
The cursor is what a poll carries across an engine switch, which is why it gets the space.
Under auto one call can be answered by the app and the next by the local store. Before 0.1.9
the local engine answered a float epoch timestamp and read the app's card id with float(),
so a cursor fetched from the app came back as a full re-read of the board and nothing said
so; a float sent the other way matched no card id, and the app answered with its newest
limit, equally quietly.
A cursor can still fail to resolve: its card expired (cards live 24 hours by default), or it
was issued by the other engine, whose ids are CB… in the app and msg_… here. Neither
engine can resume from that, so both return the newest window — but this one also sets
since_unknown and a note saying which of those happened. unread counts every live card
after the cursor and count counts what the answer carries, so unread > count means the
page did not cover everything waiting, and the note says so in words.
Three shapes are not unified, because the engines really do hold different data:
a
recallentry names its vaultvaultfrom the local store andwhfrom the app;get_contextreturns one flatdigestlocally and one bucket per warehouse (context, keyed by warehouse name) from the app;rosterentries shareagent_id; locally they also carrymessagesandlast_seen, while the app adds its registry card — display name, seat, leases, current task — which a SQLite file has no way to know.
Confirming what agents propose
Agents propose. You confirm. The confirmation lives in a terminal, in a command you have to type — deliberately not a tool an agent can call.
apiary-memory-cli list # what is waiting
apiary-memory-cli show <id> # read one in full
apiary-memory-cli approve <id> # confirm it, or --all
apiary-memory-cli reject <id> # drop it for good
apiary-memory-cli search "deploy key" # search confirmed memory
apiary-memory-cli forget <id> # soft delete, reversible
apiary-memory-cli restore <id> # undo forget
apiary-memory-cli stats # counts and the database path
apiary-memory-cli export --out dump.json
apiary-memory-cli path--db <path> on any command points at a different database. HIVE_DB does the same from the
environment.
Where your memory lives
~/.memory-hive/hive.db, unless HIVE_DB says otherwise. One SQLite file; copy it to back it
up, delete it to start over.
The board keeps its messages in the same file, so there is only ever one thing to back up. Cards
expire: 24 hours unless ttl says otherwise, clamped to between 60 seconds and 30 days, which
is what the app does too — a board that grows forever stops being a board.
How search works, and what it does not do
Chinese text is indexed as single characters plus overlapping character bigrams; Latin text as words. A query is scored by how much of it the entry covers, then nudged by recency — a 10% multiplier, enough to break ties and not enough to overturn relevance.
This is a ranker, not an understander.
Scores are relative.
0.8means "closer than0.4for this query", not "80% confident". They are not comparable across queries.No semantic recall. Ask about "money" and an entry that only says "invoice" will not be found. Related-word coverage needs an embedder; this package has no dependencies and does not pretend otherwise.
The ranking is the one the description states.
tools/listsays "words and character bigrams ... no embeddings" here, and that sentence is true of this engine. It is narrowed per engine like the embedding inputs are, because the app's answer to the same question differs.A miss is reported as a miss. When nothing matches,
recallsays so and mentions how many entries are awaiting confirmation, rather than returning a plausible neighbour.
Configuration
Variable | Default | Purpose |
|
|
|
|
| Where the local database lives |
|
| The app's endpoint |
| — | Agent id from the app; only for calls the app serves |
| — | Access token from the app; only for calls the app serves |
HIVE_AGENT_ID and HIVE_AGENT_TOKEN are not required to use the local store. They are
read straight from the environment and never written to disk by this package.
Honest limits
Written down because a memory tool that oversells itself is worse than one that does less.
The local store is not encrypted. Plain SQLite. Anyone who can read your home directory can read it. The app's vaults are the encrypted option, and
statsreports"encrypted": falseinstead of leaving you to find out.No semantic search, as above.
One writer at a time. WAL mode lets the CLI confirm while a server is connected, but this is a personal memory file, not a multi-host service. Do not point two machines at one database over a network share.
The board is coordination, not memory. Messages are for hand-offs between agents; they are not searchable with
recall.The app is macOS only. The local store is not — it is pure Python.
Troubleshooting
"no confirmed memory matched this query" with entries pending. Correct behaviour. Confirm
them: apiary-memory-cli list, then approve.
A call fails with a message about HIVE_AGENT_ID. The app answered and refused the
credential. The call did not fall back to the local store, on purpose. Register an agent in
the app and set both variables, or set HIVE_MODE=local if you meant to use the local file.
"Hive app not reachable ... and HIVE_MODE=remote forbids the local fallback". You asked for
the app only and it is not running. Start it, or drop HIVE_MODE=remote.
Where did my memory go? apiary-memory-cli stats prints the database path. If HIVE_MODE
is auto and the app is running, the app has been answering — the local file is untouched by
design.
Development
PYTHONPATH=src python -m unittest discover -s tests -vThe suite needs no running app and no network: it stands up its own fake backend where a real
response is required, and points HIVE_DB at a temporary file so a test never touches a real
memory database.
Layout:
src/hive_mcp/store.py the memory engine (SQLite, stdlib only)
src/hive_mcp/stdio.py the MCP server: routing, envelopes, the app bridge
src/hive_mcp/cli.py the human's half: review and confirm
src/hive_mcp/tools.json the tool surface snapshot for the offline pathLicense
MIT. Your memory file is yours; nothing here phones home.
Available Tools
6 toolsboardRead the shared boardARead-onlyIdempotent
Read the shared board, optionally only what arrived since your last read. Use it to poll for messages or hand-offs addressed to you. To post, use say. Pass the previous cursor as since so a poll returns only new messages instead of the whole board. Annotations declare this read-only; note that messages expire, so an empty result can mean nothing was posted or that earlier messages have aged out.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of messages to return. Omit for the server default. | |
| since | No | Cursor from a previous call. Only messages newer than this cursor are returned; omit to read the current board. | |
| roster | No | Also return which agents are currently on duty. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent safety profile, and the description adds genuinely non-obvious behavior: message expiration and the resulting ambiguity of an empty result. That is exactly the kind of context structured fields cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Four short sentences, each carrying distinct information (purpose, polling use, sibling routing, cursor pattern, expiration caveat) with the core purpose front-loaded and no filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description could say slightly more about what a returned message looks like, and the 'roster' parameter is untouched. Otherwise it covers purpose, polling semantics, the mutation alternative, and the empty-result caveat adequately for a 3-parameter read tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds real meaning for 'since' by explaining the poll pattern (pass the previous cursor to get only new messages). It does not clarify 'limit' or 'roster' beyond the schema, so it stops short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Starts with a specific verb+resource ('Read the shared board') and immediately adds the scope qualifier ('optionally only what arrived since your last read'). It also names the write counterpart ('To post, use say'), so the agent can distinguish it from siblings like say without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly states the use case ('poll for messages or hand-offs addressed to you'), gives the alternative for the opposite intent ('To post, use say'), and instructs exactly when/how to use the cursor ('Pass the previous cursor as since so a poll returns only new messages'). Nothing is left to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_contextGet session contextARead-onlyIdempotent
Pull a short digest of recent memory from the human's active threads and open tasks, to seed a conversation before they ask anything. Call this once at session start. For answering a specific question, use recall instead, since that searches all confirmed memory rather than only what is recent. For entries still awaiting approval, use manage with action list_pending. Annotations already declare this read-only; what they cannot say is that the digest reflects the most recent activity, so two calls minutes apart may differ.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of context entries to return. Omit for the server default. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations cover read-only, non-destructive, closed-world, and idempotent behavior. The description adds valuable context not in annotations: the digest reflects recent activity, so two calls minutes apart may differ. This addresses data freshness, which annotations cannot convey. The only minor gap is that it doesn't detail return format or rate limits, but for a read-only tool this is largely sufficient.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is four sentences with zero waste, front-loading the core purpose and timing before alternatives and behavioral nuance. Every sentence contributes directly to correct selection and invocation.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a read-only tool with no output schema, the description is complete: it states the purpose, when to call it, alternatives, and a behavioral trait not captured by annotations. The parameter is schema-documented, and the annotations cover safety. Nothing essential for an agent to call it correctly is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% for the single 'limit' parameter, which is fully documented in the schema. The description does not add meaning beyond what the schema provides, so baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb ('Pull a short digest') and resource ('recent memory from the human's active threads and open tasks'), and explicitly distinguishes itself from siblings like recall and manage. An agent can immediately understand what this tool does and when it differs from alternatives.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It explicitly states when to call ('once at session start') and when not to ('For answering a specific question, use recall instead', 'For entries still awaiting approval, use manage with action list_pending'). The alternatives are named with the conditions that select them, leaving nothing to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
manageManage stored memoriesA
Inspect or change the lifecycle of a specific stored memory, addressed by id or by queue state. Use list_pending to review what is awaiting the human's approval, and get_by_id to read one entry in full. forget soft-deletes and is reversible with restore; discard_pending permanently drops an entry that was never confirmed. To search confirmed memory by topic instead of by address, use recall. Except for discard_pending, every action here is reversible, which is why this is not marked destructive.
| Name | Required | Description | Default |
|---|---|---|---|
| id | No | Target memory id. Required for forget, restore, get_by_id and discard_pending; ignored by list_pending. | |
| action | Yes | Which lifecycle operation to run. list_pending takes no id; the other four require one. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already establish non-read-only, non-destructive, closed-world behavior. The description adds important context beyond them: forget is a reversible soft-delete, discard_pending permanently drops an unconfirmed entry, and the reversibility exception is disclosed rather than hidden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded and most sentences earn their place by mapping actions and alternatives. The final sentence repeats the discard_pending exception already stated, though it usefully explains the annotation choice.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a five-action lifecycle tool with no output schema, the description covers every action, the id requirement, reversibility, permanence, and the relevant sibling alternative. An agent has enough information to choose and invoke the correct action.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the id and action parameters are already fully documented. The description reinforces that entries are addressed by id or queue state, but it does not add syntax or format details beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: inspect or change the lifecycle of a stored memory, addressed by id or queue state. It also enumerates the concrete lifecycle actions and distinguishes the tool from the sibling recall tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives explicit routing guidance: list_pending for items awaiting approval, get_by_id for reading one entry, forget/restore for reversible soft-delete, discard_pending for permanent removal, and recall for topic-based search of confirmed memory. The alternatives and selection conditions are clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
proposePropose a memoryA
Submit a memory for the human to approve. It lands in a pending queue and changes no confirmed memory. Use it when the human says to remember something, or when a decision is reached that will still matter later. Do not use it as a scratchpad for transient reasoning or for data you merely fetched. This tool cannot confirm its own writes: the entry stays pending until the human accepts it inside their own Hive, so a success response means queued, not stored. Supply client_id to make retries idempotent.
| Name | Required | Description | Default |
|---|---|---|---|
| tags | No | Free-form tags for later filtering. | |
| title | No | Short label shown in the human's pending queue. Helps them decide quickly. | |
| vault | No | Target vault name. Private vaults are rejected for cloud agents; local agents may target them. | |
| content | Yes | The memory to store, written as a standalone fact that still makes sense without this conversation - include the who and the when. | |
| client_id | No | Idempotency key. Submitting twice with the same key does not create a duplicate - use this when retrying after a timeout. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations only say non-read-only, non-destructive, closed-world; the description goes much further by explaining the queue semantics, that nothing confirmed is changed, that the write cannot be self-confirmed, and that a success response means 'queued, not stored'. It also discloses the idempotency mechanism for retries — genuinely useful context an agent could otherwise get wrong.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the action and the pending-queue consequence, then usage, then failure-mode caveat, then the parameter note. Every sentence carries distinct information, though the closing client_id sentence duplicates the schema description and is the one small piece of redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of explaining what a successful call means and does so explicitly ('success response means queued, not stored'). Combined with triggers, exclusions, and retry semantics, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so all five parameters (including content authorship guidance, vault restrictions, and client_id idempotency) are already documented in the schema. The description's only parameter reference — 'Supply client_id to make retries idempotent' — restates the schema rather than adding to it, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Submit a memory for the human to approve') plus the crucial qualifier that it lands in a pending queue rather than confirmed memory. That distinguishes it cleanly from siblings like recall (read), say (immediate output), and manage (administration).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives explicit positive triggers ('when the human says to remember something, or when a decision is reached that will still matter later') and explicit exclusions ('Do not use it as a scratchpad for transient reasoning or for data you merely fetched'). The when/when-not pair leaves little to inference.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallRecall memoryARead-onlyIdempotent
Search the human's confirmed memory by natural-language query and return the closest stored entries. Use this to find what was previously decided, recorded, or agreed. Do not use it at session start when you have no query yet - use get_context instead. Do not use it to review entries still awaiting approval - use manage with action list_pending. Annotations already declare this read-only, so this text covers what they cannot: results come from the confirmed store only, private vaults are omitted for agents not permitted to read them, and an empty list means no match rather than no memory.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum number of memories to return. Omit for the server default. | |
| query | Yes | Natural-language search text, e.g. 'what did we decide about the pricing page'. Ranked by how much of it the entry's words and character bigrams cover, plus a small recency nudge and a bonus when the whole query appears verbatim. This engine has no embeddings, so an entry that shares no wording with the query will not be found - add plain keywords alongside the sentence. | |
| vaults | No | Narrow the search to these vault names. Omit to search every vault this agent may read. Naming a vault the agent may not read is not an error - it returns nothing from that vault. | |
| compact | No | Return trimmed records (id, title, snippet) instead of full bodies. Saves tokens when you only need to know whether something exists. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Rather than restating readOnlyHint, it deliberately adds what annotations cannot: results come only from the confirmed store, unreadable private vaults are silently omitted, and an empty list means no match rather than no memory. The empty-result-vs-empty-store distinction is exactly the kind of behavioral fact that prevents misdiagnosis.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Sentences are front-loaded: purpose first, then the two exclusions, then behavioral caveats. The self-referential clause about what the annotations already declare is slightly meta but functions as a signpost for why the following sentences exist.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing results, and it does so at a high level (closest entries, confirmed store only, empty list semantics), while compact-vs-full shape is in the schema. Minor gap: how ties or scores are surfaced to the caller is left implicit.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so query, limit, vaults and compact are already fully documented, including the keyword/bigram ranking behavior. The description adds only an indirect hint about vault permission behavior, which the schema itself already states, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The definition pairs a specific verb (search) with a specific resource (the human's confirmed memory) and states what it returns (the closest stored entries). It explicitly distinguishes itself from siblings get_context and manage, so an agent can route without opening a schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It names two concrete exclusions with the alternative to use instead: at session start with no query, use get_context; to review pending entries, use manage with action list_pending. Both when-to-use and when-not-to-use are covered explicitly.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
sayPost to the shared boardA
Post a message to the shared board so the human and other agents see what was done or what is being handed over. Use it when finishing a unit of work, or to hand work to another agent. Do not use it to report routine steps the human did not ask about - the human reads this board. To read what others have posted, use board. Identity comes from your credential, so a caller cannot post as another agent.
| Name | Required | Description | Default |
|---|---|---|---|
| to | No | Who should see it: 'master' for the human (default), or another agent's id. | |
| ttl | No | Seconds after which the message stops being returned by board. Defaults to 24 hours, and is clamped to between 60 seconds and 30 days so no card is immortal. | |
| kind | No | Card type. May be omitted when stage is given, in which case the kind is derived from the stage. | |
| refs | No | References the reader may want: file paths, commit shas, or memory ids. | |
| stage | No | Work event: starting, handing off, finished, or blocked. Prefixes the body so the board can be filtered and de-duplicated. | |
| summary | Yes | What happened, in one or two sentences. Write the outcome, not a log of steps. | |
| task_id | No | Link this message to an existing task; the hand-off graph aggregates by it. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly=false and idempotent=false, so the write semantics are covered. The description adds non-structured context: the board is human-readable so posting noise has real cost, and identity comes from the credential so impersonation is impossible. It doesn't note that repeated calls create duplicate cards, which is notable given idempotentHint=false.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose is front-loaded in the first sentence, then usage triggers, the exclusion, the sibling alternative, and the identity constraint in that order. Four sentences, none redundant; each carries a distinct decision-relevant fact.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 7-parameter mutation tool with full annotations and full schema coverage, the description covers selection, audience, and the main misuse risk (over-posting to a human-visible board). The one gap is that with no output schema, it never says what the call returns (e.g., a card id usable with `refs` or `task_id`).
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so `to`, `ttl`, `kind`, `stage`, `refs`, and `task_id` are already fully documented with enums and defaults. The description only implicitly touches `summary` ('what was done') and `to` ('hand work to another agent'), adding little beyond the schema. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (post a message) and resource (shared board), plus the audience ('the human and other agents'). It explicitly routes readers to the sibling tool `board` for the opposite operation, so an agent can distinguish write from read without inspecting schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives concrete triggers ('when finishing a unit of work', 'to hand work to another agent'), an explicit exclusion ('do not use it to report routine steps the human did not ask about'), and names the alternative for the inverse operation ('use board'). This is the full when/when-not/alternative triad.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
3 tool updates
v0.2.0- Changed
propose1 field changed- removed
Input schema / properties / vectorRemoved value: -{ - "description": "Optional precomputed embedding stored alongside the memory, so later recalls are faster and more precise.", - "items": { - "type": "number" - }, - "type": "array" -}
- Changed
recall2 fields changed- changed
Input schema / properties / query / descriptionPrevious value: -"Natural-language search text, e.g. 'what did we decide about the pricing page'. Matched semantically, not by substring."New value: +"Natural-language search text, e.g. 'what did we decide about the pricing page'. Ranked by how much of it the entry's words and character bigrams cover, plus a small recency nudge and a bonus when the whole query appears verbatim. This engine has no embeddings, so an entry that shares no wording with the query will not be found - add plain keywords alongside the sentence." - removed
Input schema / properties / query_vectorRemoved value: -{ - "description": "Precomputed embedding. When supplied, recall ranks by vector similarity and ignores 'query' text matching.", - "items": { - "type": "number" - }, - "type": "array" -}
- Changed
say1 field changed- changed
Input schema / properties / ttl / descriptionPrevious value: -"Seconds after which the message stops being returned by board. Defaults to 24 hours."New value: +"Seconds after which the message stops being returned by board. Defaults to 24 hours, and is clamped to between 60 seconds and 30 days so no card is immortal."
6 tool updates
v0.1.7- First observed
board - First observed
get_context - First observed
manage - First observed
propose - First observed
recall - First observed
say
TDQS
Scored across 6 tools
Each tool targets a distinct resource and action: recall searches confirmed memory, get_context seeds a session, propose queues new memory, manage handles lifecycle by id/queue state, and say/board write and read the shared board. Descriptions explicitly cross-reference each other to resolve the few tempting confusions (recall vs get_context vs manage list_pending), so an agent can select reliably.
Names mix bare verbs (recall, propose, say, manage), a bare noun (board), and a verb_noun form (get_context), so there is no single predictable pattern. Every name is still readable and memorable, so the inconsistency is stylistic rather than harmful.
Six tools is well matched to a memory server with a shared board: one each for search, session seeding, proposal, lifecycle management, board write, and board read. No tool looks redundant and none of the needed operations are crammed together beyond manage's clearly enumerated actions.
The memory lifecycle is well covered end to end: propose, discover via recall/get_context, review pending, read by id, soft-delete with restore, and discard. The main gaps are the absence of any way to edit a pending or confirmed entry's content and no richer board operations (e.g., replying to or addressing a specific message), which agents can mostly work around.
Maintenance
Related MCP Connectors
Governed personal world model and memory for your AI agent. Pair once, connect over MCP.
One memory, every AI. A shared, user-owned markdown memory your AI clients read and write over MCP.
- LogRackOAuthai.lograck
Shared memory for your AI tools: tasks, notes and context every tool can read and write over MCP.
Persistent memory, knowledge graph, task management and more for AI agents via MCP.
Related MCP Servers
- AlicenseCqualityAmaintenanceProvides AI agents with a human-inspired memory layer via MCP, enabling episodic and semantic memory recall, forgetting curves, consolidation, and contradiction detection. It integrates with MCP clients to offer local-first, dependency-free memory management.981MIT
- AlicenseNot gradedqualityBmaintenanceEnables AI agents to store, search, assemble, and manage local-first memories through seven MCP tools, including conversation turns, feedback, status, and dashboard access without cloud dependencies.AGPL 3.0
- FlicenseAqualityBmaintenanceShared fleet memory for AI agents — what one agent learns, the whole fleet knows. Nightly self-correction: stale facts rewritten in place, duplicates merged. Recall pushed into every prompt in supported coding agents. Self-hosted.113-
- AlicenseNot gradedqualityAmaintenanceProvides persistent memory for AI agents via MCP, enabling agents to store and access notes, files, and session context across sessions and clients while under user control.4MIT