Skip to main content
Glama

Server Configuration

Describes the environment variables required to run the server.

NameRequiredDescriptionDefault
MEMAI_HOMENoDirectory to store the memai.db file. Defaults to ~/.memai.
MEMAI_ADMIN_PORTNoPort for the admin dashboard (default: 8765).
MEMAI_EMBED_MODELNoSet to a Hugging Face repo id or a local path to use a different embedding model instead of the bundled one.

Capabilities

Features and capabilities supported by this server

CapabilityDetails
tools
{
  "listChanged": false
}
prompts
{
  "listChanged": false
}
resources
{
  "subscribe": false,
  "listChanged": false
}
experimental
{}

Tools

Functions exposed to the LLM to take actions

NameDescription
noteB

Save a general long-term memory (fact, decision, finding). Stored as type='note'.

Timeless knowledge -- retrieved by relevance, not recency. Bring it back with recall() (or search(type='note')); pulse() also shows the few most recent ones as warm-up breadcrumbs.

tags: comma-separated keywords/synonyms -- write generously; tags feed both the keyword index and the embedding, so they make the memory findable even when the vector side is unavailable.

checkpointA

Snapshot current working state (intent/established/pursuing/open_questions).

A summary of where the work stands, so the next session picks up the right bearing via pulse(). Fields are free-length; still prefer a readable summary here and put timeless detail into note() -- checkpoints are read for bearing, not as an archive. Stored as type='checkpoint'.

anti_patternC

Record a mistake/temptation to avoid repeating, and the correct approach.

Stored as type='anti_pattern'; open ones for a domain are surfaced by pulse().

reasoningB

Record a reasoning trace / analysis worth keeping (not a fact, a thought process).

Stored as type='reasoning' -- filter search/list_* with type='reasoning' to get these back.

handoffA

Leave a note for another agent/session picking up this work.

Stored as type='handoff'; open ones for a domain are surfaced by pulse().

searchA

Hybrid search over memory content+tags+domain: BM25 keywords + local-model vectors.

Each result is annotated with match_source ("fts" | "vec" | "both"), fts_rank (bm25, lower = better) and/or vec_distance (cosine, lower = closer). Both retrievers only widen the candidate set -- judge the returned candidates yourself. Multiple space-separated paraphrases still help the keyword side (they're OR'd together). Only active memories by default. Falls back to keyword-only if the embedding model is unavailable. Content is snippet-truncated per result -- call get_memory(uid) for the full record.

type filters (one writer each): 'note', 'reasoning', 'checkpoint', 'anti_pattern', 'handoff'. To recall note()'d knowledge specifically, recall() is the sugar for search(type='note').

recallA

Recall long-term knowledge saved with note() (type='note').

The dedicated verb for "bring back what I noted": a hybrid search (BM25 + vectors) scoped to type='note', ranked by relevance -- which is what you want for timeless facts/rules/decisions. note() has no recency warm-up hook the way checkpoints have pulse(); this (or search(type='note')) is how notes come back. Content is snippet-truncated -- call get_memory(uid) for the full record.

list_by_domainA

List active memories for a domain, most recent first. Fallback when search misses.

Matches domain exactly -- see list_domains() for the real strings in use. Content is snippet-truncated per result -- call get_memory(uid) for the full record.

list_recentA

List the most recent active memories, optionally filtered by type/domain.

Content is snippet-truncated per result -- call get_memory(uid) for the full record.

list_domainsA

List distinct domains with their memory count and latest activity.

Warm-up discovery. domain is free text and drifts over time (e.g. 'PROJ-1042' vs 'proj-1042'), and pulse/list_by_domain match it exactly -- this surfaces the real strings so you target the right one instead of guessing. Ordered by most recent activity.

pulseA

Session warm-up: latest checkpoint + open handoffs/anti-patterns + recent notes.

