Server data from the Official MCP Registry
0.3.2. Free MIT; no account, key, or payment. Verifies record, not computation. Stable error codes.
About
0.3.2. Free MIT; no account, key, or payment. Verifies record, not computation. Stable error codes.
Security Report
Valid MCP server (2 strong, 4 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry.
4 files analyzed · 1 issue found
Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.
Permissions Required
This plugin requests these system permissions. Most are normal for its category.
What You'll Need
Set these up before or after installing:
Environment variable: MONGODB_URI
How to Install
Add this to your MCP configuration file:
{
"mcpServers": {
"io-github-dreamforgestudiollc-emet": {
"env": {
"MONGODB_URI": "your-mongodb-uri-here"
},
"args": [
"-y",
"@dreamforgestudiollc/emet"
],
"command": "npx"
}
}
}Documentation
View on GitHubFrom the project's GitHub README.
EMET
EMET is an MCP (Model Context Protocol) memory server, persistent shared memory for AI agents, bot teams and chats.
אמת — Hebrew for truth. Also Enduring Memory & Epistemic Tiers.
Website: https://dreamforgestudiollc.github.io/EMET/
See also: CHANGELOG · CONTRIBUTING · SECURITY · Charter · Feature map · Development practices
What it does
- Layered memory. Six layers — identity, semantic, episodic, procedural, meta, and working — hold curated claims, split by what kind of thing an entry is.
- Verified writes. Every write is read back and compared before it is reported as saved.
- Word-for-word transcript tier. A separate tier stores the conversation as it was written, so a summary cannot overwrite the record it came from.
- stdio and remote HTTP with OAuth. The same server runs locally over stdio, and remotely over HTTP with OAuth. The transport changes. The store does not.
- MongoDB. Atlas, or MongoDB you run yourself. A one-machine trial can use MongoDB 6 or newer. Only
semantic_recallneeds Atlas. - Golem Expertise Module (GEM) socket. Add-on behavior ships as GEMs, seated at startup and checked by
gem-checkagainst the GEM standard ingem-library/. A GEM ranks below the core floor and below the user's current word, and cannot remove a protected floor line. Two work-in-progress examples ship bundled and stay off unless you ask: Neurendipity (neurodivergent engagement and autistic burnout support; support only, not counseling or treatment;EMET_ACTIVE_GEMS=neurendipity) and Lean Six Sigma (DMAIC and DMADV guidance, templates, and client-side calculators;EMET_ACTIVE_GEMS=lean-six-sigma). Fieldnote stays in the tree as a developer case-study of a runed GEM. It is not a user-facing third GEM, and it is off by default. - Bot-team backup (optional). Off unless the first-run interview records yes. Yes is the recommended choice. The recipe and the recovery template ship as the bundled bot-team-backup GEM. EMET does not copy prompts or settings itself, and secret values are never stored.
- Client-side GEM execution. A GEM may declare a tool. EMET does not run that computation. EMET verifies the record, not the computation. The client runs the tool, and what is written back is checked the same way as any other write.
- Released flag. A GEM is seated only when its released flag is the boolean true. Any other value is refused. A missing flag is refused except for a legacy manifest pinned by id, version, and file digests.
- Per-client attribution and approvals. Every write is attributed to the client that made it. A new client is read-limited until it is approved. The approval is recorded.
- Error codes and problem reports. Every error carries a stable
EMET-<AREA>-<NNN>code. An operational error log keeps 10,000 entries or 90 days, plus daily summaries. The owner-onlyemet_error_reportreturns the report and an email draft that you send yourself. See Reporting a problem. - verify-emet and the feature map.
npm run verifyrunsscripts/verify-emet.mjsfrom a checkout. It starts EMET in a temporary directory on the in-memory test database, with no.env, and drives every registered tool. A tool that needs a service a plain install does not have is reported as a gap. A run whose only problems are gaps exits 3. A failed tool exits 1. The map is docs/features/README.md. - MIT. Version 0.3.2. EMET is still 0.x: stored document shapes may change before 1.0. Pin a version if you depend on them.
The store has one owner, and other people can join only through the optional Guest (read-only) and Member (read and write) access, both off by default.
Document control (ISO 9001 7.5.3 / ISO 13485 4.2.5)
EMET is built for document control in environments that work under ISO 9001 and ISO 13485. It supports that work; it holds no certification and claims no conformity. An organization that uses it stays responsible for its own quality system, including validating EMET for its intended use.
- No delete, on any store, by design. No tool removes a memory entry, a document or a transcript. The database role EMET runs under is not granted remove on the record either.
- Corrections are made by adding. A memory entry is superseded by a revision that stands alone. A document is revised or retired. A transcript part is revised. Events are never rewritten.
- Retired means obsolete, not gone.
retire_docmarks a document obsolete and keeps its id, content, version and digest.read_docstill returns it, flagged retired, with the reason. - Prior versions are retained. Every document write archives the copy it replaces, and
read_doc_historyreads any retained revision back, checked against its stored digest. - Records are superseded whole, never patched. The handoff and any other record document cannot be patched. A new revision is written in full and names the version it supersedes.
- Templates are controlled documents. Base templates ship with the release, and the shipped copy governs. Every templated write is checked against its template, and a write that fails is kept and marked for review, never silently accepted or discarded.
- A test holds the line.
write-path.test.jsfails if anything insrc/removes from a layer, document or transcript collection, andatlas-role.test.jsfails if the database role grants remove.
30-second start
- Guided setup: docs/GUIDED-SETUP.md — never deployed anything. Your assistant installs, configures, deploys, and verifies. You sign in when asked and paste the connector URL.
- Setup: docs/SETUP.md — the manual walkthrough: MongoDB, both transports, and the first-run interview.
- Deploy: docs/DEPLOY.md — remote HTTP with OAuth, so a phone, a browser, or another vendor's agent reaches the same store.
npm lags the repo.
npx -y @dreamforgestudiollc/emetinstalls 0.3.1 until 0.3.2 is published. For 0.3.2, clone this repo and runnpm ci && npm start, or deploy the repository itself.
Status: 0.x. The stored document shapes are not frozen yet. Breaking changes to the schema may land before 1.0. Pin a version if you depend on it.
Set
EMET_SOURCE_TAGSbefore you let more than one host or bot write. The source-tag guards (unregistered tags refused on the main records, and on another bot'sbots/folder) are off unlessEMET_SOURCE_TAGSis set. With it unset, any caller can write under any tag. See.env.exampleand docs/DEPLOY.md.
Install as a Cursor / Grok Bot plugin
EMET ships a plugin for Cursor and Grok Bot (this repo's .cursor-plugin/plugin.json and
mcp.json). The Cursor Marketplace listing is submitted and pending review. The plugin does not host memory for you: it connects to your own EMET
server, so your records stay in your MongoDB.
- Deploy EMET remotely: docs/DEPLOY.md. Set
PUBLIC_URLand a strongEMET_OAUTH_PASSPHRASE. Checkhttps://<your-host>/healthreturns{"ok":true,...}. - Install the EMET plugin and set the variable
EMET_URLtohttps://<host>/mcp. - Connect. The OAuth sign-in opens EMET's passphrase page; enter your passphrase once per device.
- Verify: call
emet_statuswith{"probe": true}(it writes, reads back and removes a row from_emet_verifyonly), then save withsave_to_layerandrecallit from another client.
The plugin also ships an emet-memory skill that tells the agent when to recall, save and close
a session.
Shared memory across hosts
EMET stores agent memory in MongoDB (Atlas or self-hosted) across six layers, keeps a separate word-for-word
transcript tier, and verifies every write by reading it back. It runs as a local stdio server
and as a remote HTTP server from the same source, so it works as a bridge: AI models on several
hosts — desktop, CLI, browser, phone, another vendor's agent — read and write one shared
memory, and the work, checks, and decisions one leaves behind are there for the next. That
includes Grok Bot teams and single-session Grok chats connected to the same server: what the
bots save is there for a fresh Grok chat to find once it initializes, and the reverse. To
connect a single-session chat (a Grok project, or any chat host that takes a remote MCP
connector and supports its OAuth sign-in), add your deployed server's URL,
https://<your-host>/mcp, as a remote MCP connector there and complete the sign-in with the
passphrase you set (EMET_OAUTH_PASSPHRASE; see
Connecting clients). A connector that only takes a fixed
header or key will not work. Then put the instruction block from
docs/BOOTSTRAP.md in the project instructions: the chat reaches for that
memory most reliably, unprompted from the first turn, with the block there, or, as a fallback
where there is no such field, with it pasted as the first message. The store has one
owner, and other people can join only through the optional Guest (read-only) and
Member (read and write) access, both off by default.
Two ways in
A session that has not initialized can read everything and can write only a new drop (drops/<date>-<slug>.md): its items, wrap-up and handoff. A session with a registered source and the full startup has full access. Every initialized session sees unhandled drops first. A board edit is refused only for a drop that was listed at that session's boot. New drops are capped at 20 per New York day, in one bucket: the whole local process on stdio, one shared visitor bucket for HTTP with no signed-in client, the source tag bound at approval when there is one, or that OAuth client otherwise. A source the caller types does not move the bucket. Drops are never deleted.
Editing working state
The server provisions a blank board at setup. No session can write the board. It is edited with patch_doc and a reason; an added row names its origin. Once any working document exists, it is edited, not rewritten. A change that leaves a document under half the size it had when this session first touched it, or under half of its largest size in the last 24 hours, is refused. retire_doc refuses a working document. rename_doc issues a new id and marks the old id retired; the text stays readable and stays in the list. restore_doc is the one whole-document recovery, for an owner-listed tag, and only a stored conforming revision whose digest matches.
The name
EMET is אמת — Hebrew for truth. It is also an acronym for what the server does: Enduring Memory & Epistemic Tiers.
The choice is not decoration. In the golem legend the word emet is inscribed to animate the body, and erasing its first letter leaves מת — met, dead. One character is the whole difference.
That is why the verification layer is called aleph. Every write in EMET is read back and
compared before it is reported as saved. That read-back is the aleph: a memory system without
it still returns answers, still looks healthy, and is quietly a corpse — confidently serving
things it never actually stored. Aleph is also the first letter, which matches the order the
protocol insists on: verify before retrying, verify the premise before applying the remedy,
read back before trusting.
The same image explains what setup is for. A golem is inert until the word is written on it;
a fresh model instance is unformed until the record is written into it. emet_initialize is
that inscription — it hands the model an identity, the person it serves, where things stood,
and the disciplines it is bound by. Nothing mystical is claimed here. It is a literal
description of what the first tool call does.
Both halves of the acronym are load-bearing.
Enduring is not a modest claim, and it is not a feature competing with other memory products. It is measured against what a language model is by default: an etch-a-sketch. Every session starts from nothing, and ends by forgetting everything. You explain yourself again, re-establish what you are working on again, re-derive decisions you already made. Enduring names the difference between an assistant that knows you and one meeting you for the first time, again. That is the character of the thing, not a marketing adjective attached to it.
Epistemic Tiers is how that endurance stays trustworthy. Tier 1 holds curated claims; tier 2 holds the verbatim record that justifies them — justified belief and its evidence, kept structurally separate so neither can quietly overwrite the other. Memory that persists but cannot be checked is just confident noise that survives longer.
One memory, every device
This is the part worth understanding before anything else.
Most MCP memory servers run as a local process: your desktop launches it over stdio, and the memory lives wherever that process can reach. That works until you pick up your phone.
EMET ships two entry points over one source tree:
src/index.js | stdio | desktop and CLI, launched by the client |
src/http-remote.js | streamable HTTP + OAuth | phone, tablet, browser, another vendor's agent |
They are not two projects. Both call the same dispatchTool in dispatch.js, which calls
tools.js and database.js. src/index.js also imports validation.js. src/http-remote.js
does not import validation.js or content_analyzer.js; tools.js imports the analyser. The
transport is the only thing that differs. There is no fork to keep in sync, no second copy
drifting out of date, no "mobile version" lagging the real one. A fix lands once and both
transports have it.
Deploy the HTTP entry point to any host that can run a container — the Dockerfile is
included, and docs/DEPLOY.md walks through Railway and Fly — and every device
you own reaches the same store. Write a decision from your laptop, ask about it from your
phone an hour later, and it is simply there. Add a third host and it joins the same memory
rather than starting its own.
The remote endpoint is OAuth-protected: a device is authorized once with a passphrase you set,
and the token persists across restarts and redeploys. Leave EMET_SOURCE_TAG unset on a
server several hosts share. Over HTTP, document, transcript, and memory writes use the source
tag bound at approval. A local stdio host still passes an exact tag from EMET_SOURCE_TAGS
as source on its writes (see .env.example). Every entry records which machine produced
it — with several hosts writing to one store, provenance stops being optional bookkeeping and becomes the thing that lets you trust
what you read.
Running cost for a single user is a small MongoDB cluster plus a hobby-tier container host. Both have free tiers adequate to start.
Best practices
Split the work by what each host does best. A single-session chat (for example, a Grok project chat, connected as described at the top) only works when you send it a message. It can't watch EMET, and bots can't message it. So when a bot team needs the chat's help:
- The bots leave a task in EMET with everything needed to do it, in a document whose id they give you.
- You send the chat one line that names that document, for example: "Initialize EMET, read threads/open-tasks.md, do the task, and save the result to EMET."
- The chat saves its draft to EMET.
- The bots check it.
Good fits for the chat: long drafting and review done in one sitting. Good fits for the bots: work in the repository, on the server, on a schedule, or in accounts. If the chat runs on a separate plan, its work draws on that plan's allowance, not the bots'.
Fetch every startup page, then open the session with that startup's load_id. Call
emet_initialize {} first and fetch every page it names; ask for {"page": "all"} only on a
host known to read long results whole. Pass the load_id from those pages to
emet_session_open. An open with no load_id, with a page missing, or with a load_id the
server has no record of (one from before a restart, or 60 minutes past its last page) is
refused, and the reply says what to call. The page check runs on your own startup, and a
skipped page is refused before anything is written. See docs/BOOTSTRAP.md
and docs/BOTS.md.
Set the source-tag list before more than one host or bot writes. The guards that refuse
an unregistered tag are off unless EMET_SOURCE_TAGS is set; with it unset, a stdio caller can
write under any tag. Over HTTP the tag is the one bound when that host was approved. Add each
host's tag to the list before that host's setup interview. With several hosts writing one store,
the tag is what lets you trust who wrote what. See docs/SETUP.md.
Put the instruction block in the project's instructions. Connecting the server gives the assistant the ability to remember; it does not make it use that ability. A host with an instructions field is the strongest integration: paste the block from docs/BOOTSTRAP.md there. Where there is no such field, paste it as the first message of a session. With the block in place, the assistant reaches for memory most reliably from the first turn, instead of answering from what it can infer and saving nothing.
Approve reads standing, and keep an eye on the three writes that replace a document. Reads cost nothing and cannot be wrong destructively, so a reasonable default for most users is standing approval for reads. Additive writes are recoverable, because a correction supersedes what it corrects rather than overwriting it. The three replacing writes archive the prior version, but a wrong one is silently a different document rather than an error. Do not carry this posture to a filesystem or shell server. See docs/PERMISSIONS.md.
Reconnect each host after an upgrade that changes the tool list. Hosts cache the tool list: after a deploy that adds or renames tools, each host keeps offering the old set until you reconnect the connector there. New tools stay invisible until the host sees the new list, and the host may ask again for approvals you had already given. See docs/DEPLOY.md.
Register a bot before its first write, and set both lists in one change. One bot, one tag,
<prefix>-<bot> (for example bot-reviewer). When a bot joins the roster, append its tag to
the end of EMET_SOURCE_TAGS, keep every existing tag in order, and add
bots/<tag>/HANDOFF.md to EMET_RECORD_DOCS before its first write. Set both in one
deployment. Setting either variable redeploys the server; afterwards, check /health and
emet_status. A registered tag that is not listed as a bot can still write the main records.
The hub's tag is registered as a host and is never listed as a bot. That standing rule is
docs/BOTS.md §4.
Approve a writer yourself, and give a bot that shares your login its own key. The owner
decides a new writer on /owner/chooser. An AI does not grant a writer. When EMET_SUBKEYS=1,
each bot that can keep a key file holds its own emk_ key. The owner approves that key on the
same page. The bot presents the key once at emet_session_open. See
docs/SUBKEYS.md and docs/BOTS.md §4.
Pass session_handle on every write in a sub-key session. emet_session_open returns
session_handle once. Later writes in that session pass session_handle. A write that names
the session and omits the handle, or sends a different one, is refused, and nothing is written.
The handle is not a receipt and is not written into a document. With sub-keys off, the field is
absent. See docs/SUBKEYS.md and docs/PERMISSIONS.md.
Prove the write path before you trust a new deploy. Run emet_status with probe: true.
It writes a test document, reads the same value back and removes it; a read alone cannot show
a broken write path. A role missing a permission fails there, loudly, instead of in the middle
of a session. Then save something from one device and recall it from another. See
docs/SETUP.md.
Keep house style in the store, not pasted into every project. A document written with
write_doc is read by every host and changed in one place; text pasted into three projects is
three copies that will disagree. Delivery preferences belong in bootstrap/USER.md, not in one
vendor's own memory, which does not travel to the next host. See
docs/BOOTSTRAP.md.
Attribution
EMET is a derivative of CASCADE Enterprise RAM by Jason Glass / C.I.P.S. LLC, published
at github.com/For-Sunny/cascade-memory-enterprise, used and redistributed under the MIT
license the project adopted at commit acdb5c8c99cdfc29fb44db2cd828d7752be744db (v2.2.2,
2026-02-19). Both copyright lines are retained in LICENSE.
Link unavailable: as of 2026-10-03 that repository no longer resolves (GitHub answers 404), and no moved copy, public mirror or archive of it was found. The address and commit are kept here as the record of where this code came from.
How much is upstream, measured rather than estimated. Line-level comparison of this tree against upstream v2.2.2 at the commit named above.
Method, stated so it can be reproduced: exact, case-sensitive comparison of non-blank
lines; an upstream line counts as retained if the same line is present in this tree's file.
"How much of upstream survives here" and "how much of this file is upstream's" are different
questions with different answers, so both are given. scripts/measure-upstream.mjs
regenerates this table against a clone of the commit above (while the upstream repository is unavailable, that needs a copy kept from before) — run it after any change to
src/, because a figure nobody can cheaply re-derive is a figure that goes quietly stale.
| File | Lines here | Upstream lines retained | of upstream | of this file |
|---|---|---|---|---|
src/content_analyzer.js | 450 | not recomputed | — | — |
src/validation.js | 1163 | not recomputed | — | — |
src/index.js | 390 | not recomputed | — | — |
src/tools.js | 4273 | not recomputed | — | — |
src/database.js | 811 | not recomputed | — | — |
src/http-remote.js | 269 | — | — | no upstream counterpart |
src/oauth-provider.js | 702 | — | — | no upstream counterpart |
src/named-items.js | 206 | — | — | no upstream counterpart |
src/security-headers.js | 26 | — | — | no upstream counterpart |
src/layers.js, floor.js, aleph.js, session.js, setup.js, gaps.js, provenance.js, redact.js, annotations.js, request-log.js, disciplines.js, metadata.js, env.js | 4803 | — | — | no upstream counterpart |
Lines here were counted on 2026-10-07 (every line, including blanks, with one trailing empty line dropped). The retained percentages were not recomputed: the upstream repository no longer resolves, and no local copy of that upstream commit was available. The last measurement, against an earlier tree, was content analyser 361 of 394 (91.6% of upstream, 93.5% of that file), validation 765 of 798 (95.9%, 78.2%), index 541 of 631 (85.7%, 74.0%), tools 798 of 1007 (79.2%, 33.2%), and database 353 of 651 (54.2%, 40.2%). Other files under src/ also have no upstream counterpart and are not in this table.
Upstream's server/decay.js and server/healthcheck.js have no counterpart here and are not
carried at all. Of the five files that do have one, the content analyser and the validation
layer are substantially Jason's work, and most of his tools.js and index.js survives here
as well — the routing patterns, the validators, and the error classes are his. What changed is
described below; what did not change is his.
What diverged from upstream
- Storage: SQLite on a RAM disk → MongoDB. Upstream's
ram_disk_managerandserver/decay.jstemporal-decay engine are not carried forward, and the SQLite/RAM code paths have been removed rather than left dormant. - Transport: stdio only → stdio and streamable HTTP with OAuth, from one source tree.
- Tools: 7 → 29. Three are carried from upstream (
recall,query_layer,save_to_layer);remember,get_stats,get_echo_statsandget_statusare dropped as duplicates or folded intoemet_status. Twenty-six have no upstream equivalent — the document store (read_doc/read_doc_history/write_doc/list_docs/patch_doc/retire_doc/rename_doc/restore_doc/validate_doc/accept_nonconformance), the transcript tier (save_transcript/revise_transcript/query_transcripts— which also reads the pre-2026-07 exchange archive),semantic_recall,revise_memory,corpus_recall,emet_gaps,emet_floor, the setup and session family (emet_initialize,emet_status,emet_setup_complete,emet_session_open,emet_transcript_append,emet_session_close), and the two access doors (emet_invite_create,emet_member_access_create). - The write path: upstream validates and inserts. Here every layer write, transcript write and document write passes through one door that scrubs secrets, decides the source tag, fills missing accountability fields with visible markers, digests content and metadata into their own columns, reads the row back, and returns one receipt shape. A test fails the build on any second door. See The door below.
- Metadata vocabulary: upstream's whitelist relocated any field it did not know under
custom. EMET's own fields —supersedes,superseded_by,superseded_at,corrects,corrected_by,valid_until,valid_from,routing,assertion_origin, and the marker booleans — are first-class, and anything that is still relocated is named in the receipt. - Charter as data:
layers.jscarries, beside each layer's prose, its numeric importance band, whether it may be revised, whether provenance is required, its aliases and its expected share, and the write path reads those rather than hardcoding them.
No claim is made that layered memory, entry supersession, or a split curated/verbatim store originate here. Comparable ideas ship in other projects. EMET's aim is that the substrate is not something you have to think about.
Install
Never deployed anything? Let your AI do it: docs/GUIDED-SETUP.md. You sign in to two services when asked and paste one URL; the assistant installs, configures, deploys and verifies the rest. It needs a shell — Claude Code and Cowork have one; Claude Desktop gets one from an MCP server such as Desktop Commander (one command, in the guide).
Full walkthrough: docs/SETUP.md — Atlas, both transports, and the first-run interview. Deploying remotely: docs/DEPLOY.md. Making your assistant actually use it: docs/BOOTSTRAP.md. Running bots alongside your assistant — registering their tags, their own handoffs, the session loop: docs/BOTS.md. For designing a bot team, see docs/SUBKEYS.md.
Continuous chats. A bot in a long-running chat saves its transcripts to EMET
word for word at least nightly (a checkpoint), under the open session or a daily
YYYY-MM-DD_chat-daily session. Prefer event triggers over time-based polling.
When polling is unavoidable, use the longest interval the job allows. Never
reconstruct turns. Mark gaps as gaps. Session close cites those saved parts.
Context compression erases older turns, so a close days later cannot invent the
transcript.
Short version:
npm install
cp .env.example .env # fill in MONGODB_URI and MONGODB_DB
npm start
Requires Node 22+ and a MongoDB connection. .env is gitignored — never commit it.
Local (stdio) — as an MCP server entry:
{ "mcpServers": { "emet": { "command": "node", "args": ["/path/to/emet/src/index.js"] } } }
Remote (HTTP) — npm run start:http, or deploy the included Dockerfile to any container
host. Set PORT, PUBLIC_URL (the OAuth issuer — it must match the deployed URL exactly) and
EMET_OAUTH_PASSPHRASE. Then add https://<your-host>/mcp as a custom connector in each
client. See docs/DEPLOY.md.
Give every host its own source tag. Over HTTP, document, transcript, and memory writes use the
tag bound at approval; the caller does not pass source on those writes. A local stdio host
still passes an exact registered tag as source. EMET_SOURCE_TAGS registers the tags. Leave
EMET_SOURCE_TAG unset on a server several hosts share, since a default tag makes every
host look the same; set it only where one host uses the server (a local stdio entry, for
example). Every write records the host that produced it; a shared default tag is ambiguity
rather than attribution.
First run
Say "initialize". That is the whole interface.
emet_initialize is the front door and the only thing anyone needs to know about. On a new
store it returns a short interview — what the assistant should be called, how it should carry
itself, your name, what you are using this for, and whether more than one bot or AI will use
this memory — which your assistant runs conversationally,
then records with emet_setup_complete, which also creates the owner person. Whether more than one bot or AI will use this memory is optional; leaving it out leaves delegated client sub-keys off. A yes writes them only when this server reads .env, and they take effect on restart. A hosted server refuses and tells you the three variables to set, then redeploy. See docs/SUBKEYS.md. On an established store the same call returns the
assistant's identity, your profile, and where things were left, so the session opens already
knowing you. A read-scoped emet_initialize writes nothing; a write-scoped one may provision a missing board. First-time setup is the owner's:
emet_setup_complete is refused under a bot tag, and on a store that is already set up it is
refused unless reissue: true is passed on the owner's explicit word.
Requiring a setup command would have been backwards: the one time you need it is the first session, before you have read anything. So the branch happens inside the tool, and you never have to know which case you were in.
Connecting the server gives your assistant the ability to remember; it does not make it use that ability unprompted. docs/BOOTSTRAP.md has a short block to paste into your project instructions, and explains what still works on hosts that have no instructions field at all.
Two behaviours worth knowing. Setup refuses to finish on partial answers rather than inventing an identity for itself. And if the store cannot be reached, initialize says so plainly instead of proceeding as though memory were available — fabricated continuity is worse than an honest gap.
Every session after that: how to start, how to end
Memory is only as good as the two moments at the edges of a conversation. Nothing your assistant learned survives unless it was written to the store, and the moment to write it arrives without warning — a closed tab, a context limit, a phone call. So every session has one word at the start and one at the end.
Start: say "initialize". Your assistant calls emet_initialize, which returns who it is,
who you are, where things were left and the operating disciplines, and picks up from there.
Before it asks you anything, it names your items from the handoff and state documents: anything
left half-finished, what is dated in the next seven days, each open item you own with its next
action, and whatever was left undecided. An item not named at the start of a session is easy
to lose, so a count or a bare "where do you want to start?" is not treated as a startup.
Do this in every new conversation, on every device — the first message, before the question
you actually came to ask. A session that skips it is a session that answers from guesswork
and saves nothing.
End: say "wrap up" (or goodbye, or that you are opening a new session). Your assistant
then writes four things — the handoff, the state document, an episodic entry for the session,
and the verbatim transcript — and calls emet_session_close, which checks that each one
actually landed and returns state: "complete". Wait for that word before you close the
window. If it comes back anything else, something did not save, and the assistant will say
which.
Why both, every time: the layers are curated meaning and the transcript is the word-for-word
record; the next session reads the first and can reach into the second by timestamp. Close
without the ritual and the next session inherits a hole — it cannot see what happened, only
that something did, and emet_gaps will count it. Start without it and the assistant is a
stranger with your tools. The instruction block in docs/BOOTSTRAP.md
makes both of these automatic on hosts that take standing instructions; on hosts that do not,
the two words are what you supply.
Design notes
The six layers
Memory is split by what kind of thing an entry is, not by topic. Each entry carries an importance score and optional temporal validity.
| Layer | Holds | Importance | Written |
|---|---|---|---|
| identity | Who the assistant is and who it serves. Durable self-definition and the user's standing requirements. | 0.9 – 1.0 | Rarely, by design |
| semantic | Facts that stay true regardless of when they were learned. People, systems, definitions, established conclusions. | 0.6 – 0.9 | When a durable fact is established or corrected |
| episodic | What happened, and when. Session records, problems solved, progress through long work. | 0.4 – 0.7 | At session close and at milestones |
| procedural | How something is done, and decisions that govern future action — with the reasoning. | 0.5 – 0.8 | When a decision constrains later work |
| meta | Everything visible only from outside the exchange: how the memory system behaves, and how the assistant behaves toward the user. | 0.6 – 0.9 | On retrieval failures and wins, protocol drift, and corrections to how the user is worked with |
| working | Short-lived context, in-flight state, notes for whoever picks the work up. | 0.3 – 0.6 | When parking state between sessions |
The distinction that does most of the work: episodic, semantic and procedural are about the world — what happened, what is true, how something is done. Meta is about the system — looking back at the exchange from outside it. Material belonging in meta feels like nothing else fits it, which is precisely why it gets discarded when meta has no definition.
Every layer works from the first install
Creating six collections is not the same as having six layers. A layer with no stated charter has no answer to "does this belong here?", so nothing routes to it — and an empty collection throws no error and fails no test, so it can stay empty indefinitely without anyone noticing.
In the deployment this design came from, the meta layer sat nearly unused for about a year. The collection existed from day one and the tools accepted writes to it; it was simply never the obvious place to put anything. When it was finally given a definition it filled immediately — which is the proof that the material had been there all along and was being thrown away.
Two things in this repo exist because of that:
src/layers.jsships the charter for all six layers in code, andemet_initializereturns it — on a brand-new store as well as an established one. Same reasoning as the operating disciplines: documentation is read by people, and this has to reach the model at the start of every session. What belongs, what does not belong, when to write, when to read, and what the layer's absence looks like.assessLayerHealth()reports a layer that has gone dark. A store cannot know what should have been written, but it can see that one layer took almost nothing while the others filled, and say so in the first payload of the next session. Run against the real history above, it flags meta at 10 entries / 1.8% of the store — and goes quiet once the layer is in genuine use. It reports; it never blocks, and it stays silent on a store too new to have a pattern.
Two tiers, deliberately independent. Layer entries are curated meaning; a separate transcript store holds the word-for-word conversation. When a layer entry is relevant but thin, the transcript holds the depth that was compressed out of it. Summarising at transcript-write time collapses the two tiers into one and destroys the second line of inquiry — so the transcript path stores exactly what it is given. If a payload will not transmit, split it across parts; do not compress it.
How tier 1 reaches tier 2 — two links, one precedence rule.
An entry records the transcript span it came from: session_id plus a range of exchange indices,
written at save time as derived_from. Entries consolidated from other entries carry
{entries: [id, ...]} instead, because an entry with no transcript origin must be able to say so
rather than carry a nearest-timestamp guess dressed as a citation. Both are stored as top-level
indexed columns rather than inside the metadata subdocument, so the reverse question — every
entry drawn from this transcript — is entirely a query.
Every entry also has a timestamp, so a window around it can always be searched. The two are not redundant copies: the pointer is exact but conditional, the timestamp universal but approximate — it depends on choosing the window, degrades when sessions overlap, and when it is wrong it returns the neighbouring span rather than failing.
Precedence is what keeps them from conflicting: the pointer wins whenever present, the
timestamp is the fallback when it is null. Never averaged, never combined, and the timestamp is
never preferred merely because it returned something. resolveProvenance() applies the rule so no
caller has to decide it.
Keeping both buys something neither gives alone — they can check each other. If an entry's
pointer names a session whose span sits nowhere near that entry's own timestamp, something is
wrong: a mis-written pointer, a field copied from another entry, an entry attributed to the wrong
session. crossCheckProvenance() reports the disagreement. Two independently derived answers that
can disagree is redundancy in the engineering sense; one link that can only be trusted is not.
The reverse direction — what did we take from this session? — is not a second structure.
source_session_id is indexed, so it is the same data read the other way. A stored reverse index
would be a mirror of data that already exists, and mirrors are how forks are born.
Documentation truncated — see the full README on GitHub.
Reviews
No reviews yet
Be the first to review this server!
More Developer Tools MCP Servers
Rea
Freeby Morluto · Developer Tools
Reverse engineer anything from your terminal or agent with one CLI and MCP server.
Paperclip
Freeby Paperclipai · Developer Tools
Trending hip-hop artist momentum scores across four cultural dimensions.
Git
Freeby Modelcontextprotocol · Developer Tools
Read, search, and manipulate Git repositories programmatically
Toleno
Freeby Toleno · Developer Tools
Toleno Network MCP Server — Manage your Toleno mining account with Claude AI using natural language.
MCP Marketplace
Freeby mcp-marketplace · Developer Tools
Search and install MCP servers from inside your AI client.
mcp-creator-python
Freeby mcp-marketplace · Developer Tools
Create, build, and publish Python MCP servers to PyPI — conversationally.
