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 *.db files

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 cleanup
  • cleanup_old_backups(): Removes files exceeding retention days or max count constraints using non-blocking thread execution
  • list_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:

  1. Generates a filename with millisecond precision: memory_backup_20240312_153045.db
  2. Executes sqlite3.Connection.backup() inside asyncio.to_thread() to maintain event loop responsiveness
  3. Records file size, creation timestamp, and operation duration
  4. 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_RETENTION days
  • 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 seconds
  • daily → 86400 seconds
  • weekly → 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, and backup_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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →