memdb
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@memdbstore a memory that I learned TypeScript today"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
memdb
A SQLite-backed MCP memory server with local workspace storage, full-text search (FTS5), and knowledge graph capabilities for AI assistants.
Overview
memdb is a Model Context Protocol (MCP) server that provides persistent memory storage for AI assistants. It uses Node.js's native node:sqlite module to store memories locally with SHA-256 content deduplication, FTS5 full-text search, and a knowledge graph of typed relationships between memories. Communication happens over stdio transport.
Related MCP server: agent-memory
Key Features
Persistent local storage — SQLite database stored in the workspace (
.memdb/memory.dbby default) with WAL mode for performanceFull-text search — FTS5-powered content and tag search with BM25 relevance scoring and recency boosting
Knowledge graph — Directed, typed relationships between memories with recursive graph traversal (
recall)SHA-256 deduplication — Content-addressed storage prevents duplicate memories automatically
Batch operations — Store or delete up to 50 memories in a single call with partial success support
Memory classification — Categorize memories by type (general, fact, plan, decision, reflection, lesson, error, gradient) and importance (0–10)
Protocol safety — Custom stdio transport that rejects JSON-RPC batch requests, protocol version guard, and tool execution timeouts
Tech Stack
Component | Technology |
Runtime | Node.js ≥ 24 |
Language | TypeScript 5.9 (strict mode) |
MCP SDK |
|
Database | SQLite via native |
Validation | Zod v4 |
Transport | stdio |
Package Manager | npm |
Architecture
┌─────────────────────────────────────────────┐
│ Client │
└──────────────────┬──────────────────────────┘
│ stdio (JSON-RPC)
┌──────────────────▼──────────────────────────┐
│ 1. BatchRejectingStdioServerTransport │ ← Rejects JSON-RPC batch arrays
│ 2. ProtocolVersionGuardTransport │ ← Validates protocol version
│ 3. McpServer (MCP SDK) │ ← Tool/resource registration
│ 4. Tool handlers with timeout + error wrap │ ← Zod validation, abort signals
│ 5. Core layer (db, search, relationships) │ ← SQLite + FTS5 + knowledge graph
└─────────────────────────────────────────────┘Repository Structure
memdb/
├── src/
│ ├── core/ # Database and business logic
│ │ ├── db.ts # SQLite connection, schema, WAL, statement cache
│ │ ├── memory-read.ts # Get, delete, stats operations
│ │ ├── memory-write.ts # Store, update with SHA-256 deduplication
│ │ ├── relationships.ts # Knowledge graph edge operations
│ │ ├── search.ts # FTS5 search and graph traversal (recall)
│ │ └── abort.ts # Abort signal utilities
│ ├── index.ts # Server entrypoint, stdio transport, shutdown
│ ├── tools.ts # MCP tool registration with timeout handling
│ ├── schemas.ts # Zod schemas for all 12 tools
│ ├── types.ts # TypeScript interfaces
│ ├── config.ts # Environment variable configuration
│ ├── logger.ts # Logging (console.error, never stdout)
│ ├── stdio-transport.ts # Custom stdio transport with batch rejection
│ ├── protocol-version-guard.ts # Protocol version validation
│ ├── instructions.md # User-facing instructions (MCP resource)
│ ├── async-context.ts # AsyncLocalStorage for tool context
│ └── error-utils.ts # Error message extraction
├── tests/ # node:test runner tests
├── scripts/ # Build & task automation
├── assets/ # Logo/icon assets
├── .github/workflows/ # CI/CD (npm publish on release)
├── package.json
├── tsconfig.json
└── eslint.config.mjsRequirements
Node.js ≥ 24 — required for the native
node:sqlitemodule
Quickstart
The fastest way to start using memdb is via npx:
npx -y @j0hanz/memdb@latestAdd to your MCP client configuration:
{
"mcpServers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"]
}
}
}Installation
NPX (recommended)
No installation needed — runs the latest version directly:
npx -y @j0hanz/memdb@latestGlobal Install
npm install -g @j0hanz/memdb
memdbFrom Source
git clone https://github.com/j0hanz/memdb-mcp-server.git
cd memdb-mcp-server
npm install
npm run build
npm startConfiguration
Environment Variables
Variable | Type | Default | Description |
|
|
| Path to the SQLite database file. Set to |
|
|
| Logging verbosity level |
|
|
| Tool execution timeout in milliseconds (non-negative integer) |
Environment variables can be set via a .env file when using npm run dev:run, or passed directly to the process.
Database Location
By default, memdb creates the database at .memdb/memory.db relative to the working directory. The directory is created automatically if it doesn't exist.
Usage
memdb communicates exclusively over stdio transport. Start the server and connect via any MCP-compatible client:
# Direct
node dist/index.js
# Via npx
npx -y @j0hanz/memdb@latest
# With custom database path
MEMDB_PATH=/path/to/my.db npx -y @j0hanz/memdb@latestMCP Surface
Tools
memdb exposes 12 tools organized into memory management, search, knowledge graph, and diagnostics.
store_memory
Store a new memory with tags. Idempotent — storing the same content returns the existing hash.
Parameter | Type | Required | Default | Description |
|
| Yes | — | The content of the memory (1–100,000 chars) |
|
| Yes | — | Tags to categorize the memory (1–100 tags, no whitespace, max 50 chars each) |
|
| No |
| Priority level 0–10 (0=lowest, 10=critical). Higher importance memories surface first in search. |
|
| No |
| Category: |
Returns:
{
"ok": true,
"result": {
"id": 1,
"hash": "a1b2c3d4e5f6...",
"isNew": true
}
}store_memories
Store multiple memories in a single batch operation (1–50 items). Supports partial success.
Parameter | Type | Required | Default | Description |
|
| Yes | — | Array of 1–50 memory objects, each with |
Returns:
{
"ok": true,
"result": {
"results": [
{ "ok": true, "index": 0, "hash": "a1b2...", "isNew": true },
{ "ok": false, "index": 1, "error": "Tag must not contain whitespace" }
],
"succeeded": 1,
"failed": 1
}
}get_memory
Retrieve a single memory by its SHA-256 hash.
Parameter | Type | Required | Default | Description |
|
| Yes | — | SHA-256 hash of the memory (64 hex chars) |
Returns:
{
"ok": true,
"result": {
"id": 1,
"content": "TypeScript uses structural typing",
"summary": null,
"tags": ["typescript", "types"],
"importance": 5,
"memory_type": "fact",
"created_at": "2025-01-15 10:30:00",
"accessed_at": "2025-01-15 10:30:00",
"hash": "a1b2c3d4..."
}
}update_memory
Update memory content. Returns the new hash since content changes affect the hash. Idempotent.
Parameter | Type | Required | Default | Description |
|
| Yes | — | Hash of the memory to update |
|
| Yes | — | New content for the memory (1–100,000 chars) |
|
| No | — | Replace tags (max 100 tags, each max 50 chars) |
Returns:
{
"ok": true,
"result": {
"updated": true,
"oldHash": "a1b2c3d4...",
"newHash": "e5f6g7h8..."
}
}delete_memory
Delete a single memory by hash. Destructive operation.
Parameter | Type | Required | Default | Description |
|
| Yes | — | SHA-256 hash of the memory (64 hex chars) |
Returns:
{ "ok": true, "result": { "deleted": true } }delete_memories
Delete multiple memories by hash in a single batch operation (1–50 hashes). Supports partial success. Destructive.
Parameter | Type | Required | Default | Description |
|
| Yes | — | Array of 1–50 SHA-256 hashes to delete |
Returns:
{
"ok": true,
"result": {
"results": [
{ "hash": "a1b2...", "deleted": true },
{ "hash": "c3d4...", "deleted": false, "error": "Memory not found" }
],
"succeeded": 1,
"failed": 1
}
}search_memories
Search memories by content and tags using FTS5 full-text search with BM25 relevance scoring and recency boosting. Read-only.
Parameter | Type | Required | Default | Description |
|
| Yes | — | Search query (1–1,000 chars, searches content and tags) |
Returns:
{
"ok": true,
"result": [
{
"id": 1,
"content": "TypeScript uses structural typing",
"tags": ["typescript", "types"],
"importance": 5,
"memory_type": "fact",
"relevance": 0.85,
"hash": "a1b2c3d4...",
"created_at": "2025-01-15 10:30:00",
"accessed_at": "2025-01-15 10:30:00"
}
]
}recall
Search for memories and traverse relationships to return a connected graph cluster. Use for deeper context retrieval that follows knowledge graph connections. Read-only.
Parameter | Type | Required | Default | Description |
|
| Yes | — | Search query to find initial memories (1–1,000 chars) |
|
| No |
| How many relationship hops to follow (0–3). 0 = search only, no graph traversal. |
Returns:
{
"ok": true,
"result": {
"memories": [{ "id": 1, "content": "...", "relevance": 0.9, "...": "..." }],
"relationships": [
{
"id": 1,
"from_hash": "a1b2...",
"to_hash": "c3d4...",
"relation_type": "related_to",
"created_at": "2025-01-15 10:30:00"
}
],
"depth": 1
}
}create_relationship
Link two memories with a typed, directed relationship. Idempotent — creating the same relationship returns the existing ID.
Parameter | Type | Required | Default | Description |
|
| Yes | — | SHA-256 hash of the source memory |
|
| Yes | — | SHA-256 hash of the target memory |
|
| Yes | — | Type of relationship (e.g., |
Returns:
{ "ok": true, "result": { "id": 1, "isNew": true } }get_relationships
Get all relationships for a memory. Read-only.
Parameter | Type | Required | Default | Description |
|
| Yes | — | SHA-256 hash of the memory |
|
| No |
| Direction filter: |
Returns:
{
"ok": true,
"result": [
{
"id": 1,
"from_hash": "a1b2...",
"to_hash": "c3d4...",
"relation_type": "depends_on",
"created_at": "2025-01-15 10:30:00"
}
]
}delete_relationship
Remove a relationship between two memories. Destructive.
Parameter | Type | Required | Default | Description |
|
| Yes | — | SHA-256 hash of the source memory |
|
| Yes | — | SHA-256 hash of the target memory |
|
| Yes | — | Type of relationship to delete |
Returns:
{ "ok": true, "result": { "deleted": true } }memory_stats
Database statistics and health. No parameters required. Read-only.
Returns:
{
"ok": true,
"result": {
"memoryCount": 42,
"tagCount": 15,
"oldestMemory": "2025-01-01 00:00:00",
"newestMemory": "2025-02-09 12:00:00"
}
}Resources
URI | MIME Type | Description |
|
| Server usage instructions and tool reference guide |
Prompts
None.
Client Configuration Examples
Add to your VS Code settings.json or use the one-click install buttons above:
{
"mcp": {
"servers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"]
}
}
}
}With environment variables:
{
"mcp": {
"servers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"],
"env": {
"MEMDB_PATH": "${workspaceFolder}/.memdb/memory.db",
"MEMDB_LOG_LEVEL": "warn"
}
}
}
}
}Add to your Claude Desktop configuration file (claude_desktop_config.json):
{
"mcpServers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"]
}
}
}Or manually add to Cursor MCP settings:
{
"mcpServers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"]
}
}
}Add to your Windsurf MCP configuration:
{
"mcpServers": {
"memdb": {
"command": "npx",
"args": ["-y", "@j0hanz/memdb@latest"]
}
}
}Security
stdio hygiene — All logging is sent to
stderrviaconsole.error(). No non-MCP output is written tostdout, preventing JSON-RPC corruption.Batch request rejection — JSON-RPC batch arrays are explicitly rejected by the custom
BatchRejectingStdioServerTransportwith proper error responses per MCP spec (≥ 2025-06-18).Protocol version guard — Unsupported protocol versions are rejected at the transport layer before reaching tool handlers. The connection is closed after sending the error.
Input validation — All tool inputs are validated via Zod strict schemas at the MCP boundary. Null bytes in environment variables are detected and rejected.
Database safety — SQLite defensive mode is enabled, foreign key constraints are enforced, and the
allowExtensionoption is set tofalse.
Development Workflow
Prerequisites
Node.js ≥ 24
Install dependencies
npm installScripts
Script | Command | Purpose |
|
| TypeScript watch mode (compile on change) |
|
| Run server with auto-restart and |
|
| Compile TypeScript to |
|
| Run the compiled server |
|
| Run tests with |
|
| Run tests with coverage |
|
| TypeScript type checking ( |
|
| Run ESLint |
|
| Auto-fix linting issues |
|
| Format code with Prettier |
|
| Remove build artifacts |
|
| Launch MCP Inspector for debugging |
Build and Release
The project publishes to npm via a GitHub Actions workflow triggered on GitHub Releases:
Checkout → Setup Node.js 20 → Install dependencies
Lint → Type-check → Test → Coverage
Build → Extract version from release tag → Publish to npm with trusted publishing (OIDC)
See .github/workflows/publish.yml for the full pipeline.
Troubleshooting
node:sqlite not found
You are running Node.js < 24. The native node:sqlite module requires Node.js ≥ 24.
node --version # Must be >= 24.0.0Database locked errors
The server uses SQLite WAL mode. If you see locked errors, ensure no external tools are accessing .memdb/memory.db while the server is running.
FTS5 errors
If you get errors mentioning fts5 or no such module, ensure your Node.js binary includes the standard SQLite FTS5 extension (it should by default in Node.js ≥ 24).
Debugging with MCP Inspector
npx @modelcontextprotocol/inspector node dist/index.jsstdout corruption (stdio mode)
If your MCP client receives malformed responses, ensure no middleware or debugging tools are writing to stdout. memdb routes all logging to stderr.
Contributing
Contributions are welcome! Please ensure your changes pass all checks before submitting:
npm run lint && npm run type-check && npm run build && npm testLicense
Available Tools
12 toolscreate_relationshipCreate RelationshipAIdempotent
Link two memories with a typed relationship. Creates a knowledge graph edge between memories.
| Name | Required | Description | Default |
|---|---|---|---|
| to_hash | Yes | SHA-256 hash of the target memory | |
| from_hash | Yes | SHA-256 hash of the source memory | |
| relation_type | Yes | Type of relationship (e.g., "related_to", "causes", "depends_on", "part_of", "follows") |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The idempotentHint annotation already tells the agent the operation can be repeated safely. The description adds that an edge is created and is typed, but it does not disclose side effects (e.g., whether existing edges are overwritten, whether relationship counts affect memory_stats, or authorization requirements). With the contradiction-free annotation, a 3 is fair.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The core action ('Link two memories with a typed relationship') is front-loaded, and the second sentence adds clarifying graph vocabulary. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter creation tool with a full output schema, idempotentHint, and 100% schema coverage, the description is complete enough. The only gap is usage guidance about whether the relation should be created symmetrically or whether duplicate relations are permitted, but the schema and annotation already cover most operational needs.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Parameter help is 100% covered by the input schema, so the baseline is 3. The description slightly adds value by framing the parameters as endpoints of a directed edge ('Link two memories'), which clarifies the from/to directionality. It also notes the relation_type is 'typed', reinforcing the schema's examples. No further detail needed.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific verb ('Link') and resource ('two memories', 'knowledge graph edge'), and is distinct from siblings like get_relationships or delete_relationship. The 'typed relationship' phrasing clarifies that the edge is categorized, not a generic link.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies usage context — creating edges in a knowledge graph between existing memories — but does not explicitly state when to prefer this over store_memory, update_memory, or get_relationships, nor does it mention prerequisites such as both memories existing or hashes being retrievable. It gives some context but no exclusions or alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_memoriesDelete Multiple MemoriesADestructive
Delete multiple memories by hash in a single batch operation. Returns per-item results with partial success support.
| Name | Required | Description | Default |
|---|---|---|---|
| hashes | Yes | Hashes of memories to delete (1-50 hashes) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already carry destructiveHint=true, and the description aligns with that. It adds value beyond the annotation by disclosing batch semantics, per-item results, and partial success behavior. It does not contradict the annotations, and the additional behavioral details are relevant for an agent deciding on error handling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences lead with the primary action and scope, then immediately convey important return semantics (per-item results, partial success). No filler or repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a single-parameter tool with a 100% documented schema, a destructiveHint annotation, and an output schema already covering return structure, the description provides the remaining essential context: that it is batch and supports partial success. Nothing critical is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with the hashes parameter already documenting the 1-50 count and memory-hash nature. The description adds the notion of 'by hash' and 'batch operation' but does not meaningfully extend parameter understanding beyond the schema. Baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Delete'), the resource ('memories'), and the key scoping ('multiple', 'by hash', 'single batch operation'). This also distinguishes it from the sibling delete_memory, which is singular, and from other memory tools. The title reinforces the plural nature.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description clearly implies this tool is for deleting more than one memory at once and highlights partial success support, which is useful context. However, it does not explicitly name the alternative delete_memory or state when to prefer one over the other, so it stops short of full guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_memoryDelete MemoryCDestructive
Delete by hash
| Name | Required | Description | Default |
|---|---|---|---|
| hash | Yes | Hash of the memory (SHA-256, 64 hex chars) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The destructiveHint annotation already signals destructiveness, but the description adds no behavioral context such as permanence, idempotency, or scope. It is consistent with the annotation and not contradictory, but it contributes little beyond what the annotation already says.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is only three words, front-loaded, and contains no filler. It is appropriately compact for a one-parameter destructive operation, though its terseness contributes to the missing usage and behavior guidance.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The operation is simple and the schema, output schema, and destructiveHint annotation carry most of the needed information. However, the description leaves sibling selection (especially 'delete_memories') implicit and does not clarify side effects beyond the annotation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, including the SHA-256/64-hex format, so the baseline is 3. The phrase 'by hash' merely references the parameter rather than adding meaning like not-found behavior or whether deletion is idempotent.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description gives a clear verb ('Delete') and selection mechanism ('by hash'), and the tool name/title supplies the resource ('memory'). It is not a tautology, but it does not explicitly differentiate from the sibling 'delete_memories' tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance about when to use this tool versus 'delete_memories', 'update_memory', or other siblings. It does not state whether it deletes a single memory, require any preconditions, or mention batch deletion alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_relationshipDelete RelationshipADestructive
Remove a relationship between two memories.
| Name | Required | Description | Default |
|---|---|---|---|
| to_hash | Yes | SHA-256 hash of the target memory | |
| from_hash | Yes | SHA-256 hash of the source memory | |
| relation_type | Yes | Type of relationship to delete |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare destructiveHint=true, so the description does not need to restate the destructive nature. The description adds a useful behavioral detail: it removes only the relationship, not the underlying memories. It does not disclose idempotency, permanence beyond the annotation, or error behavior, but the annotation lowers the bar.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, focused sentence with no filler. It front-loads the action and object, and every word earns its place without repeating schema or annotation content.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple 3-parameter destructive tool, the schema plus annotations plus description are nearly sufficient: all inputs are documented, validation is clear, and the destructive hint is present. Missing sibling-routing and usage guidance slightly reduce completeness, but these are partially accounted for under usage guidelines.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with all three parameters (from_hash, to_hash, relation_type) documented including patterns and descriptions. The description itself adds no parameter-level meaning, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb, 'Remove', and clearly identifies the resource: a relationship between two memories. This distinguishes it from sibling tools like delete_memory and create_relationship without ambiguity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
There is no guidance on when to use this tool versus alternatives such as get_relationships or delete_memory, and no conditions, preconditions, or exclusions are provided. Usage context must be inferred entirely from the tool name and annotations.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_memoryGet MemoryC
Retrieve memory by hash
| Name | Required | Description | Default |
|---|---|---|---|
| hash | Yes | Hash of the memory (SHA-256, 64 hex chars) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. 'Retrieve memory by hash' only restates the action implied by the name; it does not disclose what happens on a miss, whether the operation is strictly read-only, or whether any errors are expected. The presence of an output schema helps but is not part of the description.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no wasted words. It is efficient, though it could include more useful behavioral or usage context without sacrificing conciseness.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter lookup with an output schema, the description is minimally adequate. However, it omits usage guidance and behavior on missing hashes, and given the large sibling set, some disambiguation would make the definition complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema fully documents the hash parameter with a type, pattern, and description (100% coverage). The description adds no additional semantic value beyond what the schema already states, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description 'Retrieve memory by hash' uses a specific verb and resource, and adds the retrieval key (hash). It is clear what the tool does, though it does not explicitly contrast with sibling retrieval tools like search_memories or recall.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is given about when to use this tool versus the many siblings (search_memories, recall, get_relationships). The only implied usage is that you need a hash, but this is not stated as a decision rule or contrasted with alternatives.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_relationshipsGet RelationshipsARead-only
Get all relationships for a memory. Returns linked memories with relationship types.
| Name | Required | Description | Default |
|---|---|---|---|
| hash | Yes | SHA-256 hash of the memory to get relationships for | |
| direction | No | Direction: outgoing (from this memory), incoming (to this memory), both (default) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, so the safety profile is covered. The description adds the behavior that it returns all linked memories with relationship types, and the phrase 'all' signals exhaustive retrieval. No contradiction with annotations.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with the operation, and no filler. The second sentence adds return semantics rather than repeating the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple read-only tool with a rich output schema and fully documented parameters, the description covers the core concept. It could add a note about relationship traversal use cases, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%: the schema already explains the 'hash' target and the 'direction' enum/default. The description adds no parameter-level meaning beyond naming the target memory, so the baseline 3 is appropriate.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a specific verb and resource ('Get all relationships for a memory') and clarifies what the call returns ('linked memories with relationship types'). This clearly separates it from get_memory (single memory) and create_relationship/delete_relationship (mutations).
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The intended use is implied: call this when you need the relationships of a specific memory. However, it gives no explicit when-not-to-use guidance or mention of alternatives such as search_memories or recall, so the agent must infer selection criteria from sibling names.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
memory_statsMemory StatsARead-only
Database statistics and health
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already covers the safety profile, and the description adds the specific focus on statistics and health, which is useful context. It does not disclose details about the returned metrics or whether the data is cached/current, but the presence of an output schema lowers the burden.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single four-word phrase that is immediately scannable and contains no filler or redundant repetition of the tool name or title. It front-loads the entire meaning with maximum economy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a no-parameter, read-only tool with an output schema and no nested objects, 'Database statistics and health' is enough for an agent to select and invoke it correctly. The output schema can carry the return-value detail, so no additional description is required.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters and the schema explicitly says 'No parameters required', so parameter documentation is unnecessary. This is the zero-parameter baseline case where the description does not need to add parameter meaning.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description identifies a specific resource (the database) and subject area (statistics and health), which clearly separates it from the memory CRUD and relationship siblings. It lacks an explicit verb like 'retrieve' or 'show', so it stops just short of a fully specified purpose.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The phrase 'statistics and health' implies this is the read-only inspection/status tool, and no sibling covers that function, so the intended use is reasonably clear. However, the description does not explicitly state when to prefer it or when not to use it, leaving the guidance implicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
recallRecall MemoriesARead-only
Search for memories and traverse relationships to return a connected graph cluster. Use this for deeper context retrieval that follows knowledge graph connections.
| Name | Required | Description | Default |
|---|---|---|---|
| depth | No | How many relationship hops to follow (0-3, default 1). 0 = search only, no graph traversal. | |
| query | Yes | Search query to find initial memories |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotation readOnlyHint=true already signals safety, and the description adds meaningful behavior: it searches memories, traverses relationships, and returns a connected graph cluster. This goes beyond the annotation without contradicting it. It doesn't detail edge cases like no matching memories or depth limits, but those are partially covered by the schema and output schema.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is two sentences with no filler. The first sentence states the core mechanism and result, and the second sentence gives the intended use case. It is concise, front-loaded, and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The read-only annotation, fully described parameters, and presence of an output schema cover most operational concerns. The description still leaves some implicit routing choices—e.g., how it differs from a plain search_memories call—but overall it provides sufficient context for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so both 'query' and 'depth' are already documented in the schema. The description adds minimal parameter-specific meaning beyond the general notion of graph traversal, which is acceptable given the schema's thoroughness.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the action ('Search for memories and traverse relationships') and the resource/output ('connected graph cluster'). It also distinguishes itself from siblings like search_memories and get_memory by emphasizing knowledge-graph traversal, so an agent can tell which tool is intended.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives explicit guidance on when to use the tool: 'Use this for deeper context retrieval that follows knowledge graph connections.' It does not explicitly name alternatives or state when not to use it, but the context is clear enough to route an agent appropriately.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
search_memoriesSearch MemoriesBRead-only
Search memories by content and tags
| Name | Required | Description | Default |
|---|---|---|---|
| query | Yes | Search query (searches content and tags) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The readOnlyHint annotation already communicates the safe, non-mutating nature of the tool. The description adds only that search is by content and tags, which repeats the query parameter's schema description; it does not disclose behavior like matching semantics, result ordering, or limits. No contradiction with annotations exists.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single, front-loaded sentence with no filler or redundant phrasing. It states the action and scope directly, making it easy for an agent to parse.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a one-parameter tool with an output schema and a readOnlyHint, the description is minimally sufficient. However, it lacks any context about how search_memories relates to recall or when tag-based search is preferred, leaving some ambiguity in a toolset with several similar memory-access operations.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the parameter is already fully documented. The description adds no new meaning beyond what the schema provides, which is acceptable but not additive.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as a search operation over memories, specifying the search dimensions: content and tags. It is more specific than a tautology and distinguishes itself from direct retrieval tools like get_memory, though it doesn't explicitly differentiate from the sibling recall tool.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives no explicit guidance on when to choose search_memories over alternatives such as get_memory or recall. The only usage signal is the implied need to search by content or tags, which is reasonable but not stated as selection criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
store_memoriesStore Multiple MemoriesAIdempotent
Store multiple memories in a single batch operation. Returns per-item results with partial success support.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes | Memories to store (1-50 items) |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description goes beyond the idempotentHint annotation by disclosing partial success support and per-item results, which are important behavioral traits not captured in structured metadata. However, it does not explain what happens on partial failure or how failures are indicated in the output.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences with no filler. The core purpose is front-loaded, and the key behavioral trait (partial success) is stated compactly in the second sentence. Every word earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
The definition is complete for a batch tool of this complexity: output schema exists, so return values need no description; annotations cover idempotency; and partial success is disclosed. More detail on failure-item identification would elevate it further, but nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, with the items array and each nested property well-documented. The description adds no new parameter semantics but is not required to, given the schema's completeness. Baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Description states a specific action ('Store multiple memories in a single batch operation'), clearly identifying the resource (multiple memories) and the batching behavior. It distinguishes itself from sibling store_memory via the 'multiple' and 'batch' framing, so an agent can select it correctly.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies when to use it (when storing multiple memories at once) but does not explicitly state when to use store_memory instead, nor does it mention any exclusion criteria or alternatives. Usage context is inferable but not explicit.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
store_memoryStore MemoryBIdempotent
Store a new memory with tags
| Name | Required | Description | Default |
|---|---|---|---|
| tags | Yes | Tags to categorize the memory (1-100 tags, no whitespace, max 50 chars each) | |
| content | Yes | The content of the memory | |
| importance | No | Priority level 0-10 (0=lowest, 10=critical). Higher importance memories surface first in search. | |
| memory_type | No | Category: general, fact, plan, decision, reflection, lesson, error, gradient |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description states the core write behavior: storing a new memory. The annotation 'idempotentHint: true' already covers repeat-call safety, but the description does not explain what idempotency means here, such as whether duplicate content is deduplicated, replaced, or ignored. There is no direct contradiction, but behavioral context beyond annotations is minimal.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is a single compact, front-loaded sentence with no filler words. It is efficient and easy to scan, though it is so terse that it misses useful guidance about siblings and behavior.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the rich schema descriptions and the presence of an output schema, an agent can likely invoke the tool correctly with the required parameters. However, the description alone does not clarify when to choose this over store_memories or how the idempotent behavior manifests, so the overall definition is adequate but not complete.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so each parameter is already well documented, including tags constraints, importance priority, and memory_type enum. The description adds no semantic value beyond singling out tags, which is already required by the schema. Baseline 3 is appropriate because the schema carries the full parameter burden.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description uses a clear verb ('store') and resource ('memory'), and identifies tags as part of the operation. It is not a tautology because it adds that a new memory is created with tags. However, it does not distinguish this singular tool from its sibling 'store_memories', so an agent must infer the difference from the name alone.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No guidance is provided about when to use this tool versus alternatives such as 'store_memories' for bulk storage, 'update_memory' for existing memories, or 'recall'/'search_memories' for retrieval. The agent is left to infer usage context from the tool name and input schema.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
update_memoryUpdate MemoryAIdempotent
Update memory content. Returns new hash since content change affects the hash.
| Name | Required | Description | Default |
|---|---|---|---|
| hash | Yes | Hash of the memory to update | |
| tags | No | Replace tags (max 100 tags, each max 50 chars) | |
| content | Yes | New content for the memory |
Output Schema
| Name | Required | Description |
|---|---|---|
| ok | Yes | |
| error | No | |
| result | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The description discloses a useful behavioral consequence: content changes alter the hash, so a new hash is returned. However, with only idempotentHint in annotations and no destructive/readOnly hints, it does not clarify whether old content is fully replaced, whether the old hash becomes invalid, or what happens on repeated calls.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences front-load the primary action and add exactly one consequential detail. There is no redundancy with the schema or annotations, and every sentence earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a simple three-parameter tool with 100% schema coverage, an output schema, and an idempotency annotation, the description is nearly sufficient. The main gap is usage routing among siblings, but the core update behavior and hash side effect are clear enough to invoke correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the required and optional parameters are already well documented. The description adds value by explaining the semantic tie between content and hash, clarifying why the tool returns a new hash.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description opens with a specific action and resource: 'Update memory content.' It also adds the key consequence that a new hash is returned. It is clearly distinguishable from sibling store/get/delete tools, though it does not mention that tags can also be replaced.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
No explicit guidance is provided about when to use this tool versus store_memory, delete_memory, or search_memories. The verb 'Update' implies modifying an existing memory, but there are no stated conditions, prerequisites, or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
12 tool updates
v1.4.0- First observed
create_relationship - First observed
delete_memories - First observed
delete_memory - First observed
delete_relationship - First observed
get_memory - First observed
get_relationships - First observed
memory_stats - First observed
recall - First observed
search_memories - First observed
store_memories - First observed
store_memory - First observed
update_memory
TDQS
Scored across 12 tools
Tools are mostly distinct: CRUD operations, batch variants, search, and relationship operations each have clear roles. The only mild ambiguity is between search_memories and recall, though recall's relationship traversal is explicitly described.
Most tools follow a clear verb_noun pattern like store_memory, get_memory, delete_memory, and create_relationship. Minor deviations are 'recall' and 'memory_stats', which are still readable but break the otherwise consistent convention.
12 tools is well-scoped for a memory server with knowledge graph features. Each tool covers a distinct operation without bloat or redundancy.
The memory lifecycle is well covered with single and batch creates/deletes, retrieval, update, search, and stats. Minor gaps include no explicit list-all operation and no update operation for relationships, but these are workable via search and delete/recreate.
Maintenance
Related MCP Connectors
Persistent, portable memory for AI assistants — your private memory graph, from any MCP client.
Persistent personal memory for AI assistants — save, search, and recall across every MCP client.
- EngramOAuthapp.getengram
Persistent, verbatim, searchable memory for AI assistants — one memory across every MCP client.
Persistent memory for AI agents — log and recall conversation context over MCP.
Related MCP Servers
- AlicenseAqualityCmaintenanceA local, fully-offline MCP memory server that enables persistent storage and retrieval of information using SQLite with both keyword and semantic vector search capabilities.1019 npm13MIT
- AlicenseNot gradedqualityDmaintenanceMCP server providing persistent memory management for AI agents using SQLite and FTS5, enabling storage, full-text search, and recall of memories with namespace isolation.1MIT
- AlicenseNot gradedqualityCmaintenanceA local-first MCP memory server providing persistent, searchable memory for AI agents, powered by SQLite.1 npm1Apache 2.0
- AlicenseAqualityCmaintenanceA local-first MCP server for durable agent memory using SQLite and FTS5, enabling knowledge graph storage, search, and recall for AI agents.201MIT