### Run development server Source: https://github.com/puliczek/mcp-memory/blob/main/README.md Starts the local development environment. ```bash npm run dev ``` -------------------------------- ### Install project dependencies Source: https://github.com/puliczek/mcp-memory/blob/main/README.md Installs the necessary packages for the MCP Memory project. ```bash npm install ``` -------------------------------- ### Setup Copy Configuration Button Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html This function sets up a button to copy configuration code to the clipboard, dynamically inserting a provided URL. It handles success and error states with visual feedback. Ensure the button, code block, and URL span elements exist in the DOM. ```javascript document.addEventListener("DOMContentLoaded", () => { function setupConfigCopyButton(buttonId, codeBlockSelector, urlSpanId) { const copyButton = document.getElementById(buttonId); const codeBlock = document.querySelector(codeBlockSelector); if (!copyButton || !codeBlock) { console.warn(\`Could not setup copy button: ${buttonId} - elements not found. cies `); return; } const originalButtonHtml = copyButton.innerHTML; const originalButtonClasses = Array.from(copyButton.classList); copyButton.addEventListener("click", () => { const sseUrl = document.getElementById("sse-url")?.value || ""; const urlSpan = codeBlock.querySelector(` #${urlSpanId}`); let codeToCopy = ""; const codeLines = codeBlock.textContent.split("\n"); const urlPlaceholder = `YOUR_MCP_URL_HERE`; codeToCopy = codeLines .map((line) => { const indentation = line.match(/^\s*/) || ""; if (line.includes(urlPlaceholder)) { return `${indentation}"${sseUrl}"`; } return line; }) .join("\n"); if (!codeToCopy.includes(sseUrl) && codeBlock.textContent) { console.warn( "Placeholder replacement failed for", buttonId, "using raw textContent with manual replace." ); codeToCopy = codeBlock.textContent.replace(urlPlaceholder, `"${sseUrl}"`); } if (!sseUrl || sseUrl === "YOUR_MCP_URL_HERE" || sseUrl.startsWith("Error")) { alert("MCP Server URL is not available yet."); return; } navigator.clipboard .writeText(codeToCopy.trim()) .then(() => { copyButton.innerHTML = ` Copied!`; copyButton.className = ""; copyButton.classList.add(...originalButtonClasses); copyButton.classList.remove("bg-gray-700", "hover:bg-gray-600", "text-gray-300"); copyButton.classList.add("bg-amber-500", "hover:bg-amber-600", "text-white"); setTimeout(() => { copyButton.innerHTML = originalButtonHtml; copyButton.className = ""; copyButton.classList.add(...originalButtonClasses); }, 2000); }) .catch((err) => { console.error(`Failed to copy config for ${buttonId}: `, err); alert("Failed to copy code. Please copy it manually."); }); }); } setupConfigCopyButton("copy-cursor-config-button", "#cursor-tab pre code", "cursor-config-url"); setupConfigCopyButton("copy-cla ``` -------------------------------- ### REST API: Get All Memories Source: https://context7.com/puliczek/mcp-memory/llms.txt Retrieves all memories for a specific user from the D1 database. ```bash # Get all memories for a user curl -X GET "https://your-mcp-memory.workers.dev/{userId}/memories" # Response on success: { "success": true, "memories": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "content": "User prefers dark mode" }, { "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8", "content": "User's timezone is PST" } ] } # Response on error: { "success": false, "error": "Failed to retrieve memories" } ``` -------------------------------- ### GET /{userId}/memories Source: https://context7.com/puliczek/mcp-memory/llms.txt Retrieves all memories for a specific user from the D1 database. ```APIDOC ## GET /{userId}/memories ### Description Retrieves all memories for a specific user from the D1 database, ordered by creation date (newest first). ### Method GET ### Endpoint /{userId}/memories ### Parameters #### Path Parameters - **userId** (string) - Required - The unique identifier for the user ### Response #### Success Response (200) - **success** (boolean) - Status of the request - **memories** (array) - List of memory objects containing id and content #### Response Example { "success": true, "memories": [ { "id": "550e8400-e29b-41d4-a716-446655440000", "content": "User prefers dark mode" } ] } ``` -------------------------------- ### Create MCP Memory project via CLI Source: https://github.com/puliczek/mcp-memory/blob/main/README.md Initializes a new project using the Cloudflare CLI template. ```bash npm create cloudflare@latest --git https://github.com/puliczek/mcp-memory ``` -------------------------------- ### Initialize Configuration Copy Buttons Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Sets up click handlers for copy buttons associated with Claude and Windsurf configuration blocks. ```javascript ude-config-button", "#claude-tab pre code", "claude-config-url"); setupConfigCopyButton("copy-windsurf-config-button", "#windsurf-tab pre code", "windsurf-config-url"); }); ``` -------------------------------- ### Create Vectorize index Source: https://github.com/puliczek/mcp-memory/blob/main/README.md Sets up the Vectorize index required for similarity search with specific dimensions and metric. ```bash npx wrangler vectorize create mcp-memory-vectorize --dimensions 1024 --metric cosine ``` -------------------------------- ### Deploy MCP Memory to Cloudflare Workers Source: https://context7.com/puliczek/mcp-memory/llms.txt Commands for setting up and deploying the service, including Vectorize index creation and wrangler configuration. ```bash # Option 1: Create from template using Cloudflare CLI npm create cloudflare@latest --git https://github.com/puliczek/mcp-memory # Option 2: Clone and setup manually git clone https://github.com/puliczek/mcp-memory cd mcp-memory npm install # Create Vectorize index (required before first deploy) npx wrangler vectorize create mcp-memory-vectorize --dimensions 1024 --metric cosine # Run locally for development npm run dev # Deploy to Cloudflare Workers npm run deploy # wrangler.jsonc configuration highlights: { "name": "mcp-memory", "main": "src/index.ts", "d1_databases": [{ "binding": "DB", "database_name": "mcp-memory-db" }], "vectorize": [{ "binding": "VECTORIZE", "index_name": "mcp-memory-vectorize" }], "ai": { "binding": "AI" }, "durable_objects": { "bindings": [{ "class_name": "MyMCP", "name": "MCP_OBJECT" }] }, "unsafe": { "bindings": [{ "name": "RATE_LIMITER", "type": "ratelimit", "simple": { "limit": 100, "period": 60 } }] } } ``` -------------------------------- ### Configure Cursor IDE for MCP Memory Source: https://context7.com/puliczek/mcp-memory/llms.txt Add the server configuration to the global or project-specific mcp.json file. ```json // Global config: ~/.cursor/mcp.json // Project config: .cursor/mcp.json (in project root) { "mcpServers": { "mcp-memory": { "url": "https://your-mcp-memory.workers.dev/{your-user-id}/sse" } } } ``` -------------------------------- ### Configure Claude Desktop for mcp-memory Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Add this JSON object to your Claude Desktop claude_desktop_config.json file to integrate mcp-memory. Replace YOUR_MCP_URL_HERE with your server URL and ensure npx is available. ```json { "mcpServers": { "mcp-memory": { "command": "npx", "args": [ "mcp-remote", "YOUR_MCP_URL_HERE" ] } } } ``` -------------------------------- ### Configure Claude Desktop for MCP Memory Source: https://context7.com/puliczek/mcp-memory/llms.txt Update the Claude Desktop configuration file to use the mcp-remote bridge via npx. ```json // macOS: ~/Library/Application Support/Claude/claude_desktop_config.json // Windows: %APPDATA%\Claude\claude_desktop_config.json // Linux: ~/.config/Claude/claude_desktop_config.json { "mcpServers": { "mcp-memory": { "command": "npx", "args": [ "mcp-remote", "https://your-mcp-memory.workers.dev/{your-user-id}/sse" ] } } } ``` -------------------------------- ### Configure Windsurf for MCP Memory Source: https://context7.com/puliczek/mcp-memory/llms.txt Add the server URL to the mcp_config.json file in the Windsurf configuration directory. ```json // Config location: ~/.codeium/windsurf/mcp_config.json { "mcpServers": { "mcp-memory": { "serverUrl": "https://your-mcp-memory.workers.dev/{your-user-id}/sse" } } } ``` -------------------------------- ### MCP Client Configuration: Claude Desktop Source: https://context7.com/puliczek/mcp-memory/llms.txt Configure Claude Desktop to use MCP Memory using the mcp-remote bridge. This requires npx to be available in your environment. ```APIDOC ## MCP Client Configuration: Claude Desktop Configure Claude Desktop to use MCP Memory using the mcp-remote bridge. This requires npx to be available in your environment. ```json // macOS: ~/Library/Application Support/Claude/claude_desktop_config.json // Windows: %APPDATA%\Claude\claude_desktop_config.json // Linux: ~/.config/Claude/claude_desktop_config.json { "mcpServers": { "mcp-memory": { "command": "npx", "args": [ "mcp-remote", "https://your-mcp-memory.workers.dev/{your-user-id}/sse" ] } } } ``` ``` -------------------------------- ### Deploy worker Source: https://github.com/puliczek/mcp-memory/blob/main/README.md Deploys the application to the Cloudflare network. ```bash npm run deploy ``` -------------------------------- ### Direct API SSE Connection Source: https://context7.com/puliczek/mcp-memory/llms.txt Establish an SSE connection and send JSON-RPC requests to the postEndpointUri. ```bash # 1. Establish SSE connection curl -N "https://your-mcp-memory.workers.dev/{userId}/sse" # Server sends initial message event with: # data: {"postEndpointUri": "https://your-mcp-memory.workers.dev/{userId}/mcp"} # 2. Send JSON-RPC requests to the postEndpointUri curl -X POST "https://your-mcp-memory.workers.dev/{userId}/mcp" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "addToMCPMemory", "arguments": { "thingToRemember": "User prefers TypeScript over JavaScript" } }, "id": 1 }' # 3. Responses arrive as SSE message events on the original connection # data: {"jsonrpc":"2.0","result":{"content":[{"type":"text","text":"Remembered: User prefers TypeScript over JavaScript"}]},"id":1} ``` -------------------------------- ### Configure Windsurf (Codeium) for mcp-memory Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Add this JSON object to your Windsurf mcp_config.json file to connect mcp-memory. Replace YOUR_MCP_URL_HERE with your server URL. ```json { "mcpServers": { "mcp-memory": { "serverUrl": "YOUR_MCP_URL_HERE" } } } ``` -------------------------------- ### MCP Client Configuration: Windsurf Source: https://context7.com/puliczek/mcp-memory/llms.txt Configure Windsurf (Codeium) to use MCP Memory by adding the server URL to the mcp_config.json file. ```APIDOC ## MCP Client Configuration: Windsurf Configure Windsurf (Codeium) to use MCP Memory by adding the server URL to the mcp_config.json file. ```json // Config location: ~/.codeium/windsurf/mcp_config.json { "mcpServers": { "mcp-memory": { "serverUrl": "https://your-mcp-memory.workers.dev/{your-user-id}/sse" } } } ``` ``` -------------------------------- ### Configure Cursor for mcp-memory Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Add this JSON object to your Cursor mcp.json file to connect to your mcp-memory server. Ensure you replace YOUR_MCP_URL_HERE with your actual server URL. ```json { "mcpServers": { "mcp-memory": { "url": "YOUR_MCP_URL_HERE" } } } ``` -------------------------------- ### Fetch and Display Memories Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Fetches memories for a given user and dynamically renders them in a list. Includes handling for successful fetches, empty states, and errors. This function should be called when the memory list needs to be populated or refreshed. ```javascript console.log("Fetching memories..."); fetch(`/${userUuid}/memories`) .then((response) => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then((data) => { memoriesList.innerHTML = ""; // Clear previous content or loading message let hasMemories = false; if (data.success && data.memories && data.memories.length > 0) { hasMemories = true; data.memories.forEach((memory) => { const li = document.createElement("li"); // Added padding and subtle hover effect for light mode li.className = "memory-item px-4 py-3 sm:px-6 flex justify-between items-center hover:bg-gray-50 transition duration-150 ease-in-out"; li.dataset.memoryId = memory.id; const contentContainer = document.createElement("div"); contentContainer.className = "flex-grow mr-4 overflow-hidden"; // Added overflow hidden const contentSpan = document.createElement("span"); contentSpan.className = "memory-content text-sm text-gray-800 block truncate"; // Ensure text wraps/truncates nicely contentSpan.textContent = memory.content || "Empty memory"; contentContainer.appendChild(contentSpan); li.appendChild(contentContainer); const buttonContainer = document.createElement("div"); buttonContainer.className = "flex space-x-2 flex-shrink-0"; // Prevent buttons shrinking too much // Edit button - Light mode style const editButton = document.createElement("button"); editButton.textContent = "Edit"; editButton.className = "edit-button inline-flex items-center rounded border border-gray-300 bg-white px-2.5 py-1 text-xs font-medium text-gray-700 shadow-sm hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-orange-500 focus:ring-offset-2"; buttonContainer.appendChild(editButton); // Delete button - Light mode style const deleteButton = document.createElement("button"); deleteButton.textContent = "Delete"; deleteButton.className = "delete-button inline-flex items-center rounded border border-red-300 bg-red-50 px-2.5 py-1 text-xs font-medium text-red-700 shadow-sm hover:bg-red-100 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2"; buttonContainer.appendChild(deleteButton); li.appendChild(buttonContainer); memoriesList.appendChild(li); }); } else if (data.success) { // No memories found - Enhanced Empty State const li = document.createElement("li"); li.className = "px-6 py-12 sm:px-8 text-center"; // Increased padding const emptyStateContainer = document.createElement("div"); emptyStateContainer.className = "flex flex-col items-center space-y-3"; // SVG Icon (Example: Document Add icon from Heroicons) const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute("class", "h-12 w-12 text-gray-400"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "0 0 24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "1"); svgIcon.innerHTML = ``; emptyStateContainer.appendChild(svgIcon); const heading = document.createElement("h3"); heading.className = "text-lg font-semibold text-gray-800"; heading.textContent = "No Memories Stored Yet"; emptyStateContainer.appendChild(heading); const paragraph = document.createElement("p"); paragraph.className = "text-sm text-gray-500"; paragraph.textContent = "Add your first memory through your MCP client (like Cursor, Claude, etc.)."; emptyStateContainer.appendChild(paragraph); li.appendChild(emptyStateContainer); memoriesList.appendChild(li); } else { throw new Error(data.error || "Failed to fetch memories"); } }) .catch((error) => { console.error("Error fetching or processing memories:", error); memoriesList.innerHTML = ""; const li = document.createElement("li"); li.className = "px-4 py-4 sm:px-6 text-red-600"; // Adjusted error text color li.textContent = `Failed to load memories: ${error.message}`; memoriesList.appendChild(li); }); countdown = refreshIntervalSeconds; updateTimerDisplay(); ``` -------------------------------- ### Copy API URL to Clipboard Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Enables copying the SSE endpoint URL to the clipboard with visual feedback. ```javascript document.addEventListener("DOMContentLoaded", () => { const copyDirectApiButton = document.getElementById("copy-direct-api-url-button"); const directApiUrlCode = document.getElementById("direct-api-url"); if (copyDirectApiButton && directApiUrlCode) { const originalButtonHtml = copyDirectApiButton.innerHTML; copyDirectApiButton.addEventListener("click", () => { const urlToCopy = directApiUrlCode.textContent || ""; if (!urlToCopy || urlToCopy === "YOUR_SSE_ENDPOINT_HERE") { alert("URL not generated yet."); return; } navigator.clipboard .writeText(urlToCopy) .then(() => { copyDirectApiButton.innerHTML = ` C ``` -------------------------------- ### Initialize Memory Refresh Logic Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html This JavaScript code initializes the logic for refreshing memories. It sets up a countdown timer and interval for fetching memories, with configurable refresh intervals. It also includes basic error handling for missing UI elements or user identifiers. ```javascript document.addEventListener("DOMContentLoaded", () => { const memoriesList = document.getElementById("memories-list"); const refreshTimerSpan = document.getElementById("refresh-timer"); const refreshButton = document.getElementById("refresh-button"); const userUuid = localStorage.getItem("mcpUserUuid"); const refreshIntervalSeconds = 30; let countdown = refreshIntervalSeconds; let fetchIntervalId = null; let timerIntervalId = null; function updateTimerDisplay() { if (refreshTimerSpan) { refreshTimerSpan.textContent = `(${countdown}s) `; } } function fetchAndDisplayMemories() { if (!memoriesList || !userUuid) { console.error("Missing memories list element or user UUID."); if (memoriesList) { memoriesList.innerHTML = ""; // Clear loading const li = document.createElement("li"); li.className = "px-4 py-4 sm:px-6 text-red-600"; // Use a suitable error color li.textCont ``` -------------------------------- ### Copy SSE URL to Clipboard Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html This JavaScript code adds an event listener to a button that copies the generated SSE URL to the user's clipboard. It provides visual feedback by changing the button's text and style upon successful copy and reverts after a delay. Error handling is included for copy failures. ```javascript if (copyButton && sseUrlInput && userUuid) { copyButton.addEventListener("click", () => { navigator.clipboard .writeText(sseUrl) .then(() => { // Use specific classes for the "Copied" state copyButton.innerHTML = ` Copied!`; copyButton.classList.remove("bg-orange-600", "hover:bg-orange-700"); copyButton.classList.add("bg-amber-500", "hover:bg-amber-600"); // Green for success setTimeout(() => { copyButton.innerHTML = originalButtonHtml; // Revert to original text + icon copyButton.classList.remove("bg-amber-500", "hover:bg-amber-600"); copyButton.classList.add("bg-orange-600", "hover:bg-orange-700"); }, 2000); }) .catch((err) => { console.error("Failed to copy URL: ", err); alert("Failed to copy URL. Please copy it manually."); }); }); } else if (copyButton) { copyButton.disabled = true; copyButton.title = "Cannot copy URL"; } ``` -------------------------------- ### MCP Tool: searchMCPMemory Source: https://context7.com/puliczek/mcp-memory/llms.txt Searches the user's persistent memory layer for relevant information using semantic matching. ```APIDOC ## MCP Tool: searchMCPMemory ### Description Searches the user's persistent memory layer for relevant information using semantic matching. Returns up to 10 matches ranked by similarity score, filtering out results below 0.5 similarity threshold. ### Parameters #### Request Body - **informationToGet** (string) - Required - The search query ### Response #### Success Response (200) - **content** (array) - Array containing a text object with found memories and their similarity scores, or a 'No relevant memories found' message. ``` -------------------------------- ### MCP Client Configuration: Cursor Source: https://context7.com/puliczek/mcp-memory/llms.txt Configure Cursor IDE to use MCP Memory by adding the server configuration to your mcp.json file. This can be done globally or per-project. ```APIDOC ## MCP Client Configuration: Cursor Configure Cursor IDE to use MCP Memory by adding the server configuration to your mcp.json file. The configuration can be added globally or per-project. ```json // Global config: ~/.cursor/mcp.json // Project config: .cursor/mcp.json (in project root) { "mcpServers": { "mcp-memory": { "url": "https://your-mcp-memory.workers.dev/{your-user-id}/sse" } } } ``` ``` -------------------------------- ### Deployment: Cloudflare Workers Source: https://context7.com/puliczek/mcp-memory/llms.txt Deploy your own instance of MCP Memory to Cloudflare using the CLI or one-click deploy button. The Vectorize index must be configured with 1024 dimensions and cosine similarity metric. ```APIDOC ## Deployment: Cloudflare Workers Deploy your own instance of MCP Memory to Cloudflare using the CLI or one-click deploy button. The Vectorize index must be configured with 1024 dimensions and cosine similarity metric. ```bash # Option 1: Create from template using Cloudflare CLI npm create cloudflare@latest --git https://github.com/puliczek/mcp-memory # Option 2: Clone and setup manually git clone https://github.com/puliczek/mcp-memory cd mcp-memory npm install # Create Vectorize index (required before first deploy) npx wrangler vectorize create mcp-memory-vectorize --dimensions 1024 --metric cosine # Run locally for development npm run dev # Deploy to Cloudflare Workers npm run deploy # wrangler.jsonc configuration highlights: { "name": "mcp-memory", "main": "src/index.ts", "d1_databases": [{ "binding": "DB", "database_name": "mcp-memory-db" }], "vectorize": [{ "binding": "VECTORIZE", "index_name": "mcp-memory-vectorize" }], "ai": { "binding": "AI" }, "durable_objects": { "bindings": [{ "class_name": "MyMCP", "name": "MCP_OBJECT" }] }, "unsafe": { "bindings": [{ "name": "RATE_LIMITER", "type": "ratelimit", "simple": { "limit": 100, "period": 60 } }] } } ``` ``` -------------------------------- ### searchMCPMemory Tool Implementation Source: https://context7.com/puliczek/mcp-memory/llms.txt Performs semantic search on stored memories using Vectorize, filtering results by a minimum similarity score of 0.5. ```typescript // MCP Tool Schema { name: "searchMCPMemory", parameters: { informationToGet: z.string() // The search query } } // Internal implementation flow: // 1. Generate embedding for the search query const queryVector = await generateEmbeddings(query, env); // 2. Search Vectorize with user's namespace const results = await env.VECTORIZE.query(queryVector, { namespace: userId, topK: 10, returnMetadata: "all" }); // 3. Filter by minimum similarity score (0.5) const memories = results.matches .filter(match => match.score > 0.5) .map(match => ({ content: match.metadata.content, score: match.score, id: match.id })); // Response with matches: { content: [{ type: "text", text: "Found memories:\n" + memories.map(m => `${m.content} (score: ${m.score.toFixed(4)})` ).join("\n") }] } // Response when no matches: { content: [{ type: "text", text: "No relevant memories found." }] } ``` -------------------------------- ### Direct API: SSE Connection Source: https://context7.com/puliczek/mcp-memory/llms.txt Establish a Server-Sent Events connection for direct MCP protocol communication. The connection provides a postEndpointUri for sending JSON-RPC requests. ```APIDOC ## Direct API: SSE Connection Establish a Server-Sent Events connection for direct MCP protocol communication. The connection provides a postEndpointUri for sending JSON-RPC requests. ```bash # 1. Establish SSE connection curl -N "https://your-mcp-memory.workers.dev/{userId}/sse" # Server sends initial message event with: # data: {"postEndpointUri": "https://your-mcp-memory.workers.dev/{userId}/mcp"} # 2. Send JSON-RPC requests to the postEndpointUri curl -X POST "https://your-mcp-memory.workers.dev/{userId}/mcp" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "method": "tools/call", "params": { "name": "addToMCPMemory", "arguments": { "thingToRemember": "User prefers TypeScript over JavaScript" } }, "id": 1 }' # 3. Responses arrive as SSE message events on the original connection # data: {"jsonrpc":"2.0","result":{"content":[{"type":"text","text":"Remembered: User prefers TypeScript over JavaScript"}]},"id":1} ``` ``` -------------------------------- ### PUT /{userId}/memories/{memoryId} Source: https://context7.com/puliczek/mcp-memory/llms.txt Updates the content of an existing memory for a user. ```APIDOC ## PUT /{userId}/memories/{memoryId} ### Description Updates the content of an existing memory for a user. This updates both the D1 database record and regenerates the vector embedding in Vectorize. ### Method PUT ### Endpoint /{userId}/memories/{memoryId} ### Parameters #### Path Parameters - **userId** (string) - Required - The unique identifier for the user - **memoryId** (string) - Required - The unique identifier for the memory record #### Request Body - **content** (string) - Required - The updated memory content ``` -------------------------------- ### Persist Memory Changes Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Sends updated memory content to the server via a PUT request and handles UI feedback. ```javascript function saveChanges(listItem) { const memoryId = listItem.dataset.memoryId; const input = listItem.querySelector(".memory-input"); const saveButton = listItem.querySelector(".save-button"); const newContent = input.value.trim(); if (!newContent) { alert("Memory content cannot be empty."); input.focus(); return; } saveButton.disabled = true; saveButton.textContent = "Saving..."; fetch(`/${userUuid}/memories/${memoryId}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ content: newContent }), }) .then((response) => { if (!response.ok) { return response .json() .then((err) => { throw new Error(err.error || `HTTP error! status: ${response.status}`); }) .catch(() => { throw new Error(`HTTP error! status: ${response.status}`); }); } return response.json(); }) .then((data) => { if (data.success) { console.log(`Memory ${memoryId} updated successfully.`); exitEditMode(listItem, newContent); } else { throw new Error(data.error || "Update failed on the server."); } }) .catch((error) => { console.error("Error updating memory:", error); alert(`Failed to update memory: ${error.message}`); saveButton.disabled = false; saveButton.textContent = "Save"; // Keep Save text on error }); } ``` -------------------------------- ### addToMCPMemory Tool Implementation Source: https://context7.com/puliczek/mcp-memory/llms.txt Stores user information by generating vector embeddings and saving them to both Vectorize and D1. ```typescript // MCP Tool Schema { name: "addToMCPMemory", parameters: { thingToRemember: z.string() // The content to store in memory } } // Internal implementation flow: // 1. Generate vector embedding using @cf/baai/bge-m3 model const memoryId = await storeMemory(thingToRemember, userId, env); // 2. Store in Vectorize with user namespace await env.VECTORIZE.upsert([{ id: memoryId, values: vectorEmbedding, namespace: userId, metadata: { content: thingToRemember } }]); // 3. Store original text in D1 database await env.DB.prepare( "INSERT INTO memories (id, userId, content) VALUES (?, ?, ?)" ).bind(memoryId, userId, content).run(); // Response on success: { content: [{ type: "text", text: "Remembered: " + thingToRemember }] } ``` -------------------------------- ### Manage Refresh Intervals Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Handles automatic data fetching and countdown timer updates. ```javascript // Timer countdown logic function startTimer() { if (timerIntervalId) clearInterval(timerIntervalId); timerIntervalId = setInterval(() => { countdown--; if (countdown < 0) { // Reset when it hits 0 or below countdown = refreshIntervalSeconds; } updateTimerDisplay(); }, 1000); } // Function to reset the automatic fetch interval function resetAutoRefresh() { if (fetchIntervalId) clearInterval(fetchIntervalId); fetchIntervalId = setInterval(fetchAndDisplayMemories, refreshIntervalSeconds * 1000); countdown = refreshIntervalSeconds; updateTimerDisplay(); startTimer(); } // Initial setup if (userUuid && memoriesList && refreshTimerSpan && refreshButton) { fetchAndDisplayMemories(); // Initial fetch resetAutoRefresh(); // Start intervals and timer refreshButton.addEventListener("click", () => { console.log("Manual refresh triggered."); fetchAndDisplayMemories(); // Fetch immediately resetAutoRefresh(); // Reset the interval and timer }); // Event delegation for memory list actions memoriesList.addEventListener("click", function (event) { ``` -------------------------------- ### API Response Formats Source: https://context7.com/puliczek/mcp-memory/llms.txt Standard JSON response structures for successful operations, missing memory, and validation errors. ```json { "success": true } ``` ```json { "success": false, "error": "Memory with ID {memoryId} not found for user {userId} or content unchanged." } ``` ```json { "success": false, "error": "Invalid or missing content in request body" } ``` -------------------------------- ### Handle Memory Item Interactions Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Manages click events for editing, saving, and deleting memory items, including dynamic DOM updates for empty states. ```javascript ) { const target = event.target; const listItem = target.closest(".memory-item"); if (!listItem) return; const memoryId = listItem.dataset.memoryId; // Edit/Save Click if (target.classList.contains("edit-button")) { enterEditMode(listItem); } else if (target.classList.contains("save-button")) { saveChanges(listItem); } // Delete/Cancel Click else if (target.classList.contains("delete-button")) { if (confirm(`Are you sure you want to delete this memory?`)) { const deleteButton = target; deleteButton.disabled = true; deleteButton.textContent = "Deleting..."; fetch(`/${userUuid}/memories/${memoryId}`, { method: "DELETE" }) .then((response) => { if (!response.ok) { return response .json() .then((err) => { throw new Error(err.error || `HTTP error! status: ${response.status}`); }) .catch(() => { throw new Error(`HTTP error! status: ${response.status}`); }); } return response.json(); }) .then((data) => { if (data.success) { console.log(`Memory ${memoryId} deleted successfully.`); listItem.remove(); // Check if list is now empty after deletion const hasMemories = memoriesList.querySelector(".memory-item") !== null; if (!hasMemories) { const li = document.createElement("li"); li.className = "px-6 py-12 sm:px-8 text-center"; // Match the enhanced empty state style const emptyStateContainer = document.createElement("div"); emptyStateContainer.className = "flex flex-col items-center space-y-3"; // SVG Icon const svgIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); svgIcon.setAttribute("class", "h-12 w-12 text-gray-400"); svgIcon.setAttribute("fill", "none"); svgIcon.setAttribute("viewBox", "24 24"); svgIcon.setAttribute("stroke", "currentColor"); svgIcon.setAttribute("stroke-width", "1"); svgIcon.innerHTML = ``; emptyStateContainer.appendChild(svgIcon); const heading = document.createElement("h3"); heading.className = "text-lg font-semibold text-gray-800"; heading.textContent = "No Memories Stored Yet"; emptyStateContainer.appendChild(heading); const paragraph = document.createElement("p"); paragraph.className = "text-sm text-gray-500"; paragraph.textContent = "Add your first memory through your connected MCP client (like Cursor, Claude, etc.)."; emptyStateContainer.appendChild(paragraph); li.appendChild(emptyStateContainer); memoriesList.appendChild(li); } } else { throw new Error(data.error || "Deletion failed on the server."); } }) .catch((error) => { console.error("Error deleting memory:", error); alert(`Failed to delete memory: ${error.message}`); deleteButton.disabled = false; deleteButton.textContent = "Delete"; // Revert button text on error }); } } else if (target.classList.contains("cancel-button")) { const originalContent = listItem.dataset.originalContent || ""; // Fallback if somehow missing exitEditMode(listItem, originalContent); } }); // Handle Enter/Escape key press in edit mode input field memoriesList.addEventListener("keydown", function (event) { if (event.key === "Enter" && event.target.classList.contains("memory-input")) { event.preventDefault(); // Prevent form submission if inside a form const listItem = event.target.closest(".memory-item"); if (listItem) { saveChanges(listItem); } } else if (event.key === "Escape" && event.target.classList.contains("memory-input")) { event.preventDefault(); // Prevent potential browser actions const listItem = event.target.closest(".memory-item"); if (listItem) { const originalContent = listItem.dataset.originalContent || ""; exitEditMode(listItem, originalContent); } } }); } else { // Handle missing elements or UUID on initial load if (refreshTimerSpan) refreshTimerSpan.textContent = "Setup Error"; if (memoriesList && !userUuid) { memoriesList.innerHTML = ""; const li = document.createElement("li"); li.className = "px-4 py-4 sm:px-6 text-red-600"; // Use error color li.textContent = "Could not identify user to load memories."; memoriesList.appendChild(li); } console.error("Initial setup failed: Missing critical elements or UUID."); }); ``` -------------------------------- ### DELETE /{userId}/memories/{memoryId} Source: https://context7.com/puliczek/mcp-memory/llms.txt Deletes a specific memory for a user from both D1 database and Vectorize index. ```APIDOC ## DELETE /{userId}/memories/{memoryId} ### Description Deletes a specific memory for a user from both D1 database and Vectorize index to maintain consistency. ### Method DELETE ### Endpoint /{userId}/memories/{memoryId} ### Parameters #### Path Parameters - **userId** (string) - Required - The unique identifier for the user - **memoryId** (string) - Required - The unique identifier for the memory record ### Response #### Success Response (200) - **success** (boolean) - Status of the request ``` -------------------------------- ### Update SSE Endpoint URL and Config Placeholders Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html This JavaScript code updates an input field with the Server-Sent Events (SSE) URL based on the current origin and a user's UUID. It also updates placeholder text for various configuration URLs (Claude, Cursor, Windsurf, Direct API) to reflect the generated SSE URL. ```javascript if (sseUrlInput) { const currentOrigin = window.location.origin; if (userUuid) { sseUrl = `${currentOrigin}/${userUuid}/sse`; sseUrlInput.value = sseUrl; // Update Claude config URL placeholder const claudeUrlSpan = document.getElementById("claude-config-url"); if (claudeUrlSpan) { claudeUrlSpan.textContent = sseUrl; } // Update Cursor config URL placeholder const cursorUrlSpan = document.getElementById("cursor-config-url"); if (cursorUrlSpan) { cursorUrlSpan.textContent = sseUrl; } // Update Windsurf config URL placeholder const windsurfUrlSpan = document.getElementById("windsurf-config-url"); if (windsurfUrlSpan) { windsurfUrlSpan.textContent = sseUrl; } // Update Direct API URL placeholder const directApiUrlCode = document.getElementById("direct-api-url"); if (directApiUrlCode) { directApiUrlCode.textContent = sseUrl; } } else { sseUrlInput.value = "Error generating user identifier."; console.error("Could not generate or retrieve UUID."); if (copyButton) { copyButton.disabled = true; copyButton.title = "Cannot copy URL without a user identifier"; } sseUrlInput.readOnly = true; // Keep readonly even on error } } ``` -------------------------------- ### Handle Tab Switching Logic Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html This JavaScript code manages the display of tabbed content. It adds event listeners to tab buttons to show the corresponding content and update active tab styles. Ensure HTML elements have appropriate classes and data attributes. ```javascript document.addEventListener("DOMContentLoaded", function () { const tabs = document.querySelectorAll(".tab-button"); const tabContents = document.querySelectorAll(".tab-content"); tabs.forEach((tab) => { tab.addEventListener("click", function () { const target = document.querySelector(tab.dataset.tabTarget); // Hide all tab contents tabContents.forEach((tc) => { tc.classList.add("hidden"); }); // Show the target tab content if (target) { target.classList.remove("hidden"); } // Update tab button styles tabs.forEach((t) => { t.classList.remove("border-orange-500", "text-orange-600"); t.classList.add("border-transparent", "text-gray-500", "hover:text-gray-700", "hover:border-gray-300"); t.removeAttribute("aria-current"); }); // Style the active tab button tab.classList.add("border-orange-500", "text-orange-600"); tab.classList.remove("border-transparent", "text-gray-500", "hover:text-gray-700", "hover:border-gray-300"); tab.setAttribute("aria-current", "page"); }); }); }); ``` -------------------------------- ### MCP Tool: addToMCPMemory Source: https://context7.com/puliczek/mcp-memory/llms.txt Stores user information in the persistent memory layer using semantic vector embeddings. ```APIDOC ## MCP Tool: addToMCPMemory ### Description Stores important user information in a persistent memory layer. Use this tool when a user explicitly asks to remember something, when you detect significant user preferences, or when technical details emerge. ### Parameters #### Request Body - **thingToRemember** (string) - Required - The content to store in memory ### Response #### Success Response (200) - **content** (array) - Array containing a text object confirming the stored memory. ``` -------------------------------- ### REST API: Update Memory Source: https://context7.com/puliczek/mcp-memory/llms.txt Updates memory content and regenerates the corresponding vector embedding. ```bash # Update a memory's content curl -X PUT "https://your-mcp-memory.workers.dev/{userId}/memories/{memoryId}" \ -H "Content-Type: application/json" \ -d '{"content": "Updated memory content here"}' ``` -------------------------------- ### Manage Edit Mode State Source: https://github.com/puliczek/mcp-memory/blob/main/static/index.html Functions to toggle input fields and button styles when entering or exiting edit mode for memory items. ```javascript tent; input.className = "memory-input block w-full rounded-md border-gray-300 bg-white py-1 px-2 text-gray-900 shadow-sm focus:border-orange-500 focus:ring focus:ring-orange-500 focus:ring-opacity-50 sm:text-sm"; // Light mode input contentContainer.replaceChild(input, contentSpan); input.focus(); input.select(); // Select text for easy replacement // Change buttons to Save/Cancel - Light mode styling editButton.textContent = "Save"; // Remove old styles, add new Save button styles (green) editButton.classList.remove( "edit-button", "border-gray-300", "bg-white", "text-gray-700", "hover:bg-gray-50" ); editButton.classList.add( "save-button", "border-green-500", "bg-green-50", "text-green-700", "hover:bg-green-100", "focus:ring-green-500" ); deleteButton.textContent = "Cancel"; // Remove old Delete styles, add new Cancel button styles (neutral gray) deleteButton.classList.remove( "delete-button", "border-red-300", "bg-red-50", "text-red-700", "hover:bg-red-100", "focus:ring-red-500" ); deleteButton.classList.add( "cancel-button", "border-gray-300", "bg-white", "text-gray-700", "hover:bg-gray-50", "focus:ring-orange-500" ); // Neutral style for cancel } function exitEditMode(listItem, newContent) { const contentContainer = listItem.querySelector(".flex-grow"); const input = contentContainer.querySelector(".memory-input"); const buttonContainer = listItem.querySelector(".flex.space-x-2"); const saveButton = buttonContainer.querySelector(".save-button"); const cancelButton = buttonContainer.querySelector(".cancel-button"); // Replace input with span const contentSpan = document.createElement("span"); contentSpan.className = "memory-content text-sm text-gray-800 block truncate"; // Reapply correct light mode class contentSpan.textContent = newContent; contentContainer.replaceChild(contentSpan, input); delete listItem.dataset.originalContent; // Change buttons back to Edit/Delete - Light mode styling saveButton.textContent = "Edit"; // Remove Save styles, add back Edit styles saveButton.classList.remove( "save-button", "border-green-500", "bg-green-50", "text-green-700", "hover:bg-green-100", "focus:ring-green-500" ); saveButton.classList.add( "edit-button", "border-gray-300", "bg-white", "text-gray-700", "hover:bg-gray-50", "focus:ring-orange-500" ); saveButton.disabled = false; cancelButton.textContent = "Delete"; // Remove Cancel styles, add back Delete styles cancelButton.classList.remove( "cancel-button", "border-gray-300", "bg-white", "text-gray-700", "hover:bg-gray-50", "focus:ring-orange-500" ); cancelButton.classList.add( "delete-button", "border-red-300", "bg-red-50", "text-red-700", "hover:bg-red-100", "focus:ring-red-500" ); } ``` -------------------------------- ### REST API: Delete Memory Source: https://context7.com/puliczek/mcp-memory/llms.txt Removes a specific memory from both the D1 database and the Vectorize index. ```bash # Delete a specific memory curl -X DELETE "https://your-mcp-memory.workers.dev/{userId}/memories/{memoryId}" # Response on success: { "success": true } # Response on error: { "success": false, "error": "Failed to delete memory" } ```