Skip to main content
Glama

Apiary Memory MCP

Also known as: Apiary Memory · 记忆蜂巢 · Memory Hive · 蜂巢 · apiary-memory on PyPI and io.github.330899935/apiary-memory on the MCP Registry (from v0.2.0) · old names memory-hive-mcp / hive-memory (v0.1.9 and earlier) still install and still work. Not affiliated with hive.com (team collaboration) or the hive-mcp Claude 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-memory

Desktop 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

initialize

answered locally, protocol 2024-11-05

tools/list

answered locally, six tools

propose

writes to a real database on your disk

recall

searches that database and returns ranked entries

get_context

a digest of what you confirmed most recently

manage

read one entry, list what is pending, forget, restore

say / board

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:

HIVE_MODE

Behaviour

auto (default)

Ask the app. Use the local store only if the app is unreachable.

local

Never touch the network. Always use the local store.

remote

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.stdio

Connect 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

recall

read

Search confirmed memory by topic. {"query": "..."} plus optional limit, vaults, compact.

propose

write

Submit a memory for the human to approve. Lands in a queue; changes no confirmed memory.

manage

read/write

Address one entry: list_pending, get_by_id, forget, restore, discard_pending.

get_context

read

A short digest of recent confirmed memory, to seed a conversation.

say

write

Post to the shared board so other agents see what was done or handed over.

board

read

Read the board, optionally only what arrived since your last cursor.

Two properties are worth stating plainly, because they are the product:

  • propose succeeding means "queued", not "stored". recall will not return it until a human confirms it.

  • manage has no approve action. 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 recall entry names its vault vault from the local store and wh from the app;

  • get_context returns one flat digest locally and one bucket per warehouse (context, keyed by warehouse name) from the app;

  • roster entries share agent_id; locally they also carry messages and last_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.8 means "closer than 0.4 for 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/list says "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, recall says so and mentions how many entries are awaiting confirmation, rather than returning a plausible neighbour.

Configuration

Variable

Default

Purpose

HIVE_MODE

auto

auto, local, or remote — see the table above

HIVE_DB

~/.memory-hive/hive.db

Where the local database lives

HIVE_MCP_URL

http://127.0.0.1:8768/mcp

The app's endpoint

HIVE_AGENT_ID

—

Agent id from the app; only for calls the app serves

HIVE_AGENT_TOKEN

—

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.

  1. 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 stats reports "encrypted": false instead of leaving you to find out.

  2. No semantic search, as above.

  3. 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.

  4. The board is coordination, not memory. Messages are for hand-offs between agents; they are not searchable with recall.

  5. 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 -v

The 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 path

License

MIT. Your memory file is yours; nothing here phones home.

Available Tools

6 tools
boardRead the shared boardA
Read-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.

NameRequiredDescriptionDefault
limitNoMaximum number of messages to return. Omit for the server default.
sinceNoCursor from a previous call. Only messages newer than this cursor are returned; omit to read the current board.
rosterNoAlso return which agents are currently on duty.

TDQS

A4.8/5.0
Behavior5/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters4/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 contextA
Read-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.

NameRequiredDescriptionDefault
limitNoMaximum number of context entries to return. Omit for the server default.

TDQS

A4.5/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

NameRequiredDescriptionDefault
idNoTarget memory id. Required for forget, restore, get_by_id and discard_pending; ignored by list_pending.
actionYesWhich lifecycle operation to run. list_pending takes no id; the other four require one.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

NameRequiredDescriptionDefault
tagsNoFree-form tags for later filtering.
titleNoShort label shown in the human's pending queue. Helps them decide quickly.
vaultNoTarget vault name. Private vaults are rejected for cloud agents; local agents may target them.
contentYesThe memory to store, written as a standalone fact that still makes sense without this conversation - include the who and the when.
client_idNoIdempotency key. Submitting twice with the same key does not create a duplicate - use this when retrying after a timeout.

TDQS

A4.6/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness5/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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 memoryA
Read-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.

NameRequiredDescriptionDefault
limitNoMaximum number of memories to return. Omit for the server default.
queryYesNatural-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.
vaultsNoNarrow 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.
compactNoReturn trimmed records (id, title, snippet) instead of full bodies. Saves tokens when you only need to know whether something exists.

TDQS

A4.5/5.0
Behavior5/5

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.

Conciseness4/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

NameRequiredDescriptionDefault
toNoWho should see it: 'master' for the human (default), or another agent's id.
ttlNoSeconds 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.
kindNoCard type. May be omitted when stage is given, in which case the kind is derived from the stage.
refsNoReferences the reader may want: file paths, commit shas, or memory ids.
stageNoWork event: starting, handing off, finished, or blocked. Prefixes the body so the board can be filtered and de-duplicated.
summaryYesWhat happened, in one or two sentences. Write the outcome, not a log of steps.
task_idNoLink this message to an existing task; the hand-off graph aggregates by it.

TDQS

A4.4/5.0
Behavior4/5

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.

Conciseness5/5

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.

Completeness4/5

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.

Parameters3/5

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.

Purpose5/5

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.

Usage Guidelines5/5

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.

  1. 3 tool updatesv0.2.0
    • Changedpropose1 field changed
      • removedInput schema / properties / vector
        Removed value: -{
        -  "description": "Optional precomputed embedding stored alongside the memory, so later recalls are faster and more precise.",
        -  "items": {
        -    "type": "number"
        -  },
        -  "type": "array"
        -}
    • Changedrecall2 fields changed
      • changedInput schema / properties / query / description
        Previous 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."
      • removedInput schema / properties / query_vector
        Removed value: -{
        -  "description": "Precomputed embedding. When supplied, recall ranks by vector similarity and ignores 'query' text matching.",
        -  "items": {
        -    "type": "number"
        -  },
        -  "type": "array"
        -}
    • Changedsay1 field changed
      • changedInput schema / properties / ttl / description
        Previous 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."
  2. 6 tool updatesv0.1.7
    • First observedboard
    • First observedget_context
    • First observedmanage
    • First observedpropose
    • First observedrecall
    • First observedsay

TDQS

A4.4/5.0

Scored across 6 tools

Disambiguation5/5

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.

Naming Consistency3/5

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.

Tool Count5/5

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.

Completeness4/5

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

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    A
    maintenance
    Provides 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.
    98
    1
    MIT
  • A
    license
    Not graded
    quality
    B
    maintenance
    Enables 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
  • F
    license
    A
    quality
    B
    maintenance
    Shared 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.
    11
    3
    -
  • A
    license
    Not graded
    quality
    A
    maintenance
    Provides 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.
    4
    MIT