An MCP server that provides persistent memory storage for AI agents. Stores facts, decisions, progress notes, and journal entries across sessions using SQLite with full-text search.
This memory management MCP server demonstrates strong domain-specific design with well-composed tools and comprehensive descriptions. All 5 tools have clear, action-oriented names (memory_*) and detailed descriptions that guide LLM behavior explicitly. Input schemas are present and mostly well-structured with typed fields and descriptions. However, there are notable gaps in output schema documentation, error handling guidance, and parameter validation details. The descriptions are longer than production baselines (200-300 chars vs typical 194) but appropriate for an onboarding-focused domain. No security vulnerabilities detected (no credentials exposed). The main quality gaps are: (1) output schemas for all tools are undocumented, forcing LLMs to guess response structure; (2) error recovery guidance is missing; (3) some parameter constraints lack explicit validation rules in descriptions.
Call this FIRST before responding to any coding task, bug fix, feature request, or question about the project. Without it you have no memory of previous sessions and will repeat work already done or miss known constraints. WHEN TO CALL (call immediately, do not wait for user to ask): - User says "help me with", "fix", "implement", "add", "why does", "how does", or starts any work - User says "continue", "where were we", "what's the status", "last time we..." - Any unfamiliar codebase or project name appears in the conversation COST OF SKIPPING: You lose all prior context — previous decisions, known bugs, in-progress work. RETURNS: Recent activity (last 24h by default), top entities, DB path. EXAMPLE: memory_context({}) — call with no arguments to load default context.
Correct wrong information: retract a single bad observation, or soft-delete a whole entity. Soft-delete is reversible; use permanent:true only when sure. WHEN TO CALL: When you stored something incorrect, or a project/entity is no longer relevant. EXAMPLES: - Remove one wrong fact: memory_forget({name: "auth-service", observation: "Uses JWT with 1h expiry"}) - Soft-delete entity: memory_forget({name: "old-feature"})
Connect two entities with a named relationship. Use this to map dependencies, ownership, and associations between things you have stored. WHEN TO CALL: When you identify that two stored entities are related — a bug fixed by a commit, a module depending on another, a decision driving a design. RELATION TYPES: uses, fixes, depends_on, implements, owns, blocks, related_to — use active-voice verbs. EXAMPLES: - memory_link({from: "payment-service", to: "Redis", relation: "uses"}) - memory_link({from: "fix/race-condition", to: "refund-handler", relation: "fixes"})
Output schemas are completely undocumented for all tools. LLMs cannot plan follow-up actions or extract response fields without knowing what structure is returned. This violates the core pattern of documented return types.
No error recovery guidance. Tool descriptions state WHEN to call tools but do not explain what the LLM should do if a call fails (e.g., what if memory_store fails? Should the LLM retry, ask the user, or abort?). Errors lack actionable next steps.
Parameter validation constraints are implicit or missing. For example, memory_search's 'sort' parameter has an enum constraint in the schema, but memory_context's 'since' parameter lacks explicit format/pattern validation (accepts '2h|24h|7d|ISO date' but no regex or enum in schema). LLMs cannot validate input locally.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | C | 62 | 2026-07-28+ | v2 |
Search stored memory by keyword, exact name, or browse all entities. Also reads journal logs. WHEN TO CALL: When you need to recall something specific — a past decision, a bug fix, a person's role. VS memory_context: memory_context gives you recent activity; memory_search finds specific things by keyword. EXAMPLES: - Keyword search: memory_search({query: "redis connection"}) - Exact lookup: memory_search({name: "auth-service"}) - List all: memory_search({query: ""}) - Read journal: memory_search({journal: true, since: "7d"})
Store facts, decisions, and progress notes so you remember them in future sessions. Also used to write journal entries at session end. Store proactively — do not wait to be asked. WHEN TO CALL: - Immediately after completing a task, fixing a bug, or making an architectural decision — store it before moving on - When you discover something important: a non-obvious code pattern, a constraint, a gotcha - When the user says "done", "thanks", "that's all", "good", or the conversation is wrapping up — write a journal entry - Before ending a session: journal entry with what was completed, what is in progress, any blockers ENTITY TYPES: project, module, bug, decision, person, concept, system — use whatever fits. JOURNAL: Use the journal field (not entities) for session logs. Journal entries are append-only and never deduplicated. EXAMPLES: - Store a fact: memory_store({entities: [{name: "auth-service", entityType: "module", observations: ["Uses JWT with 1h expiry", "Refresh token stored in Redis"]}]}) - End-of-session log: memory_store({journal: "Completed: JWT refresh flow. In progress: rate limiting. Blocker: Redis connection pooling under load."})
memory_store parameters 'entities' and 'journal' are marked 'mutually exclusive' in the description but this constraint is not enforced in the schema (no oneOf, anyOf, or allOf construct). The description text alone cannot enforce mutual exclusivity, LLMs may pass both, causing ambiguous behavior.
Descriptions exceed production baselines (250+ chars per tool vs typical 194 avg). While appropriate for onboarding, they use tokens inefficiently. Examples ('memory_context({})') embedded in descriptions risk LLM reuse of literal syntax. Separate examples from constraints.