mem4dev documentation

mem4dev is the context layer for AI-assisted development. It records the decisions and activity of your projects, connects them to each other and to your code, and shares them with your team and your AI assistants (Claude Code, Claude Desktop, Cursor, VS Code or any MCP client) through a native MCP server or a REST API.

Contents:

This documentation is also available as raw Markdown (/docs/index.md). Spanish version: /docs/es/.

Connect over MCP

mem4dev exposes a public Model Context Protocol (MCP) server so an AI assistant can read the context of your projects and, if you allow it, write to it.

Add it to your client

Claude Code:

claude mcp add --transport http mem4dev https://app.mem4dev.com/mcp

Cursor (~/.cursor/mcp.json):

{ "mcpServers": { "mem4dev": { "url": "https://app.mem4dev.com/mcp" } } }

VS Code (.vscode/mcp.json):

{ "servers": { "mem4dev": { "type": "http", "url": "https://app.mem4dev.com/mcp" } } }

Claude Desktop and other clients: add a remote/custom connector with the same URL.

Authorize

The first time the client connects, the mem4dev consent screen opens in your browser (log in if needed). You choose:

  1. Access type: read-only (the default) or read and write.
  2. Scopes: all your scopes (including future ones) or only the ones you select.

You can revoke access at any time from your account. A client authorized as read-only that tries a write tool gets an explicit error telling it to authorize again with write access.

Tools

ToolAccessWhat it does
list_scopesreadLists your scopes (call it first to get the scope_id).
get_plan_usagereadYour plan, its limits and how much you have used (scopes, entries, interactions this month, attachments).
get_usage_guidereadRecommended instructions for using this MCP (cheap queries with compact, obsolete entries, relations, how to write entries). Call it first, once per conversation.
get_scope_contextreadThe context you wrote for the scope (who is who, rules, vocabulary), its query instructions, who you are in it and whether it is shared. Read it once per scope.
query_entriesreadNatural-language search, with optional tags, date range, text filter, relations (related_to), references (ref) and compact format; excludes obsolete entries unless you ask for them.
get_entryreadFull text, attachments, obsolete marks, relations and references of an entry (even if it is obsolete).
get_related_entriesreadThe entries related to a given one, following the relations up to 3 hops.
list_tagsreadCustom tags of a scope, with how many entries each one has.
get_attachment_download_urlreadTemporary download link (5 minutes) for an attachment.
add_entries_bulkwriteLogs up to 20 entries in one call, with their tags, relations and references.
update_entrywriteEdits the text, date, tags, relations and references of an entry, or marks it as obsolete (the previous version is kept).
link_entrieswriteRelates an existing entry to others in the same scope, or adds references to commits, pull requests or issues, without touching its text.
delete_entrywriteSends an entry to the trash (one per call).

Tools that touch entries take a scope_id; data from other scopes or other accounts is never returned. list_scopes includes the scopes other people shared with you (marked as shared): you write in them only if your permission allows it, and the limits of the scope owner's plan apply.

Every tool description ends with the catalog version (today 2026-10-22.2): use it to check which version your client received. If you see an older date, your client has the list cached; reconnect the server.

Files can only be attached from the web app, not through MCP or the API. Through MCP you can read and download existing attachments; deleting them is also web-only.

Deleting entries

delete_entry does not delete right away: the entry leaves the searches and stays 30 days in a trash that only the scope owner sees and can recover from the web app. It cannot be recovered through MCP. If the entry was the only replacement of other entries, those stay obsolete unless you send reactivate_obsolete: true; the response carries kept_obsolete or reactivated.

Obsolete entries

An entry stops being current when a newer one replaces it. The recommended way is the replaces relation (see Relations and references): the new entry makes the old one obsolete by itself, and removing the relation reactivates it. You can also mark it by hand with update_entry: obsolete: true and, if you know it, replaced_by with the id of the new entry (it must be a live entry in the same scope). You do not need to resend the text to mark it. It is never deleted: it stays in the history, get_entry always returns it, and marking it creates a new version, like any edit. add_entries_bulk also accepts obsolete and replaced_by per entry.

query_entries and get_related_entries exclude obsolete entries by default and answer omitted_obsolete (how many matched) so the AI knows history exists; with include_obsolete: true they include them. Every returned entry carries obsolete and replaced_by. The Ask chat in the web app also excludes them, with an «Include obsolete entries» checkbox to see them.

Cheaper searches with less noise

Besides question, tags, date_from, date_to, limit and offset, query_entries accepts:

The response reports total_candidates (the union of the semantic and keyword candidates, so it can exceed the cap), total_after_filter, omitted_obsolete, candidates_limit (the cap applied to each source) and candidates_truncated (true = the candidates above the minimum score filled that cap, so unevaluated entries may exist: raise candidates or narrow by dates or tags). has_more is true when there are more results after this page. With filter and no question, only the candidates most recent entries that meet tags and dates are evaluated, and total_matches counts those that meet the filter.

Context, authors and ranking

