MCP Tools Reference¶
nervapack-memory-mcp is an MCP server that exposes 17 tools for storing and recalling structured memory. Any MCP-compatible client — Claude Code, Cursor, or a custom agent — can use it to persist facts, decisions, and outcomes across sessions.
Primary use case: conversation context extender
Call memory_recall("project context") at the start of every new chat. Get a complete project briefing — 30 days of decisions and conventions — in under 200 tokens. No more re-pasting architecture docs. See the AI Coding Agent guide for the full session workflow.
Setup¶
1. Install
2. Initialise the store
3. Register in .mcp.json
Add alongside the knowledge-graph server:
{
"mcpServers": {
"nervapack": {
"command": "nervapack-mcp",
"description": "NervaPack knowledge graph — query_codebase, graph_status, list_entities"
},
"nervapack-memory": {
"command": "nervapack-memory-mcp",
"description": "NervaPack agent memory — store, recall, and reason over facts across sessions"
}
}
}
4. Reload your editor — both servers appear automatically.
Tool Reference¶
memory_store¶
Persist a memory node and link it to entities.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
content |
string | Yes | The assertion, decision, or fact to store |
kind |
string | Yes | One of: fact, decision, action, outcome, procedure, preference |
entities |
list[string] | No | Entity names to link via ABOUT edges. Created if not found. |
confidence |
float | No | 0.0–1.0. Default 1.0 |
valid_from |
string | No | ISO-8601 timestamp when this became true. Default: now |
supersedes |
string | No | Node ID to supersede (closes its valid_until, adds SUPERSEDES edge) |
session_id |
string | No | Attach to a specific session. Default: auto-created session |
rationale |
string | No | Why this decision was made. Surfaced by memory_why. |
alternatives_rejected |
list[string] | No | Options that were considered but dropped. Surfaced by memory_why. |
namespace |
string | No | Switch active namespace before writing (resets session). Default: active namespace |
Returns:
Examples:
# Store a decision with rationale — surfaces in memory_why
memory_store(
"Chose JWT over session cookies for auth_service — stateless horizontal scaling",
kind="decision",
entities=["auth_service"],
confidence=0.9,
rationale="Stateless tokens enable horizontal scaling without a shared session store.",
alternatives_rejected=["server-side sessions", "PASETO"],
)
# Store a fact with temporal anchor
memory_store(
"auth_service issues 15-minute access tokens with rotating refresh tokens",
kind="fact",
entities=["auth_service"],
valid_from="2026-07-01T00:00:00",
)
# Store a team convention
memory_store(
"All new services must expose /health and /metrics endpoints",
kind="preference",
)
# Supersede an old decision
memory_store(
"Switched auth_service from JWT to Paseto v4 for stronger type safety",
kind="decision",
entities=["auth_service"],
supersedes="d_0019f2...",
)
memory_recall¶
Retrieve the most relevant memories for a query, packed into a token budget.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | Yes | Natural language search phrase |
budget_tokens |
int | No | Maximum tokens in result. Default 500 |
kinds |
list[string] | No | Filter to specific node kinds |
as_of |
string | No | ISO-8601 timestamp for point-in-time recall |
hops |
int | No | Graph expansion depth. Default 1, max 2 |
min_confidence |
float | No | Minimum confidence threshold (0.0–1.0). Default 0.0 (all nodes) |
namespace |
string | No | Read from a specific namespace without switching the active one |
Returns: Markdown string, always ≤ budget_tokens.
Pipeline:
- FTS5 BM25 search (tries exact → prefix → OR variants for partial matches)
- Graph expansion: neighbours inherit 0.6× parent relevance per hop
- Temporal mask: exclude superseded and tombstoned nodes
- Scoring:
relevance × recency × frequency × connectivity - Budget packing: greedy fill to 90% budget, 10% reserved for provenance
Examples:
# Context extender — call this at the start of every session
memory_recall("project context", budget_tokens=400)
# Specific topic recall
memory_recall("why JWT for auth")
# Budget-limited to 200 tokens
memory_recall("deployment procedure", budget_tokens=200)
# Only facts, point-in-time
memory_recall("auth_service", kinds=["fact"], as_of="2026-01-15T00:00:00")
# 2-hop expansion to pull in connected context
memory_recall("payment flow", hops=2)
# Only high-confidence nodes
memory_recall("auth decisions", min_confidence=0.8)
Output:
## Memory recall: "why JWT for auth" (as of 2026-07-03 · 3 items · 171/500 tokens)
### Decisions
- [d_0019f2...] 2026-07-03 · conf 0.90 — Chose JWT over session cookies for auth_service
### Facts
- [f_0019f2...] 2026-07-03 · conf 1.00 — auth_service issues 15-minute access tokens
### Entities
- [e_0019f2...] 2026-07-03 · conf 1.00 — auth_service
### Provenance
d_0019f2... ← session s_0019f2... · f_0019f2... ← session s_0019f2...
memory_about¶
Entity dossier: all currently valid nodes linked to one entity, newest first.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
entity |
string | Yes | Entity name or ID. Case-insensitive, alias-aware. |
budget_tokens |
int | No | Default 500 |
Returns: Markdown block (same format as memory_recall).
Example:
memory_about("auth_service")
memory_about("AuthService") # same result — alias-normalised
memory_about("e_0019f2...") # by node ID
memory_why¶
Explain a decision: content, rationale, rejected alternatives, caused outcomes, and supersession chain.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
decision_ref |
string | Yes | Node ID (e.g. d_0019f2...) or a search phrase (best FTS match among decision nodes) |
Returns: Markdown string.
Example:
memory_why("d_0019f2...") # by ID
memory_why("JWT auth decision") # by phrase — FTS best match among decisions
Output:
## Decision: d_0019f2...
**Chose JWT over session cookies for auth_service**
Date: 2026-07-03T10:00:00+00:00 · Confidence: 0.90
**Rationale:** JWT is stateless and enables horizontal scaling without shared session store.
**Rejected alternatives:** server-side sessions, PASETO
**Outcomes:**
- [o_0019f3...] Auth service latency dropped 12ms after removing session DB calls
**Supersedes:**
- [d_0019f1...] Chose session cookies for auth_service
memory_timeline¶
Chronological trace of all memories matching a topic, including superseded nodes.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
topic |
string | Yes | Search phrase |
since |
string | No | ISO-8601 lower bound on recorded_at |
Returns: Markdown timeline, oldest first.
Example:
Output:
## Memory timeline: 'auth_service'
- [d_0019f1...] 2026-01-01 · conf 1.00 [superseded by d_0019f2...] — Chose session cookies for auth_service
- [d_0019f2...] 2026-07-03 · conf 0.90 — Chose JWT over session cookies for auth_service
memory_end_session¶
Close the current session and store an outcome summary.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
summary |
string | Yes | What was accomplished or decided in this session |
Returns:
What it does:
- Sets
valid_until = nowon the current session node. - Creates an
outcomenode with the summary text, linked viaOCCURRED_IN. - Queues a consolidation job (processed later via
nervapack-memory consolidate). - Resets the in-process session so the next tool call opens a fresh one.
Example:
memory_end_session(
"Implemented JWT auth for auth_service; chose refresh-token rotation over opaque tokens."
)
memory_forget¶
Tombstone (soft-delete) or hard-purge nodes.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
node_id |
string | No | Specific node to forget |
entity |
string | No | Forget all nodes linked to this entity via ABOUT edges |
before |
string | No | Forget all nodes recorded before this ISO-8601 timestamp |
purge |
bool | No | True = hard-delete (irreversible). Default False |
At least one of node_id, entity, or before must be provided. Multiple selectors are combined with OR.
Returns:
Tombstone vs purge:
| Tombstone | Purge | |
|---|---|---|
| Row deleted | No | Yes |
| FTS entry removed | No | Yes (DELETE trigger) |
| Visible in timeline | Yes | No |
| Reversible | Yes (update tombstoned=0) |
No |
| Sanctioned use | Routine forgetting | GDPR / hard removal |
Examples:
# Soft-forget a node
memory_forget(node_id="f_0019f2...")
# Soft-forget everything about an entity
memory_forget(entity="old_payment_service")
# Forget all nodes before a date
memory_forget(before="2026-01-01T00:00:00")
# Hard-purge a specific node (irreversible)
memory_forget(node_id="f_0019f2...", purge=True)
memory_verify¶
Confirm or refute a memory node, updating its confidence.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
node_id |
string | Yes | Node to verify |
status |
string | Yes | "confirm" or "refute" |
Semantics:
| Status | Effect |
|---|---|
confirm |
confidence = min(1.0, confidence + 0.1) |
refute |
confidence = confidence × 0.5, valid_until = now (closes the node) |
Returns:
Example:
# Agent tests a fact and it holds
memory_verify("f_0019f2...", "confirm")
# Agent discovers a fact is wrong — close it
memory_verify("f_0019f2...", "refute")
memory_stats¶
Summary statistics for the memory store.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
namespace |
string | No | Read stats for a specific namespace without switching the active one |
Returns:
{
"kind_counts": {"fact": 14, "decision": 5, "entity": 3, "session": 4, "outcome": 4},
"db_size_bytes": 49152,
"top_entities": [
{"id": "e_0019f2...", "content": "auth_service", "degree": 6},
{"id": "e_0019f3...", "content": "payment_service", "degree": 2}
],
"namespaces": ["default"]
}
Example:
memory_start_session¶
Explicitly open a named session and return its ID. Use this instead of letting sessions be auto-created, so the sessions list is readable.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable task name (e.g. "Debugging payment flow") |
namespace |
string | No | Switch active namespace before opening session (resets any existing session) |
Returns:
If a session is already open, returns "created": false and the existing session ID.
Example:
memory_list_sessions¶
List all sessions, newest first.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
int | No | Maximum sessions to return. Default 50 |
Returns: List of session objects with id, content, recorded_at, node_count, valid_until, tombstoned.
memory_clear_session¶
Delete a session and every node that belongs to it.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
session_id |
string | Yes | Session ID to delete |
purge |
bool | No | True = hard-delete (irreversible). Default False (tombstone) |
Returns:
memory_for_code¶
Return memories that are linked to a source file via TOUCHES edges.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
file_path |
string | Yes | Relative path to source file (e.g. src/auth/jwt.py) |
line |
int | No | Line number — narrows results to functions/classes that contain this line |
Returns: Markdown string listing all memory nodes that touch the file.
Example:
# All memories about a file
memory_for_code("src/nervapack/memory/store.py")
# Memories about the specific function at line 172
memory_for_code("src/nervapack/memory/store.py", line=172)
Requires TOUCHES edges
TOUCHES edges are created automatically by memory_store when entity names match code graph nodes. Build the code graph first with nervapack build.
memory_to_code¶
Return code-graph locations that a memory node TOUCHES.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
memory_id |
string | Yes | Node ID (e.g. d_0019f2...) |
Returns: List of {graph_node_id, file_path, start_line, end_line, code_type} dicts. Empty list if no TOUCHES edges.
Example:
memory_to_code("d_0019f2...")
# Returns: [{"graph_node_id": "function:src/auth.py:verify_token:42",
# "file_path": "src/auth.py", "start_line": 42, "end_line": 61,
# "code_type": "function"}]
memory_import¶
Bulk-import memory nodes from a list of dicts. Use this to seed memory from existing notes, architecture decisions, or export files.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
nodes |
list[dict] | Yes | Array of node specs. Each must have content and kind. |
Node spec fields:
| Field | Required | Description |
|---|---|---|
content |
Yes | The fact, decision, or note to store |
kind |
Yes | One of the 8 valid kinds |
entities |
No | Entity names to link via ABOUT edges |
confidence |
No | 0.0–1.0, default 1.0 |
valid_from |
No | ISO-8601 timestamp |
rationale |
No | Why — surfaces in memory_why |
alternatives_rejected |
No | Dropped options — surfaces in memory_why |
session_id |
No | Attach to a specific session |
Returns:
{
"imported": 3,
"node_ids": ["d_...", "f_...", "pr_..."],
"created_entity_ids": ["e_..."],
"errors": []
}
Examples:
# Import decisions from a design doc
memory_import([
{"content": "Use PostgreSQL for all transactional data", "kind": "decision",
"entities": ["postgres"], "confidence": 1.0,
"rationale": "ACID compliance required for payment flows"},
{"content": "All APIs must return ISO-8601 timestamps in UTC", "kind": "preference"},
{"content": "Rate limiting: 1000 req/min per API key", "kind": "fact",
"entities": ["api_gateway"]},
])
Also accepts the full export format {"nodes": [...], "edges": [...]} from nervapack-memory export — only nodes are imported; edges are rebuilt through entity resolution.
memory_switch_namespace¶
Switch the active namespace for this server process. All subsequent writes and reads will operate in the new namespace until switched again.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
namespace |
string | Yes | Namespace to activate. Use "default" to return to the default namespace. |
Returns:
What it does:
- Sets the active namespace on the store.
- Resets the in-process session so the next write opens a fresh session in the new namespace.
Examples:
# Isolate a second project's memory in one DB
memory_switch_namespace("project_b")
memory_recall("project context") # reads from project_b only
# Return to default
memory_switch_namespace("default")
When to use namespaces
Use namespaces when one agent (or one DB) serves multiple projects. Each namespace is fully isolated — memory_recall in namespace A never sees nodes from namespace B. All namespaces share the same SQLite file; memory_stats() always reports all namespaces.
memory_verify_staleness¶
Scan all TOUCHES edges and flag memories whose source file has been modified since the memory was stored.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
queue |
bool | No | Write stale/missing nodes to mem_review_queue for review. Default True |
Returns:
{
"checked": 12,
"stale": 3,
"missing": 1,
"clean": 8,
"stale_nodes": [
{"node_id": "d_0019f2...", "file_path": "src/auth/jwt.py",
"memory_date": "2026-06-01T10:00:00+00:00",
"file_mtime": "2026-07-01T15:30:00+00:00"}
],
"missing_nodes": [
{"node_id": "f_0019f3...", "file_path": "src/old_service.py"}
],
"queued": true
}
Staleness definition: A TOUCHES edge is stale when file_path's mtime is later than the memory node's recorded_at. A deleted file is reported as missing.
What it does NOT do: Tombstone nodes automatically. Stale nodes are queued for human review — you decide whether to update or supersede them. This preserves the supersede-never-delete guarantee.
Path resolution: file_path in TOUCHES edges is repo-relative. The tool resolves it relative to the .nervapack/ parent directory (the repo root). It cannot resolve paths when using the home-directory fallback DB (~/.nervapack/memory.db).
Known limitation: git clone, git checkout, or git pull resets file mtimes. A fresh clone will flag all touched files as stale even if the code hasn't changed. Treat staleness reports as hints, not certainties.
Example:
# Find stale memories and queue them for review
memory_verify_staleness()
# Just check without queuing
memory_verify_staleness(queue=False)
Recommended Agent Workflow¶
Session start
├─ memory_start_session("Task name") # name the session
├─ memory_recall("project context", budget_tokens=400) # load all prior context
└─ memory_recall("specific topic", budget_tokens=200) # load topic-specific context
│ ... agent works ...
├─ memory_store("decision made", kind="decision",
│ entities=["service_name"],
│ rationale="...", alternatives_rejected=["..."])
├─ memory_store("fact discovered", kind="fact", entities=["component"])
├─ memory_verify("f_0019f2...", "confirm") # confirm a prior fact holds
│
└─ memory_end_session("Summary of what was done") # close session
When to call each tool:
| Tool | When |
|---|---|
memory_start_session |
First thing — name the session for the task |
memory_recall |
At session start — load project context and topic context |
memory_store |
Any decision, fact, convention, or outcome worth preserving |
memory_import |
Seeding memory from notes, ADRs, or export files (one-time or periodic) |
memory_about |
When asked about a specific service or component |
memory_why |
When asked to justify or explain a past decision |
memory_timeline |
When the user asks about the history of something |
memory_for_code |
When asked what decisions are related to a file or function |
memory_to_code |
When asked to navigate from a memory to its source location |
memory_verify |
When a prior fact is confirmed or contradicted by new evidence |
memory_forget |
When explicitly asked to forget something |
memory_end_session |
When a task or conversation ends |
memory_list_sessions |
To audit or review past sessions |
memory_clear_session |
To delete a session and all its nodes |
memory_stats |
Diagnostic/administrative use |
memory_switch_namespace |
When switching between isolated projects in one DB |
memory_verify_staleness |
Periodically — check whether TOUCHES edges are still current |
Running the Server Directly¶
# stdio (default, for MCP clients)
nervapack-memory-mcp
# Custom database
NERVAPACK_MEMORY_DB=/path/to/memory.db nervapack-memory-mcp
Cross-Process Demo¶
Verify that session A's memory is recalled by session B in a separate process:
# Session A — store
NERVAPACK_MEMORY_DB=/tmp/demo.db python examples/seed_demo.py session_a
# Session B — recall (fresh process)
NERVAPACK_MEMORY_DB=/tmp/demo.db python examples/seed_demo.py session_b
Expected output from session B:
## Memory recall: "why JWT for auth" (as of 2026-07-03 · 3 items · 171/500 tokens)
### Decisions
- [d_...] 2026-07-03 · conf 0.90 — Chose JWT over session cookies for auth_service
### Facts
- [f_...] 2026-07-03 · conf 1.00 — auth_service issues 15-minute access tokens with rotating refresh tokens
### Entities
- [e_...] 2026-07-03 · conf 1.00 — auth_service
Token count: 171/500 ✓
See Also¶
- AI Coding Agent guide — full session workflow, CLAUDE.md template, TOUCHES bridge
- Concepts & data model — bi-temporal schema, recall pipeline, scoring formula
- CLI reference —
init,stats,search,show,forget,export,consolidate,import - Knowledge Graph MCP Server — code graph tools:
query_codebase,graph_status,list_entities