import { z } from "zod";
import * as fs from "fs/promises";
import * as path from "path";
import * as os from "os";
const MEMORY_FILE = path.join(os.homedir(), ".code-mcp-memory.json");
// Helper to ensure memory file exists
async function ensureMemoryFile() {
try {
await fs.access(MEMORY_FILE);
} catch {
await fs.writeFile(MEMORY_FILE, JSON.stringify({}, null, 2));
}
}
export const saveMemorySchema = {
name: "save_memory",
description: "Save a key-value pair to persistent memory. Use this to remember user preferences, project decisions, or important context across sessions.",
inputSchema: z.object({
key: z.string().describe("Unique key for this memory"),
value: z.string().describe("Value to store"),
project: z.string().optional().describe("Optional project scope for organizing memories")
})
};
export const readMemorySchema = {
name: "read_memory",
description: "Read a value from persistent memory by key.",
inputSchema: z.object({
key: z.string().describe("Key to retrieve")
})
};
export const listMemoriesSchema = {
name: "list_memories",
description: "List all saved memories, optionally filtered by project scope.",
inputSchema: z.object({
project: z.string().optional().describe("Filter by project scope")
})
};
export const clearMemorySchema = {
name: "clear_memory",
description: "Clear a specific memory by key, or clear all memories for a project.",
inputSchema: z.object({
key: z.string().optional().describe("Specific key to clear"),
project: z.string().optional().describe("Clear all memories for this project"),
clearAll: z.boolean().optional().describe("Clear ALL memories (use with caution)")
})
};
export async function saveMemoryHandler(args: any) {
await ensureMemoryFile();
const data = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
data[args.key] = { value: args.value, project: args.project, timestamp: new Date().toISOString() };
await fs.writeFile(MEMORY_FILE, JSON.stringify(data, null, 2));
return { content: [{ type: "text", text: `Saved memory: ${args.key}` }] };
}
export async function readMemoryHandler(args: any) {
await ensureMemoryFile();
const data = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
const item = data[args.key];
if (!item) return { content: [{ type: "text", text: "Key not found." }] };
return { content: [{ type: "text", text: JSON.stringify(item, null, 2) }] };
}
export async function listMemoriesHandler(args: any) {
await ensureMemoryFile();
const data = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
const entries = Object.entries(data);
let filtered = entries;
if (args.project) {
filtered = entries.filter(([_, v]: [string, any]) => v.project === args.project);
}
if (filtered.length === 0) {
return { content: [{ type: "text", text: "No memories found." }] };
}
const list = filtered.map(([key, v]: [string, any]) =>
`- **${key}**: ${v.value.substring(0, 50)}${v.value.length > 50 ? '...' : ''} (${v.project || 'global'})`
).join("\n");
return { content: [{ type: "text", text: `# Saved Memories\n\n${list}` }] };
}
export async function clearMemoryHandler(args: any) {
await ensureMemoryFile();
const data = JSON.parse(await fs.readFile(MEMORY_FILE, "utf-8"));
if (args.clearAll) {
await fs.writeFile(MEMORY_FILE, JSON.stringify({}, null, 2));
return { content: [{ type: "text", text: "All memories cleared." }] };
}
if (args.key) {
delete data[args.key];
await fs.writeFile(MEMORY_FILE, JSON.stringify(data, null, 2));
return { content: [{ type: "text", text: `Memory cleared: ${args.key}` }] };
}
if (args.project) {
for (const key of Object.keys(data)) {
if (data[key].project === args.project) {
delete data[key];
}
}
await fs.writeFile(MEMORY_FILE, JSON.stringify(data, null, 2));
return { content: [{ type: "text", text: `All memories for project '${args.project}' cleared.` }] };
}
return { content: [{ type: "text", text: "Specify key, project, or clearAll." }] };
}