Every scope has a context written in the web app (who is who, the project, rules, vocabulary) and, if you want, query instructions. get_scope_context hands them over so any AI can use them, as the Ask tab does; it also says who you are in the scope (current_user) and whether it is shared. get_usage_guide and the connection instructions tell the AI to read both once, first.

A scope can be shared by several people. Every entry carries author (who wrote it), in full and compact format, so an AI can tell what Ana did from what Luis did.

With question, results come sorted by score (0 to 1), highest first, and on equal score the most recent first. The order does not depend on limit: the first N entries are the same with any limit, and offset reads further while has_more is true. The score mixes two signals, each normalized on its own scale: 65% semantic similarity and 35% word match (rare terms and title terms weigh more), plus a small recency weight; an entry with both signals never scores lower than one with a single signal of equal value. What matters is the order inside the response, not the absolute value.

MCP limits

Every tool has its own limit per hour and per account: query_entries 20; get_related_entries 60; add_entries_bulk, update_entry, delete_entry and link_entries 30 each. Besides, every MCP call counts as one interaction of your plan's month (like every API call and every question in Ask; what you do from the web app does not count).

Create an API key

API keys let scripts, CI jobs and your own tools use the REST API without logging in through the browser. For AI assistants, prefer MCP.

Steps

  1. Log in at https://app.mem4dev.com/ and open API keys (https://app.mem4dev.com/api-keys).
  2. Create a key and give it a name you will recognize (for example ci-notes).
  3. Choose which scopes it can access. Read access is always included in an assigned scope; write access is optional and set per scope.
  4. Copy the secret now. It looks like mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx and is shown only once.
  5. Revoke the key from the same page when you no longer need it.

Use it

Send it as a Bearer token:

Authorization: Bearer mk_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Base URL: https://app.mem4dev.com/api/v1

Endpoints

Method and pathPermissionWhat it does
GET /scopesreadLists the scopes your key can use.
GET /entriesreadLists entries by scope and date range (scope_id, date_from, date_to, limit). Every entry carries relations and refs.
POST /entries/searchreadNatural-language search (equivalent to query_entries).
GET /entries/relatedreadEntries related to a given one (equivalent to get_related_entries).
GET /entries/versionsreadEdit history of an entry.
GET /tagsreadTags of a scope, with their count.
GET /planreadYour plan, limits and usage.
POST /entries/bulkwriteLogs up to 20 entries, with tags, relations and references.
PUT or PATCH /entrieswriteEdits an entry: text, date, tags, obsolete, relations and references.
POST /entries/linkswriteRelates an entry to others or adds references, without touching its text (equivalent to link_entries).
DELETE /entrieswriteSends an entry to the trash (reactivate=1 reactivates the entries that were obsolete only because of it).

Permissions

Key configurationCan
Assigned scope, read-onlyThe read endpoints in the table above
Assigned scope, read and writeEverything above plus the write endpoints
Unassigned scope403 forbidden

A key only reaches the scopes that the account that created it has access to: its own and those other people shared with it (in the latter, writing depends on the permission you were given). If you lose access to a shared scope, the key loses it too.

Errors

Errors are JSON: { "error": { "code": "forbidden", "message": "..." } }

HTTPcodeMeaning
400invalid_requestA field is missing or has an invalid format.
401unauthorizedMissing, invalid or revoked key.
402plan_limitA limit of the plan of the account that owns the scope was reached (entries or interactions this month). Nothing is deleted: only creating more is blocked.
403forbiddenNo access (or no write access) to that scope.
404not_foundThe scope or the entry does not exist.
429rate_limitedLimit exceeded: 120 requests per hour, per key and endpoint.

Example with curl

Replace mk_live_... with your API key. Base URL: https://app.mem4dev.com/api/v1.

1. List the scopes your key can use

curl https://app.mem4dev.com/api/v1/scopes -H "Authorization: Bearer mk_live_..."
{ "ok": true, "scopes": [ { "scope_id": 1, "scope_name": "Work", "can_read": true, "can_write": true } ] }

2. Log an entry (needs write access)

curl -X POST https://app.mem4dev.com/api/v1/entries/bulk -H "Authorization: Bearer mk_live_..." -H "Content-Type: application/json" -d '{"scope_id": 1, "entries": [{"entry_text": "# Upload limit\n\nDecision: cap uploads at 50 MB.", "tags": ["adr"]}]}'

Up to 20 entries per call; each one is validated separately and the response reports saved_count, failed_count and a result per entry.

3. Log an entry that replaces another and points to a commit

curl -X POST https://app.mem4dev.com/api/v1/entries/bulk -H "Authorization: Bearer mk_live_..." -H "Content-Type: application/json" -d '{"scope_id": 1, "entries": [{"entry_text": "# New upload limit\n\nDecision: 100 MB.", "relations": [{"type": "replaces", "target": 4821}], "refs": [{"type": "commit", "value": "a1b2c3d", "repo": "mem4dev-app"}]}]}'

Entry 4821 becomes obsolete by itself and stops showing up in searches. If a relation or reference fails, the entry is saved anyway and the error goes in link_errors.

4. Search in natural language

