stats
Get memory statistics for a session, broken down by role and tier (working, long-term, archived), plus graph counts.
Instructions
Memory statistics for a session — total, by role, by tier (working/long_term/archived), graph counts.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| sessionId | Yes | Session identifier |
Implementation Reference
- engram.ts:333-372 (handler)The core implementation of the `stats` method on the Engram class. It queries the SQLite database for: total memory count, count by role, oldest/newest timestamps, and count of entries with embeddings.
async stats(sessionId: string): Promise<{ total: number; byRole: Record<string, number>; oldest: Date | null; newest: Date | null; withEmbeddings: number; }> { await this.init(); const totalRow = await this.db.get( 'SELECT COUNT(*) as count FROM memories WHERE session_id = ?', [sessionId] ); const total = totalRow?.count || 0; const roleRows = await this.db.all( 'SELECT role, COUNT(*) as count FROM memories WHERE session_id = ? GROUP BY role', [sessionId] ); const byRole: Record<string, number> = {}; roleRows.forEach((row: any) => { byRole[row.role] = row.count; }); const range = await this.db.get( 'SELECT MIN(timestamp) as oldest, MAX(timestamp) as newest FROM memories WHERE session_id = ?', [sessionId] ); const embRow = await this.db.get( 'SELECT COUNT(*) as count FROM memories WHERE session_id = ? AND embedding IS NOT NULL', [sessionId] ); return { total, byRole, oldest: range?.oldest ? new Date(range.oldest) : null, newest: range?.newest ? new Date(range.newest) : null, withEmbeddings: embRow?.count || 0 }; } - src/index.ts:92-101 (schema)The input schema definition for the 'stats' tool, declaring required 'sessionId' (string) input property.
{ name: 'stats', description: 'Memory statistics for a session — total, by role, by tier (working/long_term/archived), graph counts.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, }, required: ['sessionId'], }, - src/index.ts:35-256 (registration)The tool is registered via ListToolsRequestSchema handler, which lists all tools including 'stats' at line 93.
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ // ── Session memory ────────────────────────────────────────────────── { name: 'remember', description: 'Store a memory entry for a session. Embeddings and graph extraction happen automatically.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, content: { type: 'string', description: 'Memory content to store' }, role: { type: 'string', enum: ['user', 'assistant', 'system'], default: 'user' }, metadata: { type: 'object', description: 'Optional key-value metadata' }, }, required: ['sessionId', 'content'], }, }, { name: 'recall', description: 'Retrieve relevant memories via semantic search (falls back to keyword). Searches working + long_term tiers. Pass userId to blend in cross-session user facts.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, query: { type: 'string', description: 'Search query' }, limit: { type: 'number', description: 'Max results (default 10)', default: 10 }, userId: { type: 'string', description: 'Optional: also blend in this user\'s cross-session memories' }, tiers: { type: 'string', description: 'Comma-separated tiers to search: working,long_term,archived (default: working,long_term)' }, }, required: ['sessionId', 'query'], }, }, { name: 'history', description: 'Get recent conversation history for a session in chronological order.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, limit: { type: 'number', description: 'Max entries (default 20)', default: 20 }, }, required: ['sessionId'], }, }, { name: 'forget', description: 'Delete session memories. Delete all, one by ID, or entries before a date.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, id: { type: 'string', description: 'Specific memory ID to delete (optional)' }, before: { type: 'string', description: 'ISO date — delete entries before this date (optional)' }, }, required: ['sessionId'], }, }, { name: 'stats', description: 'Memory statistics for a session — total, by role, by tier (working/long_term/archived), graph counts.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, }, required: ['sessionId'], }, }, { name: 'consolidate', description: 'Consolidate old working memories into dense long-term summaries via LLM. Archives originals.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, batch: { type: 'number', description: 'Number of memories to consolidate (default 50)' }, keep: { type: 'number', description: 'Most recent N to leave untouched (default 20)' }, dryRun: { type: 'boolean', description: 'Preview summaries without writing (default false)' }, }, required: ['sessionId'], }, }, { name: 'graph', description: 'Query the knowledge graph for an entity — returns relationships and source memories. Requires ENGRAM_GRAPH=1.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, entity: { type: 'string', description: 'Entity name to look up (case-insensitive)' }, }, required: ['sessionId', 'entity'], }, }, // ── User-scoped (cross-session) memory ────────────────────────────── { name: 'remember_user', description: 'Store a user-scoped memory that persists across all sessions. Use for preferences, identity, long-term facts.', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'User identifier' }, content: { type: 'string', description: 'Memory content to store' }, role: { type: 'string', enum: ['user', 'assistant', 'system'], default: 'user' }, metadata: { type: 'object', description: 'Optional key-value metadata' }, }, required: ['userId', 'content'], }, }, { name: 'recall_user', description: 'Recall user-scoped memories — works from any session context.', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'User identifier' }, query: { type: 'string', description: 'Search query (optional — returns all if omitted)' }, limit: { type: 'number', description: 'Max results (default 10)', default: 10 }, }, required: ['userId'], }, }, { name: 'forget_user', description: 'Delete user-scoped memories.', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'User identifier' }, id: { type: 'string', description: 'Specific memory ID (optional)' }, before: { type: 'string', description: 'ISO date — delete entries before this date (optional)' }, }, required: ['userId'], }, }, { name: 'consolidate_user', description: 'Consolidate user-scoped working memories into long-term summaries.', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'User identifier' }, batch: { type: 'number', description: 'Number of memories to consolidate (default 50)' }, keep: { type: 'number', description: 'Most recent N to leave untouched (default 20)' }, dryRun: { type: 'boolean', description: 'Preview without writing (default false)' }, }, required: ['userId'], }, }, { name: 'user_stats', description: 'Memory statistics for a user — total, by role, by tier.', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'User identifier' }, }, required: ['userId'], }, }, // ── Temporal & export tools ──────────────────────────────────────── { name: 'recall_by_time', description: 'Query memories using natural language time expressions like "yesterday", "last week", "this morning", "before 3pm".', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, expression: { type: 'string', description: 'Natural language time expression like "yesterday", "last week", "before Monday"' }, limit: { type: 'number', description: 'Max results (default 10)', default: 10 }, }, required: ['sessionId', 'expression'], }, }, { name: 'recall_recent', description: 'Get the N most recent memories for a session — no query needed.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, limit: { type: 'number', description: 'Number of recent memories to return (default 20)', default: 20 }, }, required: ['sessionId'], }, }, { name: 'daily_summary', description: 'Returns a summary of memories for a given date (YYYY-MM-DD), or today if omitted.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, date: { type: 'string', description: 'ISO date string YYYY-MM-DD (optional, defaults to today)' }, }, required: ['sessionId'], }, }, { name: 'temporal_stats', description: 'Returns temporal statistics about when memories were created — frequency over time, most active periods.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, }, required: ['sessionId'], }, }, { name: 'export_memories', description: 'Export all session memories as markdown or JSON.', inputSchema: { type: 'object', properties: { sessionId: { type: 'string', description: 'Session identifier' }, format: { type: 'string', enum: ['markdown', 'json'], description: 'Export format (default "markdown")', default: 'markdown' }, }, required: ['sessionId'], }, }, ], - src/index.ts:309-312 (handler)The MCP request handler for the 'stats' tool — calls memory.stats() and returns the result as JSON text.
case 'stats': { const stats = await memory.stats(args.sessionId as string); return { content: [{ type: 'text', text: JSON.stringify(stats, null, 2) }] }; }