MCP Memory Service Backup Scheduler Architecture and Configuration Guide
The MCP Memory Service implements a four-layer asyncio-driven backup architecture that automates SQLite database snapshots via environment variables and exposes manual controls through FastAPI endpoints.
The doobidoo/mcp-memory-service repository provides a production-ready backup scheduler designed to protect vector store data without manual intervention. This guide examines the scheduler's internal architecture—from configuration parsing to the periodic execution loop—and provides concrete examples for deploying automated backups in your environment.
Architecture Overview
The backup system consists of four distinct layers that handle configuration, execution, scheduling, and external control. Understanding this separation helps troubleshoot backup failures and customize retention policies.
Configuration Layer
Environment variables drive the scheduler behavior. In src/mcp_memory_service/config.py (lines 605–608), the service parses five critical settings:
- MCP_BACKUP_ENABLED: Boolean toggle for the scheduler (default:
True) - MCP_BACKUP_INTERVAL: Frequency string (
hourly,daily,weekly) - MCP_BACKUP_RETENTION: Days to retain backups (default:
7) - MCP_BACKUP_MAX_COUNT: Maximum files to store (default:
10) - MCP_MEMORY_BACKUPS_PATH: Writable directory for
*.dbfiles
The configuration layer validates paths and creates the backup directory during service initialization.
Backup Service Layer
The BackupService class in src/mcp_memory_service/backup/scheduler.py (lines 42–135) handles the physical creation and maintenance of backup files. It uses sqlite3.Connection.backup() executed via asyncio.to_thread to prevent blocking the event loop during large database copies.
Key methods include:
create_backup(): Generates timestamped filenames (format:memory_backup_YYYYMMDD_HHMMSS.db), executes the SQLite backup, records metadata, and triggers cleanupcleanup_old_backups(): Removes files exceeding retention days or max count constraints using non-blocking thread executionlist_backups(): Scans the backup directory and returns sorted metadata dictionaries
Scheduler Layer
The BackupScheduler class (lines 368–426 in scheduler.py) manages the periodic execution loop. It maintains a single background asyncio.Task that runs indefinitely while the service operates.
The scheduler translates textual intervals (hourly, daily, weekly) into seconds via _get_interval_seconds(). Every 300 seconds (5 minutes), the _schedule_loop checks if the elapsed time since last_backup_time exceeds the configured interval. When triggered, it invokes BackupService.create_backup() with a descriptive tag like "Scheduled daily backup".
HTTP API and Lifecycle Layer
The FastAPI application in src/mcp_memory_service/web/app.py (lines 94–101) controls the scheduler lifespan. During startup, if BACKUP_ENABLED is true, the app initializes the global scheduler instance and calls await backup_scheduler.start(). The scheduler receives a graceful shutdown signal when the application stops.
The HTTP API defined in src/mcp_memory_service/web/api/backup.py exposes three protected endpoints:
| Endpoint | Access | Function |
|---|---|---|
/api/backup/status |
Read | Returns scheduler state and next scheduled run |
/api/backup/now |
Write | Immediately executes create_backup() |
/api/backup/list |
Read | Displays existing backups with metadata |
All endpoints require API key authentication via require_read_access or require_write_access middleware.
Configuring Automated Backups
Enable and customize the scheduler through environment variables before starting the service. The configuration is read once at startup and stored in the global config object.
Environment Variable Reference
# Enable the scheduler (default: true)
MCP_BACKUP_ENABLED=true
# Set frequency: hourly, daily, or weekly
MCP_BACKUP_INTERVAL=daily
# Retention policy: 7 days and max 10 files
MCP_BACKUP_RETENTION=7
MCP_BACKUP_MAX_COUNT=10
# Absolute path for backup storage
MCP_MEMORY_BACKUPS_PATH=/var/lib/mcp/backups
Changes require a service restart to take effect, as src/mcp_memory_service/config.py parses these values during module initialization.
Backup Service Implementation Details
The BackupService class provides the core functionality for safe database duplication and storage management.
Safe SQLite Backup Execution
The create_backup() method verifies the source database exists at SQLITE_VEC_PATH, then performs the backup:
- Generates a filename with millisecond precision:
memory_backup_20240312_153045.db - Executes
sqlite3.Connection.backup()insideasyncio.to_thread()to maintain event loop responsiveness - Records file size, creation timestamp, and operation duration
- Calls
cleanup_old_backups()to enforce retention policies
Retention Policy Enforcement
The cleanup routine evaluates two constraints simultaneously:
- Age constraint: Deletes files older than
MCP_BACKUP_RETENTIONdays - Count constraint: Removes oldest files when total exceeds
MCP_BACKUP_MAX_COUNT
Files are deleted using asyncio.to_thread() to prevent I/O blocking.
The Backup Scheduler Loop
The BackupScheduler orchestrates timing and state management. It implements a soft polling mechanism rather than precise cron-like scheduling, checking every 5 minutes whether the interval threshold has passed.
Interval Translation
The _get_interval_seconds() method converts configuration strings:
hourly→ 3600 secondsdaily→ 86400 secondsweekly→ 604800 seconds
Graceful Lifecycle Management
The scheduler exposes start() and stop() methods for clean integration with FastAPI's lifespan context. When stopped, the background task receives a cancellation signal and exits the while self.is_running loop in _schedule_loop.
HTTP API Integration
The web interface provides operational visibility and manual override capabilities essential for maintenance windows.
FastAPI Lifespan Hooks
In src/mcp_memory_service/web/app.py, the application lifespan handler conditionally initializes the scheduler:
if BACKUP_ENABLED:
backup_scheduler = get_backup_scheduler()
await backup_scheduler.start()
Shutdown logic ensures the scheduler stops before the application exits, preventing corrupted backups from interrupted writes.
API Endpoints
The backup router in src/mcp_memory_service/web/api/backup.py delegates to the scheduler and service instances:
- Status endpoint: Returns
enabled,interval,last_backup_time,next_backup_at, andbackup_count - Manual trigger: Bypasses the timing check and immediately creates a backup with description
"Manual API trigger" - List endpoint: Returns JSON array of backup metadata including size and creation time
Practical Configuration Examples
Basic Environment Setup
Create a .env file in your project root:
MCP_BACKUP_ENABLED=true
MCP_BACKUP_INTERVAL=daily
MCP_BACKUP_RETENTION=14
MCP_BACKUP_MAX_COUNT=20
MCP_MEMORY_BACKUPS_PATH=/data/mcp-backups
Ensure the directory exists and is writable by the service user:
mkdir -p /data/mcp-backups
chown mcp-user:mcp-group /data/mcp-backups
Manual Backup Trigger
Trigger an immediate backup via curl:
curl -X POST "http://localhost:8000/api/backup/now" \
-H "X-API-Key: your-api-key-here"
Response format:
{
"success": true,
"filename": "memory_backup_20240312_153045.db",
"size_bytes": 8427362,
"created_at": "2024-03-12T15:30:45.123456+00:00",
"duration_seconds": 0.421
}
Programmatic Status Inspection
Check scheduler state from Python code:
import asyncio
from mcp_memory_service.backup.scheduler import get_backup_scheduler
async def check_backup_health():
scheduler = get_backup_scheduler()
status = scheduler.get_status()
print(f"Scheduler active: {status['enabled']}")
print(f"Next backup: {status['next_backup_at']}")
print(f"Total backups stored: {status['backup_count']}")
asyncio.run(check_backup_health())
Custom Cleanup Execution
Force retention policy enforcement outside the normal schedule:
from mcp_memory_service.backup.scheduler import get_backup_service
service = get_backup_service()
# Uses current config values for retention days and max count
await service.cleanup_old_backups()
Summary
- The MCP Memory Service backup scheduler uses a layered architecture separating configuration (
config.py), execution logic (BackupService), timing (BackupScheduler), and external control (FastAPI endpoints) - Environment variables control enablement, interval, retention days, and file count limits parsed at startup
- The asyncio-driven loop checks every 5 minutes and executes non-blocking SQLite backups via
asyncio.to_thread() - Retention policies enforce both time-based and count-based limits automatically after each backup
- HTTP endpoints provide operational visibility and manual trigger capabilities protected by API key middleware
Frequently Asked Questions
How do I enable automated backups in MCP Memory Service?
Set MCP_BACKUP_ENABLED=true in your environment variables or .env file. The scheduler initializes automatically when the FastAPI application starts, as implemented in src/mcp_memory_service/web/app.py. Verify status via the /api/backup/status endpoint or check that the backup directory contains timestamped .db files after the first interval elapses.
What backup intervals are supported by the scheduler?
The scheduler accepts three interval values: hourly (3600 seconds), daily (86400 seconds), and weekly (604800 seconds). Configure via MCP_BACKUP_INTERVAL. The _get_interval_seconds() method in src/mcp_memory_service/backup/scheduler.py handles the translation. The scheduler checks every 5 minutes whether the elapsed time exceeds this threshold.
How does the retention policy work for old backups?
The system enforces dual constraints defined by MCP_BACKUP_RETENTION (days) and MCP_BACKUP_MAX_COUNT (files). After each backup creation, cleanup_old_backups() removes files exceeding either limit—deleting oldest first when over count, or any file older than the retention window. Both constraints operate independently; a backup deletes if it violates age OR count policies.
Can I trigger a manual backup via the API?
Yes. Send a POST request to /api/backup/now with write-access API key authentication. This endpoint bypasses the interval check and immediately invokes BackupService.create_backup() with the description "Manual API trigger". The endpoint returns the filename, size, timestamp, and duration of the created backup, identical to scheduled backup metadata.
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 →