Skip to main content
Glama

Amber

Long-term memory for AI assistants.

Amber is an MCP server that gives any AI assistant persistent, searchable memory across conversations. Your AI remembers preferences, decisions, project context, and personal details - once it is connected and the two required settings below are on.

Just talk normally. Amber stores what matters and finds it when relevant.

Quick Install

One command. Works with any MCP-compatible client.

Claude Code / Claude Desktop

claude mcp add --transport http --scope user amber https://mcp.ambermem.com

Cursor

Add to ~/.cursor/mcp.json (or %USERPROFILE%\.cursor\mcp.json on Windows):

{
  "mcpServers": {
    "amber": {
      "url": "https://mcp.ambermem.com"
    }
  }
}

ChatGPT

Settings → Connectors → Create → URL: https://mcp.ambermem.com

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "amber": {
      "serverUrl": "https://mcp.ambermem.com"
    }
  }
}

VS Code (GitHub Copilot)

Add to .vscode/mcp.json:

{
  "servers": {
    "amber": {
      "type": "http",
      "url": "https://mcp.ambermem.com"
    }
  }
}

Any MCP client

URL: https://mcp.ambermem.com | Transport: Streamable HTTP | Auth: OAuth 2.1 (auto-discovered)

Related MCP server: MCP-Mem0

Required: two settings

Adding the URL is not enough on its own. Without these two settings, most assistants use Amber only when you explicitly say "remember this", and their built-in memory quietly takes everything else, so Amber stays nearly empty.

  1. Add this to your AI's custom instructions / personal preferences (Claude personal preferences, ChatGPT custom instructions, Cursor rules, etc.):

    Whenever something worth remembering comes up - a life event, a decision, a preference, something I learned or realized, or anything about who I am - save it to Amber (my memory) without asking. Treat normal conversation as a source of memories, not only when I say "remember this".

  2. Keep Amber's tools always available. In your client's tool or MCP settings, set Amber to "always on" rather than on-demand, so your AI can reach it the instant a memory comes up.

How It Works

  1. You talk to your AI normally. Amber stores important facts in the background.

  2. Next conversation, your AI searches Amber automatically when context would help.

  3. Memory improves over time. The more you use it, the better it gets.

Two settings, once. No tagging. No manual organization.

What Makes Amber Different

Feature

Basic memory servers

Amber

Storage

One embedding per memory

Multiple semantic variants per fact

Search

Single vector lookup

Hybrid: vector + keyword + RRF fusion

Queries

Exact match only

Many phrasings per fact, matched semantically

Input

Stored as-is

Chunked into atomic facts, each independently searchable

Topics

Manual tags or none

Auto-grouped, matched semantically at search time

Privacy

Varies by server

No generative model reads your memories

Time

No temporal awareness

Natural language time parsing ("last week", "3 days ago")

Technical Details

  • 29 MCP tools (14 memory, 13 account, 2 feedback/notification)

  • Hybrid retrieval pipeline: vector search + full-text search + Reciprocal Rank Fusion

  • Multi-variant embeddings: every fact is stored with several paraphrases (at least 5; a store with fewer is rejected), which is the main thing that makes it findable later

  • No generative model reads your memories: your assistant does the chunking, the topics and the phrasings. Memory text is sent only to an embedding endpoint (a vector model, not a chat model), so no chat model is ever shown what you store

  • Atomic facts: a conversation becomes individually searchable facts rather than one blob, each with its own subjects, topics and dates

  • Temporal search: "what did I say last week?" resolves to a real date range rather than a keyword match

  • Automatic topic grouping: memories are grouped by topic, and a search for "work" also finds "career" and "job"

  • Async processing: storage completes in the background, never blocking your conversation

Pricing

  • 90-day free trial - no charge, cancel anytime

  • $2.99/month after trial, via PayPal

  • Cancel instantly - ask your AI to cancel, or cancel through PayPal directly

  • No lock-in - export all your data as JSON anytime

Privacy

  • No email collected

  • No marketing, no spam

  • Data isolated per user (separate database)

  • PayPal handles all payment info

  • Full export + account deletion available

  • GDPR compliant (data minimization by design)

Architecture

Amber runs on Cloudflare Workers (zero cold starts, global edge deployment) with Turso databases (one per user, full isolation). Your assistant does the chunking, the topics and the phrasings, so no generative model is ever shown what you store; memory text is sent only to OpenAI's embedding endpoint.

For full technical documentation: ambermem.com/llms.txt

FAQ

Will it slow my AI down? No. Storage is async (background). Search adds <1 second.

What if Amber shuts down? Export all your data as JSON anytime. Your data is always yours.

Do I need a PayPal account? Currently yes. PayPal handles both identity and billing. More login options coming soon.

Is my data safe? Each user gets a completely isolated database. No data is shared between users. Amber has no access to your PayPal payment details.

Can I self-host? Not currently. Amber is a managed service. We handle the infrastructure, scaling, and LLM costs so you don't have to.

Available Tools

29 tools
amber_cancel_account_deletionCancel scheduled account deletionA
Idempotent
Inspect

Cancel a previously scheduled account deletion. Removes the deletion deadline and unblocks memory tools immediately. Access resumes until next_billing_date (the remaining paid period). No data is lost.

Side effects: clears deletion_scheduled_at from the account. The PayPal subscription was already cancelled when deletion was scheduled -- call amber_reactivate_subscription to start a new one if the paid period has expired. Returns code: not_scheduled if no deletion is pending. Not rate-limited.

Inputs: no named parameters. Returns: status, message

amber_cancel_subscriptionCancel the subscriptionA
DestructiveIdempotent
Inspect

Cancel the user's PayPal subscription. Access continues until next_billing_date (already paid). Data is preserved, not deleted. Do NOT use if the user wants to delete their account entirely -- use amber_delete_account instead.

Cancellation is sent to PayPal immediately; status update arrives via webhook within ~1 minute. Returns code: no_subscription if none exists. Requires confirm: true.

Errors: cancelled (you did not pass confirm: true; NOTHING was attempted - the name is historical and collides with the success status: cancelled this same tool returns when a cancellation DOES happen, so branch on which FIELD carried it: error.code means you did not confirm, status means it is done), no_subscription (this account has no subscription), not_found (PayPal did not recognise the subscription id on this account; it may already have been cancelled or expired), deletion_scheduled (the account is already scheduled for deletion, which ends billing anyway), cancel_failed (PayPal refused; the subscription is unchanged, so it is safe to retry).

