# MCP Memory Service Backup Scheduler Architecture and Configuration Guide

> Explore the four-layer asyncio backup scheduler architecture for MCP Memory Service. Learn how to configure automated SQLite snapshots and manual controls.

- Repository: [Henry/mcp-memory-service](https://github.com/doobidoo/mcp-memory-service)
- Tags: architecture
- Published: 2026-02-28

---

**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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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

```bash

# 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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/src/mcp_memory_service/web/app.py), the application lifespan handler conditionally initializes the scheduler:

```python
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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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:

```dotenv
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:

```bash
mkdir -p /data/mcp-backups
chown mcp-user:mcp-group /data/mcp-backups

```

### Manual Backup Trigger

Trigger an immediate backup via curl:

```bash
curl -X POST "http://localhost:8000/api/backup/now" \
     -H "X-API-Key: your-api-key-here"

```

Response format:

```json
{
  "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:

```python
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:

```python
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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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`](https://github.com/doobidoo/mcp-memory-service/blob/main/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.