Skip to main content
Glama

mem_save

Records workflow memories with FIFO eviction to maintain up to 1000 tokens, capturing what was done, why, and outcomes for AI-assisted task tracking.

Instructions

Record workflow memories with FIFO eviction (keep ≤ 1000 tokens)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathYesProject path (provided by AI)
entriesYesList of memory entries

Implementation Reference

  • The handler function for 'mem_save' tool. It appends new memory entries to memory.json, enforces a 1000 token limit via FIFO eviction, updates metadata, and returns success/error response.
    async ({ projectPath, entries }) => { try { // 1. 讀取現有 memory.json const memoryPath = path.join(projectPath, '.memory', 'memory.json'); let memory: Memory = readJSON(memoryPath) || { entries: [], meta: { total_entries: 0, estimated_tokens: 0, last_updated: "" } }; // 2. 新增 entries memory.entries.push(...entries); // 3. 計算總 tokens let totalTokens = memory.entries.reduce( (sum, e) => sum + estimateTokens(e), 0 ); // 4. FIFO 刪除(保持 ≤ 1000 tokens) while (totalTokens > 1000 && memory.entries.length > 1) { const removed = memory.entries.shift()!; totalTokens -= estimateTokens(removed); } // 5. 更新 meta memory.meta = { total_entries: memory.entries.length, estimated_tokens: totalTokens, last_updated: new Date().toISOString().split('T')[0] }; // 6. 寫回檔案 writeJSON(memoryPath, memory); return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, message: `Recorded ${entries.length} entries, current total ${memory.meta.total_entries} entries (approx. ${memory.meta.estimated_tokens} tokens)` }, null, 2) }] }; } catch (error) { return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, message: `Write failed: ${error}` }, null, 2) }], isError: true }; } }
  • Input schema for 'mem_save' tool using Zod, defining projectPath and entries array with structured fields.
    { projectPath: z.string().describe("Project path (provided by AI)"), entries: z.array(z.object({ what: z.string().describe("What was done"), why: z.string().describe("Why it was done"), outcome: z.string().describe("What was the outcome"), task_context: z.string().optional().describe("Task context"), constraints: z.string().optional().describe("Constraints"), dependencies: z.string().optional().describe("Dependencies") })).describe("List of memory entries") }, async ({ projectPath, entries }) => {
  • src/index.ts:66-140 (registration)
    Registration of the 'mem_save' tool on the MCP server using server.tool(), including name, description, schema, and handler.
    server.tool( "mem_save", "Record workflow memories with FIFO eviction (keep ≤ 1000 tokens)", { projectPath: z.string().describe("Project path (provided by AI)"), entries: z.array(z.object({ what: z.string().describe("What was done"), why: z.string().describe("Why it was done"), outcome: z.string().describe("What was the outcome"), task_context: z.string().optional().describe("Task context"), constraints: z.string().optional().describe("Constraints"), dependencies: z.string().optional().describe("Dependencies") })).describe("List of memory entries") }, async ({ projectPath, entries }) => { try { // 1. 讀取現有 memory.json const memoryPath = path.join(projectPath, '.memory', 'memory.json'); let memory: Memory = readJSON(memoryPath) || { entries: [], meta: { total_entries: 0, estimated_tokens: 0, last_updated: "" } }; // 2. 新增 entries memory.entries.push(...entries); // 3. 計算總 tokens let totalTokens = memory.entries.reduce( (sum, e) => sum + estimateTokens(e), 0 ); // 4. FIFO 刪除(保持 ≤ 1000 tokens) while (totalTokens > 1000 && memory.entries.length > 1) { const removed = memory.entries.shift()!; totalTokens -= estimateTokens(removed); } // 5. 更新 meta memory.meta = { total_entries: memory.entries.length, estimated_tokens: totalTokens, last_updated: new Date().toISOString().split('T')[0] }; // 6. 寫回檔案 writeJSON(memoryPath, memory); return { content: [{ type: "text" as const, text: JSON.stringify({ success: true, message: `Recorded ${entries.length} entries, current total ${memory.meta.total_entries} entries (approx. ${memory.meta.estimated_tokens} tokens)` }, null, 2) }] }; } catch (error) { return { content: [{ type: "text" as const, text: JSON.stringify({ success: false, message: `Write failed: ${error}` }, null, 2) }], isError: true }; } } );
  • Helper function to estimate token count for memory entries, used in eviction logic.
    function estimateTokens(entry: MemoryEntry): number { const text = JSON.stringify(entry); const chinese = (text.match(/[\u4e00-\u9fa5]/g) || []).length; const english = (text.match(/[a-zA-Z]/g) || []).length; const symbols = text.length - chinese - english; return Math.ceil(chinese * 1.3 + english * 0.3 + symbols * 0.6); }
  • Helper function to write Memory data to JSON file, ensuring directory exists.
    function writeJSON(filePath: string, data: Memory): void { const dir = path.dirname(filePath); if (!fs.existsSync(dir)) { fs.mkdirSync(dir, { recursive: true }); } fs.writeFileSync(filePath, JSON.stringify(data, null, 2), 'utf-8'); }

Other Tools

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Artin0123/workflow-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server