Inputs: confirm (required). Returns: status, message

amber_create_backup_keyCreate a backup keyA
Destructive
Inspect

Create a key that lets an automated job download a full export of this account without an AI session -- for example a weekly cron that saves everything to the user's own S3 bucket or NAS.

Usage: a backup is a task. POST /backup with header X-Amber-Backup-Key: <key> returns a task_id; poll GET /backup/<task_id> with the same header until status is complete, then download the download_url it carries. A ready-to-run weekly script is at https://ambermem.com/backups

IMPORTANT: the key is shown ONCE and never again -- only a hash is stored, so it cannot be recovered, only replaced. RELAY IT TO THE USER VERBATIM and tell them to save it somewhere safe. There is one key per account: calling this again REPLACES the previous key, which immediately stops working. That is how rotation works, and how to respond if a key leaks. The response says when the replaced key was last used, so you can tell the user whether a scheduled job just stopped -- RELAY THAT WARNING if it is there, because the job will not report the failure itself. The key does exactly TWO things: download an export, and start a restore -- which is a WRITE, so treat it as more than a read credential. It cannot read an individual memory, change the subscription, or delete the account. Corrected 2026-09-19: this said "exactly one thing ... cannot read, write or delete anything", which understated it, and the tool's own response text said the opposite. A restore also puts trashed memories back AS trash, which is a change rather than an addition. The backup includes deleted memories still in the trash. Backups are limited to one per hour. Revoke with amber_revoke_backup_key. Not rate-limited. ASK THE USER how long a gap without a successful backup should be treated as a problem, and pass it as warn_after_days. Without it Amber has to fall back to a cautious 30 days, and a backup that stopped is invisible until the day it is needed.

Inputs: warn_after_days. Returns: message, backup_key, example_command, warn_after_days, +2 more

amber_delete_accountSchedule account deletionA
DestructiveIdempotent
Inspect

Schedule permanent account deletion in 30 days. Memory tools are blocked immediately (unlike cancellation, which keeps access until period end). Cancels the PayPal subscription. Reversible within 30 days via amber_cancel_account_deletion.

During the grace period: account management tools (status, export, feedback) remain accessible; memory tools are blocked. After 30 days: all data is permanently deleted.

Requires confirm: true. Returns code: cancelled when false, code: already_scheduled if already pending.

Inputs: confirm (required). Returns: status, message, deletion_date

amber_delete_memoryDelete memories (soft-delete)A
DestructiveIdempotent
Inspect

Soft-delete one or more memories to the trash. Reversible via amber_restore_memory. Do NOT use this for account-level cleanup -- use amber_delete_account instead.

Provide memory_id (single) or memory_ids (batch, max 100). At least one is required. Idempotent: already-deleted memories are skipped. EVERY ID you send is accounted for: deleted_count plus already_deleted_ids (existed, already trashed) plus not_found_ids (no such row). ALWAYS check deleted_count against how many IDs you sent -- a batch is NOT all-or-nothing, and a shortfall usually means those memories are still being written (amber_store_memory is async), so check amber_get_store_task_status and retry rather than assuming they are gone. If the IDs are already in the trash you get deleted_count: 0 with an explanatory message (a no-op, NOT an error); code: not_found is returned only when no memory exists with those IDs -- so a no-op is distinguishable from wrong IDs. VERIFY WHAT YOU DELETED: the reply carries deleted -- the full content of every memory this call actually trashed. READ IT and confirm it is what the user meant, because an id proves nothing: if you deleted the wrong memory this is the moment to notice, and amber_restore_memory puts it straight back. Tell the user what was deleted rather than only how many. Requires an active subscription. Not rate-limited.

Errors: invalid_params (no id supplied, or both singular and plural given). A wrong TYPE -- a number where a string belongs -- is caught a layer earlier and answers invalid_input. Deleting an id that does not exist is NOT an error: deleted reports what was actually trashed, so compare its length against how many ids you sent.

Inputs: memory_id, memory_ids. Returns: status, deleted, deleted_count, not_found_ids, +1 more

amber_export_memoriesStart a full export of all memoriesA
Read-only
Inspect

Start exporting your memories to a downloadable JSON file. Returns a task_id IMMEDIATELY -- the file is built in the background. Poll amber_get_export_status with that id until status is complete, then give the user the download_url it returns.

By DEFAULT exports ACTIVE memories only; pass include_deleted=true to also include trashed (soft-deleted) memories. IF THE USER ASKED FOR A BACKUP, PASS include_deleted=true. Amber's deletes are reversible, so an active-only archive is missing everything they could still restore -- on a real account that was 121 records against 6,334. The unattended route at /backups always includes the trash for that reason; active-only is the right choice for "let me look at my data", not for a backup. Each record carries content, subjects, topics, metadata (internal prefixes stripped), event dates, and timestamps (deleted records also carry deleted_at).

Use this when the user wants a backup, wants to migrate data, or asks "can I download my data?". Unlike amber_list_memories (which paginates one page at a time), this exports ALL memories into one file; unlike amber_search_memories (which finds specific content), this is a complete dump.

WHY IT IS ASYNC: an export of a large account cannot be produced inside one request, so it is built in slices in the background. There is no size limit and no truncation. A small account is usually ready on the first poll; a large one takes several. For an UNATTENDED schedule (a weekly cron with no assistant running), point the user at https://ambermem.com/backups instead -- same mechanism over plain HTTP.

Does not modify any data -- read-only. Requires an active subscription. Not rate-limited.

Errors: queue_failed (the export could not be queued; nothing was started, so retrying is safe and creates no orphan task).

Inputs: include_deleted. Returns: status, message, task_id, exported_at

amber_get_account_statusGet account statusA
Read-onlyIdempotent
Inspect

Return the authenticated user's account summary: subscription state, next billing date, memory counts, and account creation date. Use this when the user asks about their account, subscription status, or how many memories they have.

After cancellation, access continues until next_billing_date (the end of the paid period). Once ACCESS ends, memory counts show as null (data is preserved, just not queryable until resubscribed) -- note that is later than subscription_active turning false, because a cancelled subscription keeps access until its paid period ends and reports real counts until then. If deletion_scheduled_at is set, the account is pending permanent deletion -- use amber_cancel_account_deletion to stop it. Read-only -- does not modify any account state. Not rate-limited.

