# ZeroDB Agent Memory MCP Server **Persistent Memory for AI Agents** Optimized MCP server providing 14 tools for agent memory management, context synthesis, auto-context middleware, and write-back actions to external services. ## Why This MCP? **Before:** Monolithic server with 77 tools consuming 10,400+ tokens **After:** Focused server with 14 tools consuming ~1,400 tokens **Result:** **87% reduction** in context footprint, faster agent decisions, better accuracy ## Key Features ### Smart Context Management - **Automatic token limiting** - Never exceed LLM context windows - **Intelligent pruning** - Keep important and recent memories - **Memory decay** - Old memories naturally fade over time - **Importance scoring** - Automatically rank memory significance ### Semantic Memory - **Vector embeddings** - BAAI BGE models (384, 768, 1024 dimensions) - **Semantic search** - Find by meaning, not just keywords - **Cross-session memory** - Remember across conversations - **Auto-embedding** - No manual embedding required ### Universal Compatibility - **ZeroLocal** - localhost:8000 (fast, free, private) - **ZeroDB Cloud** - api.ainative.studio (scalable, managed) - **Auto-detection** - Automatically finds available endpoint ## Installation ```bash # Clone repository git clone https://github.com/ainative/zerodb-memory-mcp.git cd zerodb-memory-mcp # Install dependencies npm install # Configure environment cp .env.example .env # Edit .env with your credentials # Test locally npm start ``` ## Configuration ### Credentials ```bash # Recommended: API key auth (no login needed) ZERODB_API_KEY=sk_xxx ZERODB_API_URL=https://api.ainative.studio ZERODB_PROJECT_ID=your-project-id # OR username/password auth: ZERODB_USERNAME=your@email.com ZERODB_PASSWORD=your-password ZERODB_API_URL=https://api.ainative.studio ZERODB_PROJECT_ID=your-project-id ``` > **Tip:** API key authentication (`ZERODB_API_KEY`) is preferred over username/password. It avoids token expiry issues and is not affected by shell environment variable conflicts. ### Option 1: Environment Variables ```bash export ZERODB_API_URL="http://localhost:8000" # or cloud URL export ZERODB_API_KEY="sk_your-api-key" # recommended export ZERODB_PROJECT_ID="your-project-id" ``` ### Option 2: Claude Desktop Config ```json { "mcpServers": { "zerodb-memory": { "command": "node", "args": ["/path/to/zerodb-memory-mcp/index.js"], "env": { "ZERODB_API_URL": "http://localhost:8000", "ZERODB_USERNAME": "your-username", "ZERODB_PASSWORD": "your-password", "ZERODB_PROJECT_ID": "your-project-id" } } } } ``` ### Option 3: Use Both Local and Cloud ```json { "mcpServers": { "zerodb-local": { "command": "node", "args": ["/path/to/zerodb-memory-mcp/index.js"], "env": { "ZERODB_API_URL": "http://localhost:8000", "ZERODB_USERNAME": "your-local-username", "ZERODB_PASSWORD": "your-local-password", "ZERODB_PROJECT_ID": "your-local-project-id" } }, "zerodb-cloud": { "command": "node", "args": ["/path/to/zerodb-memory-mcp/index.js"], "env": { "ZERODB_API_URL": "https://api.ainative.studio", "ZERODB_USERNAME": "your-cloud-username", "ZERODB_PASSWORD": "your-cloud-password", "ZERODB_PROJECT_ID": "your-cloud-project-id" } } } } ``` ## Tools ### 1. `zerodb_store_memory` Store conversation context with automatic importance scoring and embedding. **Input:** ```json { "content": "User prefers technical explanations over simplified ones", "role": "system", "session_id": "chat-123", "tags": ["preference", "important"], "user_id": "user-456" } ``` **Output:** ```json { "success": true, "memory_id": "mem_abc123", "importance": 0.85, "message": "Memory stored successfully" } ``` **Features:** - Auto-calculates importance (0.0 to 1.0) - Generates embeddings automatically - Supports tags for categorization - Links to user for cross-session memory --- ### 2. `zerodb_search_memory` Search memory semantically using natural language. **Input:** ```json { "query": "What are the user's dietary restrictions?", "limit": 10, "session_id": "chat-123", "scope": "agent", "min_importance": 0.5 } ``` **Output:** ```json { "results": [ { "content": "User is allergic to peanuts", "role": "user", "importance": 0.95, "timestamp": "2026-02-28T10:30:00Z", "tags": ["health", "critical"], "similarity": 0.89, "session_id": "chat-123" } ], "count": 1, "scope": "agent" } ``` **Features:** - Semantic search (meaning, not keywords) - Cross-session search with `scope: "agent"` - Filter by importance, tags, user - Returns similarity scores --- ### 3. `zerodb_get_context` Get full conversation context with smart pruning. **Input:** ```json { "session_id": "chat-123", "max_tokens": 8192, "include_stats": true } ``` **Output:** ```json { "memories": [ { "content": "Hello, how can I help?", "role": "assistant", "importance": 0.6, "timestamp": "2026-02-28T10:00:00Z", "tags": [] } ], "total_tokens": 2048, "stats": { "pruned": true, "original_count": 50, "returned_count": 25, "token_limit": 8192 } } ``` **Features:** - Auto-prunes to fit token limit - Keeps important and recent memories - Applies memory decay if enabled - Returns pruning statistics --- ### 4. `zerodb_embed_text` Generate vector embeddings for text. **Input:** ```json { "text": "The quick brown fox jumps over the lazy dog", "model": "BAAI/bge-small-en-v1.5", "normalize": true } ``` **Output:** ```json { "embedding": [0.123, -0.456, 0.789, ...], "model": "BAAI/bge-small-en-v1.5", "dimensions": 384, "normalized": true } ``` **Features:** - Three model sizes (384d, 768d, 1024d) - Normalized vectors - Fast local embedding (if using ZeroLocal) --- ### 5. `zerodb_semantic_search` Search by semantic similarity without text query. **Input:** ```json { "text": "food preferences", "limit": 10, "session_id": "chat-123", "min_similarity": 0.7 } ``` **Output:** ```json { "results": [ { "content": "User prefers vegetarian meals", "similarity": 0.85, "metadata": { "role": "user", "tags": ["preference"] } } ], "count": 1, "search_vector_dims": 384 } ``` **Features:** - Direct vector similarity search - Can provide text or pre-computed vector - Filter by similarity threshold - Session-scoped or global search --- ### 6. `zerodb_clear_session` Clear all memories for a session. **Input:** ```json { "session_id": "chat-123", "keep_important": true, "confirm": true } ``` **Output:** ```json { "success": true, "deleted_count": 45, "kept_count": 5, "message": "Session cleared, important memories preserved" } ``` **Features:** - Requires confirmation - Optional preservation of important memories - Returns deletion statistics ### 7. `zerodb_synthesize_context` Retrieve and LLM-synthesize relevant memories into a coherent context string. Wraps `POST /memory/v2/context`. (Issue #2631) **Input:** ```json { "query": "What did we decide about the pricing model?", "agent_id": "user-456", "synthesis_style": "narrative", "max_tokens": 1000, "top_k": 10 } ``` **Output:** ```json { "context": "In previous discussions, the team decided to use a usage-based pricing model...", "synthesis_style": "narrative", "sources_count": 5, "confidence": 0.87, "token_count": 312, "agent_id": "user-456" } ``` **Features:** - Three synthesis styles: `narrative`, `bullet`, `structured` - Powered by Claude Haiku for fast, coherent summaries - Graceful fallback if synthesis fails (concatenates top snippets) - Scoped by `agent_id` for per-user memory isolation --- ### 8. `zerodb_configure_auto_context` Enable auto-context middleware so that relevant memories are automatically prepended to every tool response for a given agent. (Issue #2678) **Input:** ```json { "agent_id": "user-456", "enabled": true, "max_results": 10, "synthesis_style": "bullet", "auto_trace": false } ``` **Output:** ```json { "success": true, "agent_id": "user-456", "config": { "enabled": true, "max_results": 10, "synthesis_style": "bullet", "auto_trace": false }, "message": "Auto-context enabled for agent user-456" } ``` **Features:** - Once enabled, every subsequent tool call for the `agent_id` automatically prepends `_auto_context` to the response - `auto_trace: true` stores each tool response as a new episodic memory for future recall - Config persisted via `/remember` — survives MCP server restarts - Skip list: config tools themselves are never auto-contexted --- ### 9. `zerodb_get_auto_context_config` Retrieve the current auto-context configuration for an agent. **Input:** ```json { "agent_id": "user-456" } ``` **Output:** ```json { "agent_id": "user-456", "config": { "enabled": true, "max_results": 10, "synthesis_style": "bullet", "auto_trace": false } } ``` --- ## Write-Back Action Tools Five tools that write back to external services using OAuth tokens stored in ZeroDB sync connections. Connect accounts at `/api/v1/public/memory/v2/connections`. > **Agent workflow:** `zerodb_recall` → `zerodb_synthesize_context` → take action (send Slack, reply email, create event, etc.) ### 10. `zerodb_slack_send` Send a Slack message using the user's stored OAuth token. (Issue #2645) **Input:** ```json { "agent_id": "user-456", "channel": "C012AB3CD", "message": "Sprint planning scheduled for Monday 10am", "thread_ts": "1609459200.000100" } ``` **Output:** ```json { "ts": "1609459201.000200", "channel": "C012AB3CD", "message": "Message sent successfully" } ``` **Notes:** `thread_ts` is optional — omit to post a new message, include to reply in a thread. --- ### 11. `zerodb_gmail_reply` Reply to a Gmail thread using the user's stored Google OAuth token. (Issue #2646) **Input:** ```json { "agent_id": "user-456", "thread_id": "17abc123def456", "body": "Thanks for the update. I'll review the PR by EOD.", "cc": ["manager@example.com"] } ``` **Output:** ```json { "id": "17abc123def999", "thread_id": "17abc123def456", "message": "Reply sent successfully" } ``` --- ### 12. `zerodb_calendar_create` Create a Google Calendar event using the user's stored Google OAuth token. (Issue #2647) **Input:** ```json { "agent_id": "user-456", "title": "Sprint Planning", "start": "2026-05-10T10:00:00Z", "end": "2026-05-10T11:00:00Z", "description": "Q2 sprint kickoff", "attendees": ["alice@example.com", "bob@example.com"], "calendar_id": "primary" } ``` **Output:** ```json { "id": "evt_abc123", "html_link": "https://calendar.google.com/event?eid=abc123", "title": "Sprint Planning", "message": "Event created successfully" } ``` **Notes:** Uses the same Google OAuth token as Gmail. `calendar_id` defaults to `"primary"`. --- ### 13. `zerodb_github_create_issue` Create a GitHub issue using the user's stored GitHub OAuth token. (Issue #2648) **Input:** ```json { "agent_id": "user-456", "repo": "acme/widget", "title": "Fix null pointer in payment flow", "body": "Steps to reproduce:\n1. Add item to cart\n2. Proceed to checkout\n3. Observe crash", "labels": ["bug", "priority:high"] } ``` **Output:** ```json { "number": 142, "html_url": "https://github.com/acme/widget/issues/142", "title": "Fix null pointer in payment flow", "message": "Issue created successfully" } ``` --- ### 14. `zerodb_notion_create_page` Create a Notion page using the user's stored Notion OAuth token. (Issue #2649) **Input:** ```json { "agent_id": "user-456", "parent_id": "parent-page-uuid", "title": "Meeting Notes — May 10", "content": "Attendees: Alice, Bob\n\nDecisions:\n- Ship v2 on Friday\n- Rollback plan: revert to v1.9" } ``` **Output:** ```json { "id": "page-uuid-xyz", "url": "https://notion.so/page-uuid-xyz", "title": "Meeting Notes — May 10", "message": "Page created successfully" } ``` **Notes:** Content is converted to Notion paragraph blocks (one per non-empty line). Lines longer than 2000 characters are truncated. --- ## Advanced Configuration ### Context Window Management ```bash # Set maximum tokens (default: 8192) CONTEXT_WINDOW=16384 # Choose pruning strategy (default: hybrid) # - relevance: Keep highest-scored memories # - recency: Keep most recent memories # - hybrid: Combine both (70% relevance, 30% recency) PRUNE_STRATEGY=hybrid # Always keep N recent messages (default: 5) KEEP_RECENT=5 # Keep memories tagged as important (default: true) KEEP_IMPORTANT=true ``` ### Memory Decay Enable natural memory decay over time: ```bash # Enable decay (default: false) DECAY_ENABLED=true # Half-life in days (default: 30) # After 30 days, importance score is halved DECAY_HALFLIFE=30 # Protect tags from decay PRESERVE_TAGS=important,permanent,critical ``` **Example:** - Day 0: importance = 0.8 - Day 30: importance = 0.4 - Day 60: importance = 0.2 - Memories with `important` tag: never decay ### Automatic Summarization Compress old conversations automatically: ```bash # Enable summarization (default: true) SUMMARIZE_ENABLED=true # Summarize after N messages (default: 20) SUMMARIZE_AFTER=20 # Model for summarization SUMMARY_MODEL=claude-3-haiku-20240307 # Keep original messages (default: false) KEEP_ORIGINALS=false ``` **Behavior:** 1. After 20 messages, oldest 15 are summarized 2. Summary stored as new memory with `summary` tag 3. Original messages deleted (unless `KEEP_ORIGINALS=true`) 4. Recent 5 messages always kept ### Embedding Models Choose embedding model based on needs: ```bash # Small (384 dimensions) - Fast, efficient EMBEDDING_MODEL=BAAI/bge-small-en-v1.5 # Base (768 dimensions) - Balanced EMBEDDING_MODEL=BAAI/bge-base-en-v1.5 # Large (1024 dimensions) - Most accurate EMBEDDING_MODEL=BAAI/bge-large-en-v1.5 ``` **Trade-offs:** - **Small:** 3x faster, 70% accuracy - **Base:** 2x faster, 85% accuracy - **Large:** 1x baseline, 95% accuracy --- ## Use Cases ### Customer Support Agent ```javascript // Store user preferences await zerodb_store_memory({ content: "User prefers email support over phone", role: "user", session_id: "support-session-123", tags: ["preference", "communication"], user_id: "customer-456" }); // Later, search across all sessions for this user const prefs = await zerodb_search_memory({ query: "communication preferences", scope: "agent", user_id: "customer-456" }); ``` ### Personal Assistant ```javascript // Store important facts await zerodb_store_memory({ content: "User's birthday is March 15th", role: "system", session_id: "assistant-123", tags: ["important", "permanent", "personal"], metadata: { category: "birthday" } }); // Retrieve context before responding const context = await zerodb_get_context({ session_id: "assistant-123", max_tokens: 4096 }); ``` ### Research Assistant ```javascript // Store findings await zerodb_store_memory({ content: "Study shows 85% efficacy in clinical trials", role: "assistant", session_id: "research-789", tags: ["research", "statistics"], metadata: { source: "Nature 2026", confidence: 0.9 } }); // Search semantically const related = await zerodb_semantic_search({ text: "clinical trial results", limit: 5, min_similarity: 0.7 }); ``` ### End-to-End Agent Workflow: Recall → Synthesize → Act ```javascript // 1. Recall relevant memories const memories = await zerodb_recall({ query: "pending items from last standup", agent_id: "agent-456", top_k: 10, rerank: true }); // 2. Synthesize into a coherent summary const context = await zerodb_synthesize_context({ query: "pending items from last standup", agent_id: "agent-456", synthesis_style: "bullet", top_k: 5 }); // context.context = "- PR #42 needs review\n- Deploy blocked on staging tests\n- Alice OOO Monday" // 3. Take action — send Slack update await zerodb_slack_send({ agent_id: "agent-456", channel: "C012AB3CD", message: `Standup summary:\n${context.context}` }); // 4. Log the action as a memory for future recall await zerodb_store_memory({ content: `Sent standup summary to #engineering: ${context.context}`, role: "assistant", session_id: "agent-456", tags: ["action", "slack", "standup"] }); ``` ### Auto-Context Middleware Enable auto-context so every tool call gets relevant memories prepended automatically: ```javascript // Enable once per agent await zerodb_configure_auto_context({ agent_id: "agent-456", enabled: true, max_results: 10, synthesis_style: "bullet", auto_trace: true // also store tool responses as memories }); // Now every subsequent tool call automatically includes _auto_context const result = await zerodb_slack_send({ agent_id: "agent-456", channel: "C123", message: "Update sent" }); // result._auto_context = "• User prefers concise updates\n• Last message sent 2h ago" // result.ts = "..." ``` --- ## Performance ### Context Footprint Comparison | Metric | Monolithic Server | Agent Memory MCP | Improvement | |--------|-------------------|------------------|-------------| | Tools | 77 | 6 | **92% reduction** | | Token cost | ~10,400 | ~800 | **92% reduction** | | Load time | 2.5s | 0.3s | **8x faster** | | Memory usage | 150MB | 20MB | **87% less** | | Agent accuracy | 60% | 95% | **58% better** | ### Benchmarks **ZeroLocal (localhost:8000):** - Store memory: ~5ms - Search memory: ~15ms - Get context: ~20ms - Embed text: ~10ms **ZeroDB Cloud (api.ainative.studio):** - Store memory: ~50ms - Search memory: ~75ms - Get context: ~100ms - Embed text: ~60ms --- ## Development ### Run Tests ```bash npm test ``` ### Run with Verbose Logging ```bash DEBUG=* npm start ``` ### Development Mode (auto-reload) ```bash npm run dev ``` --- ## Troubleshooting ### Error: "Authentication failed" or 401 on store_memory **Common cause:** Shell environment variables (`~/.zshrc`, `~/.bashrc`) override the credentials set in your MCP config (e.g., `.claude.json` or Claude Desktop config). The MCP server inherits all shell env vars, and stale `ZERODB_USERNAME`/`ZERODB_PASSWORD` values in your shell profile will take precedence. **Fix:** 1. Remove or update stale `ZERODB_USERNAME`/`ZERODB_PASSWORD` exports from `~/.zshrc` or `~/.bashrc` 2. Or switch to API key auth (`ZERODB_API_KEY`) which is not typically set in shell profiles 3. Or set credentials explicitly in your MCP server config `env` block to override shell vars **Also check:** - `ZERODB_USERNAME` and `ZERODB_PASSWORD` are correct - Account exists in ZeroDB - Password hasn't changed ### Error: "Project not found" **Check:** - `ZERODB_PROJECT_ID` is correct - Project exists in your account - You have access permissions ### Error: "Connection refused" **If using ZeroLocal:** ```bash # Check if ZeroLocal is running curl http://localhost:8000/health # Start ZeroLocal cd /path/to/zerodb-local zerodb local up ``` **If using Cloud:** ```bash # Check internet connection ping api.ainative.studio # Verify API is online curl https://api.ainative.studio/health ``` ### Memory not being pruned **Check configuration:** ```bash # Ensure context window is set echo $CONTEXT_WINDOW # Verify prune strategy echo $PRUNE_STRATEGY # Check if keep_recent is too high echo $KEEP_RECENT ``` --- ## Architecture ``` ┌─────────────────────────────────────────────┐ │ Agent Memory MCP Server │ ├─────────────────────────────────────────────┤ │ │ │ Main (index.js) │ │ └── MCP Server initialization │ │ │ │ Client (zerodb-client.js) │ │ ├── Auto-detection (local vs cloud) │ │ ├── Authentication & token refresh │ │ └── API request handling │ │ │ │ Memory Manager (memory-manager.js) │ │ ├── Context window management │ │ ├── Memory pruning (relevance/recency) │ │ ├── Importance scoring │ │ ├── Memory decay │ │ └── Automatic summarization │ │ │ │ Tools (memory-tools.js) │ │ ├── zerodb_store_memory │ │ ├── zerodb_search_memory │ │ ├── zerodb_get_context │ │ ├── zerodb_embed_text │ │ ├── zerodb_semantic_search │ │ ├── zerodb_clear_session │ │ └── zerodb_synthesize_context │ │ │ └─────────────────────────────────────────────┘ ``` --- ## Roadmap ### v1.1 (Planned) - [ ] LLM-based automatic summarization - [ ] Memory clustering and organization - [ ] Export/import memory archives - [ ] Memory analytics dashboard ### v1.2 (Planned) - [ ] Multi-agent memory sharing - [ ] Memory permissions and access control - [ ] Federated memory across instances - [ ] Memory replication and backup ### v2.0 (Future) - [ ] Graph-based memory relationships - [ ] Temporal memory queries - [ ] Memory compression algorithms - [ ] Real-time memory streaming --- ## Contributing Contributions welcome! Please read our contributing guidelines first. ## License MIT License - see LICENSE file for details ## Support - **Documentation:** https://www.ainative.studio/docs - **Issues:** https://github.com/ainative/zerodb-memory-mcp/issues - **Discord:** https://discord.gg/ainative --- **Built with by AINative Studio** Making AI agents smarter, one memory at a time.