Picks the checkpoint by created_at DESC, never by similarity -- a similarity-ranked top-1 can return a stale checkpoint over a same-day one, which is exactly the failure mode this avoids. latest_checkpoint is returned in full (that's the point of pulse), with its relations attached so linked memories are visible without a separate get_relations call. handoffs and anti_patterns are notes left for whoever resumes; recent_notes are the newest note()'d facts, as recency breadcrumbs -- for relevance-ranked recall use recall()/search(). Those three lists are snippet-truncated -- call get_memory(uid) for one in full.

get_memoryB

Fetch a single memory's full record, including its edit history and relations.

edit_memoryB

Correct/update a memory's content, keeping the previous version in edit history.

Corrections are common in append-only memory stores that only support delete, not edit; this preserves the old content instead of losing it.

link_memoriesA

Create a queryable edge between two memories.

relation_type is free text but keep it consistent, e.g. 'supersedes', 'relates_to', 'contradicts', 'links_to'.

get_relationsA

List all relations (incoming and outgoing) for a memory.

set_confidenceB

Set a memory's confidence: unverified | confirmed | contradicted.

forgetA

Archive a memory (soft delete -- content is kept, just excluded from default search/list).

A reason is recorded as a status-change audit entry (without touching the content or recomputing its embedding).

purge_memoryA

PERMANENTLY delete a memory + its edit history + relations. Irreversible.

Use forget() instead unless the user explicitly asked to permanently remove data -- forget() is reversible (archived, content kept), this is not. Guardrail: confirm_phrase must exactly equal "DELETE ", typed by the user in their own message. Do not construct this string yourself from an inferred "yes"/"confirm" -- it must come from the user actually stating the uid back.

dedup_scanA

Surface likely-duplicate/contradictory memory pairs.

Semantic (cosine over the embedded store) when vectors are available, lexical overlap otherwise -- each pair carries its method. Same- domain/session checkpoint pairs are excluded (timelines, not dups) and checkpoint pairs rank below durable-type pairs. Not an automatic merge -- returns candidate pairs + similarity score for the agent to review and decide (link_memories / edit_memory / forget as appropriate).

optimize_scanA

Dump the memory corpus compactly so you can plan a curation pass.

Step 1 of the "optimize my memories" workflow. Returns every memory's curation-relevant fields, the relation edges among them, and dedup-candidate pairs as a starting hint. Read this, then decide what to compact/reword/retag/redomain/set_confidence/archive/link/merge/ distill and stage it with optimize_stage.

The listing is slim on purpose so a few-hundred-memory store fits one response: content is a ~120-char snippet plus content_len (tags cut at ~100 with tags_len); empty/default fields are omitted (incl. confidence 'unverified' -- stats keeps the aggregate); created_at drops sub-second precision. Pass full=True for whole bodies, or fetch one with get_memory(uid) when a snippet is not enough. A page also ends early if its serialized size hits an internal budget, so one response ALWAYS fits the host's output cap. truncated: true means the listing stopped before the corpus ended -- page onward with offset = offset + count (stats.total is the whole corpus).

On a grown store, prefer INCREMENTAL curation over full-corpus passes: since limits the scan to memories created or updated at/after an ISO timestamp or date ('2026-07-01'), so a recurring "optimize my memories" only reviews the delta since the last run (optimize_runs shows when that was). Cross-window collisions are still caught: dedup_hints probe FROM the new memories against the whole store (a new memory duplicating an old one outside the window surfaces; old x old pairs are skipped), and domain_hints report any store-wide domain cluster the delta touches. Combine with domain/type to curate one slice at a time. Also included:

  • stats: totals for the whole filtered corpus (by_type, by_confidence, by_domain, empty_domain) -- computed regardless of limit,

  • domain_hints: clusters of domain-string variants that likely mean the same thing (case/separator drift, ticket-id spellings), with a suggested canonical -- ready-made redomain candidates,

  • anchors: per memory, the verifiable references found in its FULL content (URLs, file paths, table/field identifiers, constants), space-joined -- the things to go check against live facts.

Before proposing any change, CHECK IT AGAINST LIVE FACTS -- do not rewrite or archive something that was true then but stale now, and do not "correct" something that is still true:

  • cross-check newer memories already in this corpus (supersession / contradiction),

  • for code/config memories, verify the anchors against the live repo,

  • for world-facts, web-check current truth. Record what you verified in each suggestion's verified field -- destructive suggestions (archive, set_confidence=contradicted) are rejected without it.

optimize_stageA

Stage a batch of curation suggestions for human review in the dashboard.

Step 2 of the "optimize my memories" workflow. Writes the suggestions to a new optimization run; they are NOT applied here -- the user reviews and applies/rejects each one in the admin dashboard's Optimization tab, where a backup is taken before the first apply and every applied change can be undone.

Each suggestion is an object: {"kind": ..., "target_uid": ..., "payload": {...}, "rationale": "why", "verified": "what live-facts check you did"}

Kinds and their payload: compact / reword {"new_content": str} retag {"tags": str} comma-separated redomain {"domain": str} set_confidence {"confidence": "unverified|confirmed|contradicted"} archive {"reason": str} soft/reversible; never hard-deletes link {"from_uid", "to_uid", "relation_type", "note"?} merge {"keep_uid", "drop_uid", "note"?} links supersedes + archives drop distill {"source_uids": [uid, ...], "new_type": "note|reasoning|anti_pattern", "new_content": str, "tags"?, "domain"?}

distill extracts the durable knowledge out of one or MORE source memories into a newly authored one: creates it, links it supersedes each source and archives the sources (all reversible). Use it to retire closed-ticket checkpoints without losing what they taught, or as an n-ary merge when the survivor needs synthesized content.

link/merge derive target_uid from the payload (from_uid / drop_uid) and distill creates its target -- omit target_uid for those kinds. Destructive suggestions (archive, set_confidence=contradicted, distill) require a non-empty verified describing the live-facts check that justifies them.

Invalid suggestions are skipped and reported in errors; the rest are staged. Returns {run_id, staged, errors}.

optimize_runsA

List optimization runs with their review progress.

Read-only companion to optimize_stage: after staging, use this to see whether the user has applied/rejected your suggestions in the admin dashboard. Each run carries total/pending/applied/rejected counts, its note, and the safety-backup path once the first apply happened. Applying/rejecting stays in the dashboard by design -- the agent proposes, the human disposes.

optimize_statusA

Inspect one optimization run: every suggestion and its decision.

Read-only. Returns the run header plus each suggestion's kind, target_uid, payload, rationale, verified, status (pending/applied/rejected) and decided_at -- so you can tell which proposals landed, follow up on rejected ones, or build on applied ones in a later pass.

helpA

Explain the memai tools, read directly from their code docstrings.

Without arguments: every tool with its one-line summary. With command='': that tool's full signature and docstring. The docs can't drift from behavior because they ARE the code's own docstrings, extracted at call time.

Prompts

Interactive templates invoked by user choice

NameDescription

No prompts

Resources

Contextual data attached and managed by the client

NameDescription

No resources

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Filipe-Soares-de-Almeida/MemAI'

If you have feedback or need assistance with the MCP directory API, please join our Discord server