Inputs: no named parameters. Returns: user_id, payer_id, member_since, memory_count, +6 more

amber_get_export_statusCheck export status and get the download linkA
Read-onlyIdempotent
Inspect

Check an export started by amber_export_memories, and collect its download link once it is finished. Not rate-limited. Read-only. Requires an active subscription.

Statuses: pending (queued), running (writing the file), complete (ready -- download_url is set), failed (gave up; error says why).

Poll every few seconds. memory_count climbs while it runs, so a caller can tell progress from a stall. Only report the export as ready to the user once status is complete.

The download_url is signed and valid for 7 days, matching how long the export itself is kept, so an interrupted download can be RESUMED with a Range request rather than restarted. Call this again for a fresh link if it has expired, and note an old link. The export itself is kept for 7 days, after which this returns code: not_found.

Inputs: task_id (required). Returns: error, status, task_id, chunk_count, +4 more

amber_get_import_statusCheck a restore in progressA
Read-onlyIdempotent
Inspect

Check a restore in progress, whichever way it was started: the upload panel from amber_upload_backup, the browser page at https://ambermem.com/restore, a URL given to amber_import_memories, or a presigned upload from POST /import/presign. Not rate-limited. Read-only. Requires an active subscription.

Statuses: awaiting_upload (a link was handed out and no file has arrived yet; not a failure), pending (queued), running (restoring), complete, failed (error says why).

imported_count climbs while it runs, so a caller can tell progress from a stall. There is NO total to compare it against: the archive is never read in full up front, which is what lets a restore of any size cost the same per step. It counts memories PROCESSED, so re-running a restore counts them again even though nothing is written twice.

IF IT FAILED, SAY SO PLAINLY AND RELAY error, which names the cause and what to do. Starting a new restore is safe: memories keep their ids, so anything already restored is skipped rather than written twice. If the error says the file is damaged or cut short, the same file will stop at the same place, so restore from a fresh backup instead. A memory that was in the trash in the backup is restored INTO the trash, and is counted in imported_count like the rest. Errors: not_found (no task with that id, or it belongs to another account, or it aged out after 7 days), invalid_input (the id is missing or not a string -- the schema layer answers this one).

If the user still needs to get a file INTO Amber, amber_upload_backup shows them an uploader; https://ambermem.com/backups documents the scripted route.

Inputs: task_id (required). Returns: error, status, task_id, exported_at, +1 more

amber_get_memoryGet a memory by IDA
Read-onlyIdempotent
Inspect

Retrieve a single memory by its ID with full, untruncated content. Use this after amber_search_memories when a result's content was truncated (indicated by truncated: true), or when you have a memory_id from a previous interaction and need the complete text.

Returns the memory with its full content, metadata (if any), topic names (if any), and created_at timestamp. Resolves a memory by id whether it is active OR in the trash -- a non-empty deleted_at marks a trashed one (restore it with amber_restore_memory). Returns code: not_found only if no memory with that id exists at all. Read-only -- does not modify the memory. Not rate-limited. Requires an active subscription.

Inputs: memory_id (required). Returns: memory

amber_get_store_task_statusCheck memory storage statusA
Read-onlyIdempotent
Inspect

Check the processing status of a memory store task. Call this before you list, search for or delete the facts you just stored, or when the user asks whether something was saved. Do NOT hold your reply to the user waiting for completed: an accepted store is already durable and finishes in the background, usually within a minute for a few facts. Not rate-limited. Read-only. Requires an active subscription.

Statuses, and these are the ONLY four: pending (accepted and queued, nothing written yet), processing (facts are being written; some are already stored), completed (every fact written), error (error says why). Poll until completed -- note the ed. The import tool's vocabulary (awaiting_upload, running, complete, failed) was published here by mistake until 2026-09-12; an agent waiting for complete waited for ever.

progress reads Stored N/M memories... while writing. Facts are embedded in one batch and then written one at a time, each write idempotent and retry-safe, so a QUEUE redelivery creates no duplicates. That is Amber retrying internally. A CLIENT retry is different: re-sending the same amber_store_memory call starts a NEW task and stores a second copy, so check this status before resending after a transport error.

Rows become listable and SEARCHABLE as they land, NOT only at completed: a partially written task already has some of its memories retrievable. Wait for completed before concluding a fact is absent.

Returns code: not_found if the task_id doesn't exist or has expired (tasks are pruned after 7 days).

Inputs: task_id, idempotency_key. Returns: error, status, task_id, progress, +2 more

amber_import_memoriesRestore memories from a backup URLA
Idempotent
Inspect

Restore an Amber backup from a URL. Amber reads the archive DIRECTLY from that URL and never stores a copy of it.

Use this when the user has their .json.gz backup somewhere reachable over HTTPS -- S3, R2, Backblaze, Google Cloud Storage, a self-hosted MinIO, or any presigned link. IF THE FILE IS ONLY ON THEIR COMPUTER this tool cannot reach it: send them to https://ambermem.com/backups, which explains how to upload it directly. Do not ask them to paste the file contents; a backup is far too large and it is not text you can retype.

THE LINK MUST STAY VALID FOR THE WHOLE RESTORE, which runs for hours on a large account -- tell the user to use one good for at least 30 days. Amber re-reads the URL as it works, so a link that expires part-way stops the restore.

SAFE TO RUN AGAIN. Memories keep the ids they had in the archive, so re-running cannot duplicate anything -- and a restore that stopped part-way resumes rather than starting over. This ADDS to the account; it never deletes or replaces what is already there.

Returns a task_id. Poll amber_get_import_status until it says complete, and tell the user the count when it does. Requires an active subscription.

Errors: invalid_params (the URL is not https, points back at Amber, carries credentials, cannot be read right now, does not support range requests, or what is behind it is not an Amber archive). All of that is checked BEFORE any task is created, so a rejected URL leaves nothing behind.

Inputs: url (required). Returns: status, message, task_id

amber_list_deleted_memoriesList deleted memories (trash)A
Read-onlyIdempotent
Inspect

Browse the trash in reverse chronological order of deletion (most recently deleted first). Supports cursor pagination via after_id. has_more tells you whether another page exists. Use amber_restore_memory to bring an item back, or amber_search_deleted_memories for meaning-based search within the trash.

Each result includes full content (not truncated), metadata, topics, creation timestamp, and deletion timestamp. Pass metadata_filter for an EXHAUSTIVE exact-match filter over the trash (same as amber_list_memories). Read-only -- does not modify or permanently delete any memories. Not rate-limited. Requires an active subscription.

