How the MCP Memory Server Handles Backward Compatibility Migration
The MCP Memory server automatically migrates legacy memory.json files to the modern memory.jsonl format during startup by detecting the old file, renaming it while preserving contents, and logging the transition, requiring no manual intervention from users.
The MCP Memory server in the modelcontextprotocol/servers repository stores knowledge-graph data in a JSON Lines format for improved efficiency and append-only operations. To ensure seamless backward compatibility migration for existing deployments, the server implements an automatic migration routine in src/memory/index.ts that upgrades legacy storage files without breaking existing data or requiring user action.
Migration Architecture in src/memory/index.ts
The core migration logic resides in the ensureMemoryFilePath function. This utility determines the correct file path and handles format transitions during server initialization by detecting file presence and executing conditional rename operations.
Detecting Legacy vs. Modern Formats
The function distinguishes between two storage formats:
- Legacy format:
memory.json(plain JSON structure) - Modern format:
memory.jsonl(JSON Lines for append-only efficiency)
According to the source code at lines 22-25, the function constructs both paths relative to the module directory. When no custom path is specified via environment variables, it checks for the existence of these files to determine if migration is necessary.
Environment Variable Override
Before checking for legacy files, the function respects the MEMORY_FILE_PATH environment variable. As implemented at lines 15-20, if this variable is set, the function resolves the specified absolute or relative path and returns it immediately, skipping all migration logic. This allows users to maintain custom storage locations outside the default migration workflow.
Automatic Migration Workflow
When the server starts, the migration routine executes automatically through the following decision tree implemented in lines 26-43:
- Both files exist: The server uses
memory.jsonlexclusively, ignoring the legacy file without migration or console output. - Only legacy file exists: The server logs a detection message, executes
fs.rename()at line 36 to renamememory.jsontomemory.jsonl, logs completion, and proceeds with the new file. - No legacy file: The server returns the default
memory.jsonlpath, creating the file later when data is first saved.
This approach ensures the migration is idempotent and non-destructive, preserving exact file contents during the rename operation without parsing or transforming the JSON data.
Validating Migration Behavior
The test suite in src/memory/__tests__/file-path.test.ts validates all migration scenarios to ensure reliability:
- Environment variable precedence: Confirms
MEMORY_FILE_PATHbypasses migration logic for absolute, relative, and Windows paths. - Clean installation: Verifies behavior when neither file exists, returning the default path.
- Legacy-only migration: Ensures
memory.jsonis renamed tomemory.jsonlwith exact content preservation and proper log output. - Coexistence handling: Confirms no migration occurs when both files exist, preventing accidental overwrites of existing modern format data.
- Data integrity: Validates that file contents remain bit-for-bit identical after migration, confirming the rename operation does not modify data.
Implementation Examples
Starting the Server with Automatic Migration
When you start the Memory server, the migration runs automatically if needed:
import { ensureMemoryFilePath } from "./src/memory/index.js";
async function start() {
// Triggers migration if memory.json exists
const memoryPath = await ensureMemoryFilePath();
console.log("Using memory file:", memoryPath);
// Server initialization continues...
}
start();
Console output when migration occurs:
DETECTED: Found legacy memory.json file, migrating to memory.jsonl for JSONL format compatibility
COMPLETED: Successfully migrated memory.json to memory.jsonl
Using memory file: /path/to/memory.jsonl
Bypassing Migration with Custom Paths
To use a custom storage location and skip automatic migration:
# Unix/Linux
export MEMORY_FILE_PATH=/data/persistent-memory.jsonl
node src/memory/index.js
# Windows PowerShell
$env:MEMORY_FILE_PATH = "C:\data\persistent-memory.jsonl"
node src/memory/index.js
When MEMORY_FILE_PATH is set, the server resolves the absolute path and ignores the default migration logic entirely, as specified in the ensureMemoryFilePath implementation.
Programmatic Migration Testing
Simulate the migration in a test environment to verify behavior:
import { promises as fs } from "fs";
import path from "path";
import { ensureMemoryFilePath, defaultMemoryPath } from "./src/memory/index.js";
async function testMigration() {
// Create legacy file with sample data
const legacyPath = path.join(process.cwd(), "memory.json");
await fs.writeFile(legacyPath, '{"entities":[],"relations":[]}');
// Execute migration
await ensureMemoryFilePath();
// Verify migration success
const newContent = await fs.readFile(defaultMemoryPath, "utf-8");
console.assert(newContent === '{"entities":[],"relations":[]}');
console.log("Migration verified successfully");
}
testMigration();
Summary
- The MCP Memory server automatically handles backward compatibility migration by detecting legacy
memory.jsonfiles and renaming them tomemory.jsonlduring startup. - The
ensureMemoryFilePathfunction insrc/memory/index.tsimplements this logic at lines 26-43, specifically performing the atomic rename operation at line 36. - Migration only occurs when exclusively the legacy file exists; if both files exist, the server uses the modern format without modification to prevent data loss.
- The
MEMORY_FILE_PATHenvironment variable overrides all migration logic, allowing custom storage locations without triggering legacy file detection. - Comprehensive tests in
src/memory/__tests__/file-path.test.tsverify idempotent behavior and data preservation across all migration scenarios.
Frequently Asked Questions
What triggers the MCP Memory server backward compatibility migration?
The migration triggers automatically when the server starts and detects a memory.json file in the module directory without an existing memory.jsonl file. The ensureMemoryFilePath function performs this check during initialization, renaming the legacy file to the new JSON Lines format while preserving all contents exactly and logging the transition to stderr.
Will I lose data during the automatic migration from memory.json to memory.jsonl?
No. The migration uses a simple file rename operation at line 36 of src/memory/index.ts, which preserves the exact byte content of the original file. The test suite confirms that data remains bit-for-bit identical after migration, and because the operation uses the filesystem's native rename, it is atomic and does not parse or transform the JSON structure.
How do I prevent automatic migration and use a custom memory file location?
Set the MEMORY_FILE_PATH environment variable to your desired absolute or relative path. When this variable is present, the server uses the specified path directly and skips all legacy file detection and migration logic, as implemented in lines 15-20 of the source code. This is the recommended approach for production deployments requiring specific storage volumes or network paths.
What happens if both memory.json and memory.jsonl exist in the directory?
If both files exist simultaneously, the server uses memory.jsonl exclusively and performs no migration. This prevents accidental overwrites of existing data and allows administrators to manually manage the transition if needed. The server produces no console output in this scenario, treating the presence of both files as a standard operational state where the modern format takes precedence.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →