MCP server for semantic personal knowledge base. Exposes a searchable brain memory system with semantic similarity search, memory ingestion, and tool discovery via Cursor, Claude Desktop, and other MCP clients.
This server has strong foundational design with 7 well-defined tools operating on a semantic memory domain. Naming is action-oriented (search_brain, add_memory, recall, forget, brain_stats, index_cursor_chats, discover_tools). All tools have descriptions exceeding 20 characters. Input schemas are fully visible and properly typed using Zod. However, several tools lack comprehensive output schema documentation in code, and some parameters could benefit from tighter constraint descriptions. Error handling is present but recovery guidance is minimal. The toolshed extension (discover_tools) is a thoughtful pattern solution to the 'token explosion' problem and demonstrates good composition thinking.
Add new knowledge to the personal brain. Content is embedded and stored for future semantic retrieval.
Get statistics about the personal knowledge base: total memories, embedding coverage, breakdown by source.
Discover which MCP tools are available for a given task. Returns the most relevant tool names, servers, and descriptions based on your natural language query. Call this before using an unfamiliar tool to find the right one.
Delete a memory from the brain by its ID.
Index Cursor agent transcripts into the brain as searchable work history. Reads JSONL transcripts from the configured transcripts directory and stores each session as a memory with source="work_history". Skips already-indexed sessions by default. Search them afterward with search_brain using source="work_history".
Output schemas not documented in tool definitions. While input schemas are well-defined via Zod (query: string, limit: number with min/max, threshold: 0-1 float, source enum-like filtering), the return types and response field structures are not explicitly declared in the tool registration code visible in the source. LLMs need to know what fields to expect in responses to plan downstream tool calls and extract the right data.
Error handling returns text-based error messages without classification (retryable vs user-fixable vs fatal). In src/toolshed.ts, the discover_tools error response is '{content: [{type: "text", text: `discover_tools failed: ${msg}`}], isError: true}', this tells the LLM the tool failed, but not whether to retry, ask the user, or abandon the path. Error responses must categorize failures and provide recovery guidance.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 62 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 0 | - | v1 |
List memories with optional filtering by source, tags, or date range. No semantic search — returns raw filtered results.
Search personal knowledge base by meaning. Returns memories ranked by semantic similarity to the query.
The 'forget' tool (delete operation) lacks a confirmation/dry-run step. Destructive operations should support a confirm_before_execute pattern or at minimum require explicit user confirmation via MRTR. Agents make mistakes, deleting a memory by UUID without confirmation invites accidental data loss.
Tool descriptions lack dependency hints and when-to-use guidance. 'search_brain' says it 'Returns memories ranked by semantic similarity' but does not explain when to call it vs 'recall' (which does filtered list retrieval without embedding). This ambiguity forces LLMs to guess which to invoke for a given task.
The 'source' parameter in search_brain accepts enum-like values ('manual', 'telegram', 'cursor', 'api', 'conversations', 'knowledge', 'toolshed', 'work_history') but is declared as optional string without formal enum constraint. Free-form strings invite hallucinated values. Should be: source: z.enum(["manual", "telegram", "cursor", "api", "conversations", "knowledge", "toolshed", "work_history"]).optional().
The 'source' parameter in recall also lacks enum constraint, same issue as search_brain. Additionally, 'tags' parameter accepts array of strings but does not document what valid tag values are or how tag filtering works (OR vs AND logic).
The 'index_cursor_chats' tool's 'limit' parameter description ('Only index the N most recent transcripts') lacks clarity on what 'recent' means (by file modification time? by session date?). Also lacks min/max constraints visible in the schema.