Returns memories array, next_cursor (null if no more pages), and has_more boolean.

Errors: invalid_input (a bad cursor, limit, or filter type).

Inputs: limit, after_id, metadata_filter. Returns: has_more, memories, next_cursor

amber_list_memoriesList active memories (chronological)A
Read-onlyIdempotent
Inspect

Browse all active memories in reverse chronological order (newest first). Use cursor-based pagination via after_id. has_more tells you whether another page exists. Prefer amber_search_memories when looking for specific content; use this when the user wants a browsing overview or asks "show me my recent memories".

Each result includes full content (not truncated), subjects, metadata, topics, event dates, and creation timestamp. Pass metadata_filter for an EXHAUSTIVE exact-match filter -- it returns every memory carrying the given metadata (search's metadata_filter is relevance-bounded and can miss low-scoring matches). Read-only -- does not modify any memories. Not rate-limited. Requires an active subscription.

Returns memories array, next_cursor (null if no more pages), and has_more boolean.

Errors: invalid_input (a bad cursor, limit, or filter type). A cursor from another account or an older schema is rejected rather than silently restarted from the beginning.

Inputs: limit, after_id, metadata_filter. Returns: has_more, memories, next_cursor

amber_list_subjectsList existing subjects (people)A
Read-onlyIdempotent
Inspect

List the subjects (people) already in memory, most-mentioned first, with a count and the topics their memories appear under. Call this before amber_store_memory or amber_search_memories when you're unsure how a person was recorded, and REUSE the existing spelling ("patrick vane") instead of a near-duplicate ("pat"/"patrick"/"patrick v"). Subject drives retrieval ranking, so consistent naming matters even more than for topics.

USE topics TO CATCH A SPLIT PERSON. Subjects match by EXACT text, so one human recorded under two names (a nickname, a maiden name, a first name then a full name -- e.g. "katie" and "yu pan") forks silently into two people, and every later search returns a plausible but INCOMPLETE answer. String similarity cannot catch that, because the two spellings need not share any characters. Overlapping topics are the signal: two subjects that both appear under e.g. "relationships" may be the same person. If you suspect a fork, confirm it with the USER (never merge on your own inference -- wrongly merging two real people is worse than the fork), then repair it with amber_rename_subject, which merges into the target name.

Read-only, not rate-limited. Requires an active subscription.

Inputs: limit. Returns: has_more, subjects

amber_list_topicsList existing topics/tagsA
Read-onlyIdempotent
Inspect

List the topics (tags) already in use, most-used first. Call this before amber_store_memory when you're unsure whether a topic already exists, and REUSE an existing name instead of minting a near-duplicate (reuse "work" rather than adding "career" or "job"). By default only topics with at least one live memory are shown; pass include_empty=true to also see orphaned 0-count topics (topics aren't deleted when their memories are). Consistent topics keep the topics filter in amber_search_memories reliable. Read-only, not rate-limited. Requires an active subscription.

Inputs: limit, include_empty. Returns: topics

amber_manage_subscriptionGet subscription management URLA
Read-onlyIdempotent
Inspect

Return a PayPal URL the user can open to manage their subscription (update payment method, view billing history, change payment source) and the next billing date. Use this when the user asks about billing, wants to change their payment method, or wants to view their subscription details.

Unlike amber_cancel_subscription (which cancels) or amber_reactivate_subscription (which creates a new subscription), this tool only provides a link to PayPal's self-service page -- no changes are made by calling it.

The URL opens PayPal's subscription management page -- Amber does not handle payment details directly. Returns code: no_subscription if the account has no subscription on record (use amber_reactivate_subscription to start one). Read-only -- does not modify the subscription. Not rate-limited.

Inputs: no named parameters. Returns: message, manage_url, next_billing_date

amber_mark_notification_readMark a developer notification as readA
DestructiveIdempotent
Inspect

Dismiss a developer notification after the user has acknowledged it. Permanently removes it from the developer_notifications block. That block is appended to a tool response ONLY WHEN there is at least one unread notification -- most responses will not contain it, and its absence means there is nothing pending, not that the feature is missing.

Side effects: deletes the notification row from the user's database. Idempotent in intent but returns code: not_found if already dismissed. Only call after the user has seen the notification content. Not rate-limited.

Inputs: notification_id (required). Returns: status, notification_id

amber_reactivate_subscriptionSubscribe or resubscribeAInspect

Create a PayPal subscription and return an approval URL. The user MUST open this URL in their browser to activate. Do NOT use if the user just wants to manage an existing subscription -- use amber_manage_subscription instead.

First-time: 90-day free trial, then $2.99/month. Returning: preserves remaining free days, or bills immediately if expired. Warn the user to log in with the SAME PayPal account they originally signed up with.

No charge until the user approves. Returns code: already_active if active, code: deletion_scheduled if deletion is pending. Each call creates a NEW pending subscription with its own approval URL, so give the user the latest one. Approving one cancels any other active subscription on the same account, so an older link approved by mistake cannot bill twice.

Errors: creation_failed (PayPal would not create the subscription; nothing was charged and retrying is safe).

Inputs: no named parameters. Returns: status, message, approval_url

amber_rename_subjectRename a subject (person) everywhereAInspect

Relabel a subject (person) across EVERY memory tagged with them -- use when a name changes, or when you learn more of it (you stored facts under "sean" and later learn it is "sean okafor"). Subject retrieval is EXACT-MATCH, so a bare first name or an outdated name is a latent retrieval miss; this fixes all of that person's memories at once. If some of those memories already carry new_subject, they MERGE onto the one name -- merged_into_existing reports how many. NEVER deletes a memory. A plain rename (target name unused) is fully reversible by renaming back. A MERGE IS NOT REVERSIBLE: once two names are one, renaming back moves ALL of those memories to the old name, including the ones that never had it -- the original split cannot be restored through this tool. So when merged_into_existing would be > 0 you are performing a ONE-WAY operation: be correspondingly sure, and prefer confirming with the user first. Both names match case-insensitively and are normalized the same way stored subjects are (call amber_list_subjects to see exact spellings first). Also relabels the person on any of their memories currently in the trash, so restoring one later stays consistent -- so renamed_count (total memories relabelled) can exceed the active count shown by amber_list_subjects. Returns renamed_count; 0 (a no-op, not an error) if no memory was tagged with old_subject. Requires an active subscription.