curl -X POST https://app.mem4dev.com/api/v1/entries/search -H "Authorization: Bearer mk_live_..." -H "Content-Type: application/json" -d '{"scope_id": 1, "question": "what did we decide about file uploads?", "date_from": "2026-09-01"}'

Omit question to filter only by tags and dates. Results come 20 at a time (use offset to paginate). Obsolete entries are excluded unless you send include_obsolete: true.

5. Read by date range

curl "https://app.mem4dev.com/api/v1/entries?scope_id=1&date_from=2026-09-01&limit=50" -H "Authorization: Bearer mk_live_..."

6. Follow the relations of an entry

curl "https://app.mem4dev.com/api/v1/entries/related?scope_id=1&entry_id=4821&depth=2&include_obsolete=1" -H "Authorization: Bearer mk_live_..."

7. Relate an existing entry (needs write access)

curl -X POST https://app.mem4dev.com/api/v1/entries/links -H "Authorization: Bearer mk_live_..." -H "Content-Type: application/json" -d '{"scope_id": 1, "entry_id": 4830, "add_relations": [{"type": "implements", "target": 4821}], "add_refs": [{"type": "pull_request", "value": "128", "repo": "mem4dev-app"}]}'

8. Edit and delete (need write access)

curl -X PUT https://app.mem4dev.com/api/v1/entries -H "Authorization: Bearer mk_live_..." -H "Content-Type: application/json" -d '{"scope_id": 1, "entry_id": 4821, "entry_text": "Corrected text.", "add_tags": ["adr"]}'
curl -X DELETE "https://app.mem4dev.com/api/v1/entries?scope_id=1&entry_id=4821" -H "Authorization: Bearer mk_live_..."

Deleting sends the entry to the trash: the scope owner can recover it from the web app for 30 days.

9. Check your plan and usage

curl https://app.mem4dev.com/api/v1/plan -H "Authorization: Bearer mk_live_..."

Returns the plan, its limits, what you have used and what is left (scopes, entries, interactions this month and storage). If a limit is reached, writes and searches answer 402 plan_limit.

Also available: GET /entries/versions?scope_id=&entry_id= (edit history) and GET /tags?scope_id=.

Limits: 120 requests per hour per key and endpoint. See the public limits.

Scopes and tags

Scopes

A scope is a separate space inside your account: for example Work, Client A, Side project. Every scope has its own entries and its own AI context.

Shared scopes

The owner of a scope can share it with other people by email, with read-only or read-and-write permission. It is available on every plan.

Entries

An entry is free text (up to 5,000 characters) with an event_date (today in your time zone by default; it cannot be in the future). Edits keep a version history. For an AI to make the most of them, write each entry with a title (# ...) and a «Decision» section, so it can be understood on its own.

Tags

Custom tags organize entries inside a scope, beyond free text.

Relations and references

An entry can be related to others in the same scope and point to your code. Relations never cross scopes.

Relation types

TypeInverseMeaning
replacesreplaced_byThe new entry replaces the old one. The old one is obsolete while the relation exists.
caused_bycausesA decision or work session comes from an incident or problem.
implementsimplemented_byA work session carries out a decision.
refinesrefined_byAn entry adjusts part of another, which stays current.
continuescontinued_byAn entry is the next part of a long text split across several entries. Neither becomes obsolete.
relates_torelates_toFree, symmetric association.

Every relation is stored once; the inverse is computed when reading. You can use either name when creating it.

External references

An entry can point to: commit (a hash of 7 to 64 characters), pull_request, issue (number or key, like PROJ-123), branch and url. Every reference accepts optional repo and title. mem4dev only stores the pointer: it does not query your repository.

How to create them

How to read them

Limits and permissions

Public limits

ItemLimit
Entry text5,000 characters
Entries per bulk call20
Relations and references per entry50 relations, 20 references
Attachments10 MB per file, 5 per entry (upload from the web app only; MCP can read and download them)
Attachment typespdf, jpg, jpeg, png, webp, docx, xlsx, pptx, txt, md, zip, rar, skill
REST API120 requests per hour, per API key and endpoint (GET /scopes, GET /tags and GET /plan: no limit of their own)
MCPper tool and per hour: query_entries 20, get_related_entries 60, add_entries_bulk, update_entry, delete_entry and link_entries 30 each
Search results20 per page
InteractionsEvery API call, every MCP call and every question in Ask counts 1, against the plan of the data owner. What you do from the web app does not count.

Plans

PlanOwn scopesEntriesInteractions per monthAttachmentsPeople per shared scopeScopes from other accounts you can accept
Free11,0001,000100 MB11
Individual (from USD 7.99 a month)1010,00010,0001 GB1010

The Free plan needs no credit card and has no feature restrictions (MCP and API included); its limits are on volume. Individual has higher tiers within the same plan. Individual is available now; Teams is coming soon. Sharing scopes is available on every plan, and the limits are set by the scope owner's plan. At the entries limit only creating more is blocked; at the interactions limit the API, MCP and Ask pause until it renews. Nothing is ever deleted and the web app stays readable. Check your usage with the MCP tool get_plan_usage or GET /api/v1/plan.