Errors: invalid_input (a name is empty, too long, or carries control characters).

Inputs: new_subject (required), old_subject (required). Returns: status, new_subject, old_subject, renamed_count, +5 more

amber_restore_memoryRestore deleted memoriesA
Idempotent
Inspect

Un-delete memories from the trash, making them searchable and visible in amber_list_memories again. Use after amber_search_deleted_memories or amber_list_deleted_memories to recover accidentally deleted content. Do NOT use for new content -- use amber_store_memory instead.

Provide memory_id (single) or memory_ids (batch, max 100). At least one is required. Idempotent: already-active memories are skipped. Side effects: moves memories from trash to active. VERIFY WHAT CAME BACK: the reply carries restored -- the full content of every memory this call actually un-trashed. READ IT and confirm it is the one the user meant, because an id proves nothing. EVERY ID you send is accounted for: restored_count plus already_active_ids plus not_found_ids. ALWAYS check restored_count against how many IDs you sent -- a batch is NOT all-or-nothing. If the IDs are already active you get restored_count: 0 with an explanatory message (a no-op, NOT an error); code: not_found is returned only when no memory exists with those IDs -- so a no-op is distinguishable from wrong IDs. Requires an active subscription. Not rate-limited.

Errors: invalid_params (no id supplied, or both singular and plural given); a wrong TYPE answers invalid_input from the schema layer. Restoring something that was never deleted is not an error either; it comes back in already_active_ids.

Inputs: memory_id, memory_ids. Returns: status, restored, not_found_ids, restored_count, +1 more

amber_revoke_backup_keyRevoke the backup keyA
DestructiveIdempotent
Inspect

Revoke this account's backup key. Any automated job using it stops working immediately. Use this if a key may have leaked -- for example it was committed to a repository or pasted into a log. Returns code: not_found if no key exists. To rotate instead of simply revoking, call amber_create_backup_key, which replaces the old key in one step. Not rate-limited.

Inputs: no named parameters. Returns: message, revoked

amber_search_deleted_memoriesSearch deleted memories (trash)A
Read-onlyIdempotent
Inspect

Search within the trash for soft-deleted memories. Useful when the user asks about something they've since deleted. Results are ordered by relevance (higher score = better match; scores are relative within a single query). Optional max_age_days restricts to recently deleted items. Optional topics filters by topic (semantic matching). For ranking quality it takes the SAME optional steering params as amber_search_memories -- subjects, query_variants, keywords -- so trash ranking matches active search. Content is truncated to 1000 chars -- use amber_get_memory for full content. Use amber_restore_memory to bring a result back. Rate-limited (search bucket: 5000 capacity, refills ~1 per 17 seconds).

Errors: invalid_input (a parameter has the wrong type, or a date could not be parsed).

Inputs: query (required), subjects (required), topics, keywords, +6 more. Returns: results

amber_search_memoriesSearch memoriesA
Read-onlyIdempotent
Inspect

Find active memories by semantic meaning. Write the query as a natural-language question or description, NOT as keywords. Good: "What are the user's dietary preferences?", "meetings the user had last week". Bad: "diet food preferences", "meeting notes". Recall depends on YOU expanding the query: pass alternative phrasings in query_variants (synonyms, related terms, and sub-questions), the same way you attach variants when storing. Amber searches the query plus every variant and fuses the results -- it does NOT expand the query for you. For exact-term precision, also pass the distinctive lexical terms the answer would contain (key nouns, product names, numbers, IDs) in keywords -- and OMIT the subject's name from them (use subjects for that). Supports optional metadata filtering (e.g. { "user_tag": "work" }). Results are ordered by relevance (higher score = better match). Scores are only meaningful for ranking within a single query, not across different queries. IMPORTANT -- results are RANKED, never FILTERED: Amber always returns the closest n_results memories it has, even when none of them actually answer the query. A returned memory is therefore NOT evidence that the answer is stored, and a low score is not a reliable absence signal (scores aren't comparable across queries). YOU must judge relevance by READING the content: if no returned memory actually states the fact you asked about, treat it as NOT in memory. This matters most for the mandatory search-before-store check -- only count a fact as already stored when a returned memory genuinely states it, not merely because results came back. Ask for fewer results (n_results) if the padding is noisy. Use amber_list_memories for chronological browsing. When several results describe the SAME subject at different points in time, read them as a TIMELINE of how it evolved -- a more recent memory updates an older one, it does NOT contradict it. Each result carries created_at (and event_start/event_end when known); use those timestamps to order the progression rather than treating differing facts as a conflict. Optional topics param: pass topic names (like when storing) to focus on a category -- matched SEMANTICALLY against topics that already exist, so "beliefs" also matches "opinions"/"superstitions". It restricts the SEMANTIC half of the search to memories under the nearest topics and gives closer ones a BOUNDED lift (at most 1.5x) -- it does NOT re-sort by topic, and the keyword half is not restricted, so off-topic memories can still appear. Do not expect the on-topic memory at #1: a memory that answers the query better still wins, which is deliberate (a wrong topic guess must never bury the true answer). There is NO similarity floor: your name is matched to the NEAREST existing topics whatever their similarity, so a name matching nothing conceptually still resolves to the closest topics rather than to none. Check topics_resolved -- it reports the similarity of each match, and a low number there means your name found nothing real. A poor match cannot bury the true answer, because the lift is bounded and the keyword half is never restricted, but it does not silently become a no-op either. Omit if unsure. Content is truncated to 1000 chars in search results -- use amber_get_memory for full content. Rate-limited (drip bucket: 5000 capacity, refills ~1 token per 17 seconds).

Errors: invalid_input (a parameter has the wrong type, or a date could not be parsed). An empty result is NOT an error and comes back as an ordinary response with no hits. It is also RARE, because ranking pads results rather than filtering them, so treat it as "this account has nothing to rank" -- a new or emptied store, or a metadata_filter that excluded everything -- rather than as a stronger absence signal than a padded result.

Inputs: query (required), subjects (required), topics, keywords, +5 more. Returns: results, topics_resolved, filter_truncated, filter_matched_total

amber_search_subjectsSearch subjects (people) by nameA
Read-onlyIdempotent
Inspect

Find subjects (people) already in memory WITHOUT listing them all. Same data as amber_list_subjects -- name, memory count, and the topics their memories appear under -- just filtered. Prefer this over amber_list_subjects once a store has grown: listing every subject with its topics costs thousands of tokens on every store, and you usually only need to check one person.

MATCHING -- one rule: NO * means CONTAINS, and * is an anchor. • vane -> contains: finds "patrick vane" AND "robin vane" • van* -> starts with • *vane -> ends with • patrick*vane -> starts with one, ends with the other • * or an empty query -> everything (same as amber_list_subjects) Case- and accent-insensitive: andre finds "andré bremer". Spaces, hyphens, apostrophes and periods are IGNORED on both sides when comparing, so vanderberg and van-der berg both find "van der berg". Word ORDER still matters: berg van does NOT match it. Anchors apply to that compared form, so *jr DOES match "van der berg jr." -- the trailing period is not part of what is compared.

IT MATCHES TEXT, NOT PEOPLE. It cannot tell you that "pat" is "patrick vane" -- unrelated spellings of one human (a nickname, a maiden name) share no characters, so no text search finds them. To catch a person split across two names, list subjects and compare their topics, as amber_list_subjects explains.

Read-only, not rate-limited. Requires an active subscription.

Inputs: query (required), limit. Returns: has_more, subjects, total_matched

amber_send_feedback_to_developerSend feedback to the developerAInspect

Send a structured bug report, feature request, or general feedback to Amber's developer. Send feedback PROACTIVELY when you encounter errors, unexpected behaviour, or the user expresses frustration -- briefly mention it to the user after sending, but do not ask for permission first. Never include passwords, API keys, or other sensitive personal information in any field. Rate-limited (bucket: 12 capacity, refills 1 per 5 minutes).

Inputs: details (required), summary (required), category (required), tool_context. Returns: status, message

amber_store_memoryStore memoriesAInspect

Store long-term memories you can search later with amber_search_memories. YOU do the preparation. Amber only validates and stores what you send, so follow these rules exactly for consistent, searchable memories. ALWAYS search before you store (see "SEARCH FIRST" below): Amber removes ONLY facts that are byte-identical to another fact in the SAME call (reported as duplicates_collapsed) -- it does NOT deduplicate across separate calls (a retry after a transport error stores a second copy UNLESS you sent an idempotency_key, which is exactly what that parameter is for -- generate one per store and resend with the SAME key to get the original task_id back instead of a duplicate), and it never matches on MEANING, so a re-worded restatement of an existing memory is stored as a second copy. Preventing those is entirely your responsibility.

WRITES ARE ASYNCHRONOUS. "Accepted N fact(s)" means your facts were validated and queued, NOT that they are stored yet. Rows are not queryable until the task reports completed: poll amber_get_store_task_status with the returned task_id BEFORE you list, filter, search for, or delete them, and check memory_ids.length against fact_count. Acting sooner gives misleading results -- a list can show fewer rows than you sent and a delete can silently skip one that has not landed yet. But do NOT hold your reply to the user waiting for it: an accepted store is already durable, so answer first and check the status only when you are about to act on those rows or the user asks whether it was saved.

Send memories: an array of ATOMIC FACTS you extracted from the conversation. Break the source text into the smallest possible self-contained facts, where each memory is exactly ONE single statement, then format each as an object with these fields:

• "content" (required) is exactly ONE fact: a single statement of one thing (a subject plus one predicate: "X is Y", "X did Z", "X has W"). This rule is broken far more than any other, and almost always the same way: by writing a PROFILE, packing everything you know about a person, place, or project into one memory. NEVER do that. Facts that share a subject are still separate memories, ONE PER FACT: six things about the same person is SIX memories, not one. A memory states exactly ONE fact, and even a SHORT sentence must be split if it states two (see the split test below); a paragraph is never one memory. SPLIT TEST. Before storing each memory, try to break its content apart; if any piece can stand alone as its own fact, you MUST split there:

  • more than one sentence → one memory per sentence;

  • parts joined by "and" / "but" / a comma / a semicolon that each stand alone → one memory each ("Sam is a widower and has three daughters" = TWO facts, stored separately);

  • different KINDS of information bundled about someone (who they are + a job + a marriage + a health note + an anecdote) → one memory per item;

  • DENSE TECHNICAL or MEASURED data (test results, genotypes, lab values, metrics, specs, config values) → ONE result per memory. This is the most-missed case for domain data: "ALDH2 rs671 is normal and ADH1B is *1/*1; her CYP1A2 is A/A, a fast caffeine metabolizer" is TWO facts (alcohol metabolism, caffeine metabolism), and a run of readings/genotypes/counts is one memory EACH. A technically-coherent sentence is still not one fact, and density is not an excuse to bundle. Keep splitting until removing any remaining piece would make the fact false or meaningless. Only then is it atomic. Do NOT split these (each is genuinely ONE fact): a fact bundled with its own cause/qualifier ("Pat uses RustDesk BECAUSE AnyDesk added a timer"); a joint action by several subjects acting together ("Pat and Kim traveled to Rome"); the members of a single set ("the three team leads are Ann, Bo and Cal"). A list of DIFFERENT attributes is NOT a set, so split it. Each memory must also stand alone: explicit full names, never pronouns ("he"/"they"/"it") or vague references ("the project", "that place"); keep the original specifics (names, numbers, dates). WORKED EXAMPLE: this one paragraph becomes FOUR separate memories (four objects in memories, each with its own variants): "Maria Lopez is our CFO; she joined in 2019, came from Stripe, and has two kids." → "Maria Lopez is the company's CFO." · "Maria Lopez joined the company in 2019." · "Maria Lopez previously worked at Stripe." · "Maria Lopez has two children." SHORT sentences split too, and this is the most-missed case. "Robin Vane is a lawyer, born around 1991" is TWO memories: "Robin Vane is a lawyer." + "Robin Vane was born around 1991." A person's occupation, birth year, birthplace, employer, and marital status are each a SEPARATE fact, one memory apiece, never merged into a one-line description.

• "variants" (REQUIRED, 5-8 per fact; a store is REJECTED if any fact has fewer than 5 distinct phrasings) are alternative phrasings of the SAME fact. Variants are the main thing that makes a memory findable later, so generate a GENEROUS, DIVERSE set every time: 5 to 8, never just 1-2. For each fact, cover several of these angles:

  • synonyms / reworded ("Patrick can't digest lactose" / "Patrick is intolerant to dairy sugar")

  • the question forms the fact answers ("What is Patrick allergic to?", "Who is lactose intolerant?")

  • a different sentence structure or word order

  • a short, keyword-dense form ("Patrick Vane, lactose intolerance") Every variant MUST mean exactly the same fact (never add, drop, or change information) and should include the subject's name so it stands alone. Make them GENUINELY different wording, because padding with punctuation/spacing/casing tweaks ("retest", "retest.", "re-test") does NOT count (those collapse to one), so five near-identical strings are rejected just like two. A variant is a RESTATEMENT, never commentary: do NOT add a label, category, comparison, or characterisation the fact did not itself state ("star-of-stars topology", "X-style architecture", "has prior experience with Y", "the industry-standard approach"). If the fact does not say it, neither can the variant. Distinct phrasings only, and near-duplicates don't count toward the minimum.

• "subjects" is an ARRAY of the people the fact is about, lowercase (e.g. ["patrick vane"]). Use the person's FULL name ("patrick vane", never "patrick"). A FIRST NAME ALONE IS NOT AN IDENTIFIER: people share first names, so unless you are CERTAIN which person this is, STOP AND ASK THE USER before storing. Do not guess and do not store the bare first name. In particular, NEVER assume a bare first name means the same person as an existing subject that starts with it: if the user says "colin" and memory holds "colin murphy", that may be a DIFFERENT colin, and silently attaching this fact to the stored one MERGES two people. Ask which one. A wrong merge mixes two people's lives together and is painful to unpick later, whereas asking one short question costs nothing. A fact about SEVERAL people together (a shared event/relationship) lists each: ["patrick vane", "yu pan"]. Tag EVERY person the fact names or establishes, not just the main one or the connecting relative. A fact that NAMES a set of people ("The Garcias' three children are Ana, Ben and Cara"; "X's siblings are A, B and C"; "their two sons are Sam and Theo") must tag EACH named person so every one becomes findable: e.g. ["ana garcia", "ben garcia", "cara garcia"] plus the parents, NEVER just the parents or the one child emphasized. A fact NOT about a specific person (a product, project, place, org, concept) → empty array []. Never invent a subject. Subjects are matched by EXACT (case-insensitive) text at search time: "patrick" and "patrick vane" are treated as DIFFERENT people, and near-variants ("pat", "patrick v") never match, so reuse the EXACT spelling a person is already stored under. Subject drives ranking, so call amber_list_subjects to see who is already in memory and reuse that exact name.

• "topics" (up to 3) are broad, REUSABLE, lowercase category labels (e.g. "health", "work", "travel", "finances"). Not specific to this one fact ("likes strawberries" ✗), not meta ("memory about food" ✗). Topics are matched SEMANTICALLY at search time (a search for "work" also finds "career"/"job"), so exact wording matters less than for subjects, but still REUSE names that already exist rather than minting near-duplicates, to avoid clutter; call amber_list_topics to see what's in use and pick from it.

• "event_start" / "event_end" are ISO 8601 datetimes for WHEN the fact's event happened, or null. Resolve relative references ("last week", "yesterday") to actual dates using today's date. Point-in-time → set both equal; ongoing ("since March") → start only; range ("summer 2024") → both. null when the fact has no temporal reference.

• "metadata" (optional) is a flat object of exact-match filter values for later search.

SEARCH FIRST. THIS IS MANDATORY. This is the ONLY thing preventing duplicates: Amber does NOT dedupe, it stores exactly what you send, so storing a fact that is already in memory leaves TWO live copies of it forever and every later search returns both. Before storing ANY fact, call amber_search_memories for that fact's subject/topic, then decide per fact:

  • Genuinely new (search finds nothing equivalent) → store it.

  • Already stored and unchanged → SKIP it. Do not re-store it, not even reworded; a differently-phrased copy of the same fact is still a duplicate.

  • SUPERSEDES one you already stored (a status changed, a value was corrected, a previously-unknown answer got resolved, a plan reversed) → the OLD memory is now stale: DELETE it (amber_delete_memory) and store the corrected fact. Never leave both live. Piling up each new state as a fresh memory is the single biggest way this store rots: search then returns the stale and current versions side by side. Supersede, don't accumulate. (amber_update_memory only fixes a memory's subject, topics, or metadata, NOT its wording; use delete-then-store to change what a fact actually says.) DO NOT rely on your own memory of what you have already stored. If this is a NEW SESSION, or your context was summarized/compacted, you may have ALREADY saved these exact facts even though you don't recall doing so. Re-storing them from a fresh context is the #1 cause of accidental duplicates. When in any doubt, SEARCH; never assume a fact is unstored.

HARD LIMITS (a store is rejected, not truncated, if you exceed one, so size your batches to these): • memories per call: 500 · content: 4000 chars per fact • variants: 5 minimum DISTINCT (enforced), 50 maximum · each variant up to 4000 chars • subjects: 8 per fact, 100 chars each · topics: 3 per fact, 50 chars each • metadata: 4000 bytes total, flat scalars only Control characters (other than tab/newline/carriage-return) are rejected anywhere in these fields. They would corrupt the stored text.

Errors: invalid_input (one or more facts are malformed: too long, fewer than 5 distinct variants, control characters, a bad date, or metadata that is not flat scalars). NOTHING is stored when this happens, so fix and resend the whole call. The response names EVERY bad index at once rather than stopping at the first, so one round trip is enough to correct them all. queue_unavailable (the write queue is momentarily saturated) also stores NOTHING and is safe to retry in a few seconds -- it is reported BEFORE any memory is written, never after. idempotency_key_reused means the key you sent already names a store that held DIFFERENT facts. NOTHING was written, and the message names that original task. Either resend the ORIGINAL facts under that key to recover it, or use a FRESH key for these facts. Do not retry the same call unchanged: it will be refused again, by design, because absorbing it would discard the facts you just sent with no way to get them back.

Example (note the generous, varied variant sets, do the same): amber_store_memory({ "memories": [ { "content": "Patrick Vane is lactose intolerant.", "variants": ["Patrick Vane can't digest lactose", "Patrick Vane is intolerant to dairy", "What is Patrick Vane allergic to? Lactose.", "Who is lactose intolerant? Patrick Vane.", "Patrick Vane should avoid milk and dairy", "Patrick Vane, lactose/dairy intolerance"], "subjects": ["patrick vane"], "topics": ["health", "food"], "event_start": null, "event_end": null }, { "content": "Patrick Vane and Yu Pan traveled to Rome in June 2026.", "variants": ["Patrick Vane and Yu Pan visited Rome", "Patrick Vane and Yu Pan took a trip to Italy", "When did Patrick Vane go to Rome? June 2026.", "Who traveled to Rome in June 2026? Patrick Vane and Yu Pan.", "Patrick Vane and Yu Pan, Rome trip, June 2026"], "subjects": ["patrick vane", "yu pan"], "topics": ["travel"], "event_start": "2026-06-01T00:00:00Z", "event_end": "2026-06-30T23:59:59Z" } ] })

Inputs: memories (required), idempotency_key. Returns: status, message, task_id, deduplicated, +1 more

amber_update_memoryFix a memory's subject, tags, or metadataAInspect

Correct a stored memory after the fact. Use this when you notice -- e.g. while reviewing search results -- that a memory has the WRONG or MISSING subject (who it's about), a wrong/missing topic tag, or stale metadata. Does NOT change the fact's wording; to reword a fact, delete it and store the corrected version. Works on TRASHED memories too, deliberately: correcting a subject or tag while a memory sits in the trash keeps it coherent for a later restore -- the same reason amber_rename_subject relabels trashed records.

Pass memory_id plus only the fields you want to change:

  • subject: who the memory is about, e.g. "patrick" or "patrick's father". Fixes mis-attributed facts (e.g. a fact about the user's dad wrongly tagged as the user). It REPLACES every subject, so subject: "" removes them all.

  • rederive_subject: true to re-extract the subject from the memory's own content (use when it's clearly wrong but you don't know the right value). Ignored if subject is given.

  • add_topics / remove_topics: topic/category names to add or remove, e.g. ["health"].

  • add_subjects / remove_subjects: person name(s) to add or remove as co-subjects WITHOUT clobbering the others -- e.g. a fact naming two people that was tagged with only one: add_subjects: ["tjeerd spruijt"]. (Use subject to REPLACE the whole subject set instead.)

  • set_metadata: object of metadata fields to set or overwrite, e.g. { "importance": "high" }.

  • clear_metadata: metadata field names to remove, e.g. ["importance"].

Reuse existing names: subjects are matched by EXACT (case-insensitive) text -- call amber_list_subjects and reuse the stored spelling -- while topics are matched SEMANTICALLY -- call amber_list_topics.

Example -- a fact about the user's father is tagged as the user: amber_update_memory({ memory_id: "...", subject: "patrick's father" }). Returns the updated memory. Requires an active subscription.

Errors: not_found (no memory with that id on this account; a trashed memory is found and updated), invalid_input (a field has the wrong type, nothing to change was supplied, or the change would leave the memory over a store limit: 3 topics, 4000 bytes of metadata).

Inputs: memory_id (required), subject, add_topics, add_subjects, +5 more. Returns: memory

amber_upload_backupRestore a backup from a fileA
Idempotent
Inspect

Show the user a drag-and-drop panel for restoring a backup that is on THEIR COMPUTER. Call this with no arguments when someone wants to restore and the file is local -- they pick it, and it uploads straight to storage without passing through this conversation.

IF THE BACKUP IS ALREADY ONLINE (S3, R2, Backblaze, a presigned link) use amber_import_memories with the URL instead; that needs no upload at all and is the better path.

The prepare and finish actions are driven BY THE PANEL, not by you. Call this with no arguments and let the person use it; then poll amber_get_import_status for progress.

IF YOUR CLIENT CANNOT RENDER PANELS, tell them to open https://ambermem.com/restore instead. It is the same uploader as an ordinary web page, and it needs a key from amber_create_backup_key. Requires an active subscription.

Errors: invalid_params (finish called without a task_id), not_found (no upload with that id, or it belongs to another account), nothing_uploaded (finish called but nothing arrived at the upload link), invalid_archive (via amber_get_import_status, not from this call: what was uploaded is not a readable Amber backup; that task is marked failed, so start a new one), not_startable (the upload is no longer in a state that can begin, for example it already ran or already failed; ask for a fresh link and send the file again, which duplicates nothing because memories keep their ids).

Inputs: action, task_id. Returns: status, task_id, upload_url, restore_url, +1 more

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4.4/5.0

    Scored across 29 tools

    Disambiguation4/5

    Most tools target a clearly distinct operation, and the potentially confusable pairs (list vs search, active vs trash, export vs backup key, upload vs import from URL) are explicitly contrasted in the descriptions. The main residual friction is the overloaded word 'restore' (amber_restore_memory for un-deleting vs restoring a backup via upload_backup/import_memories) and the three near-identical status-polling tools, which an agent must map by task type rather than by name alone.

    Naming Consistency5/5

    Every tool uses the same amber_ prefix plus lowercase snake_case with a verb_noun shape (store_memory, delete_memory, list_subjects, get_import_status). No camelCase or style mixing anywhere, and the verb choice reliably signals read vs write (list/get/search vs store/update/delete/restore).

    Tool Count3/5

    29 tools is heavy for one server and spans several sub-domains beyond the core memory CRUD (subscription billing, backup keys, import/export plumbing, feedback, notification dismissal). Each tool does have a real job, but the surface is at the upper edge of what an agent can hold, and peripheral capabilities like backup-key rotation and feedback submission arguably belong in a separate administrative surface.

    Completeness4/5

    Coverage is unusually thorough: writes, reads, search, subject/topic hygiene, soft-delete and restore, trash browsing, account and subscription lifecycle, export/import and async status polling are all present. The notable gap is that deletion is only ever soft — there is no way to permanently purge a memory or empty the trash, so an agent cannot fully complete a 'delete this forever' request.

    Maintenance

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      D
      maintenance
      A template implementation of the Model Context Protocol server that integrates with Mem0 to provide AI agents with persistent memory capabilities for storing, retrieving, and searching memories using semantic search.
      MIT
    • A
      license
      Not graded
      quality
      Not graded
      maintenance
      Provides AI agents with persistent long-term memory capabilities using semantic search. Enables storing, retrieving, and searching memories through three core tools integrated with Mem0 and vector storage.
      MIT
    • F
      license
      Not graded
      quality
      D
      maintenance
      Provides AI agents with persistent, searchable memory that survives across conversations using semantic search, temporal versioning, and smart organization. Enables long-term context retention and cross-session continuity for AI assistants.
      14
      -