Skip to main content

Quality Gate Status Bugs Vulnerabilities Code Smells Coverage Duplicated Lines (%)

Universal Memory MCP — AI Conversation Memory

A Model Context Protocol (MCP) server that provides persistent, searchable conversation memory across multiple AI platforms. Store, search, and retrieve conversation history with fast full-text search powered by SQLite FTS5.

Features

  • 🔍 Fast full-text search via SQLite FTS5 with relevance ranking — ~10x faster than a linear scan (measured)
  • 🏷️ Automatic topic extraction — 574+ unique topics across 2,000+ associations
  • 📊 Weekly summaries with insights and patterns
  • 🗃️ Organized file storage by date and topic
  • 🤖 Multi-platform support — Claude, ChatGPT, Cursor AI, and custom formats
  • 🔌 MCP integration for Claude Desktop and Claude Code

Quick Start

Prerequisites

  • Python 3.10+ (CI runs 3.14)
  • Ubuntu/WSL environment recommended
  • Claude Desktop (for MCP integration)

Installation

From PyPI (recommended):

pip install universal-memory-mcp

That gives you a universal-memory-mcp console script, which is what an MCP config should point at — more robust than an absolute path into a checkout:

{ "mcpServers": { "claude-memory": { "command": "universal-memory-mcp" } } }

Install from source instead if you intend to modify it — the steps below do that.

Option 1: Install with Claude Code (Recommended)

Quick Install - Copy and paste this into Claude Code:

claude mcp add --transport stdio claude-memory -- sh -c "cd $HOME/Code/universal-memory-mcp && python3 src/universal_memory_mcp/server_fastmcp.py"

Important: Replace $HOME/Code/universal-memory-mcp with the actual path where you cloned this repository.

Examples for different locations:

# If cloned to ~/Code/universal-memory-mcp (default)
claude mcp add --transport stdio claude-memory -- sh -c "cd $HOME/Code/universal-memory-mcp && python3 src/universal_memory_mcp/server_fastmcp.py"

# If cloned to ~/projects/universal-memory-mcp
claude mcp add --transport stdio claude-memory -- sh -c "cd $HOME/projects/universal-memory-mcp && python3 src/universal_memory_mcp/server_fastmcp.py"

# If cloned to ~/dev/universal-memory-mcp
claude mcp add --transport stdio claude-memory -- sh -c "cd $HOME/dev/universal-memory-mcp && python3 src/universal_memory_mcp/server_fastmcp.py"

What this does:

  • --transport stdio: Uses standard input/output for local processes
  • claude-memory: Server identifier name
  • --: Separates Claude CLI flags from the server command
  • sh -c "cd ... && python3 ...": Changes to project directory before running server

This adds the MCP server to your Claude Desktop configuration automatically.

Documentation: https://code.claude.com/docs/en/mcp

Option 2: Manual Installation

  1. Clone the repository:

    git clone https://github.com/adamkwhite/universal-memory-mcp.git
    cd universal-memory-mcp
    
  2. Set up virtual environment:

    python3 -m venv .venv
    source .venv/bin/activate
    
  3. Install dependencies:

    pip install -e .
    

    This installs the package in editable mode along with all required dependencies: Dependencies are pinned in pyproject.toml and locked in uv.lock — read them there rather than from a list here, which drifts on every bump.

  4. Test the system:

    python3 tests/validate_system.py
    

Basic Usage

MCP Server Mode

# Run as MCP server (from project root)
python3 src/universal_memory_mcp/server_fastmcp.py

# Or from src directory
cd src && python3 server_fastmcp.py

Bulk Import

# Import conversations from JSON export
python3 scripts/bulk_import_enhanced.py your_conversations.json

MCP Tools

search_conversations(query, limit=5)

Full-text search across all stored conversations with relevance ranking. Query text is treated as literal Unicode terms, so punctuation and FTS5 operators do not change the query semantics. Results include conversation IDs for exact retrieval.

get_conversation(conversation_id, max_chars=12000)

Retrieve a stored conversation by an ID returned from a search tool. Content is read from the authoritative JSON store and truncated to max_chars to protect the model context. max_chars must be between 1 and 50,000.

search_by_topic(topic, limit=10)

Find conversations tagged with a specific topic.

add_conversation(content, title, date)

Store a new conversation with automatic topic extraction and FTS indexing.

generate_weekly_summary(week_offset=0)

Generate insights and patterns from recent conversations.

get_search_stats()

View search engine statistics — index size, topic counts, and engine status.

update_conversation(conversation_id, content=None, title=None, add_tags=None, remove_tags=None, set_tags=None, conversation_type=None, session_id=None, user_id=None, change_note=None, record_audit=True)

Update fields on an existing conversation in place. Pass conversation_id plus any subset of fields to change; unspecified fields are left alone. By default, the first line of stored content is rewritten with a self-documenting audit line — [update <iso-timestamp> — <change_note>] — chained across repeated updates. If change_note is omitted, it is derived from the changed fields.

Set record_audit=False only for authoritative imports whose content must remain an exact replica of the source system. Normal interactive updates should retain the default audit record.

Tag operations: set_tags replaces the full tag list and is mutually exclusive with add_tags/remove_tags (pass set_tags=[] to clear all tags); add_tags/remove_tags mutate the existing list.

Returns a status string. On success: Status: success plus a summary message and, when enabled, the audit line. On failure (malformed ID, conversation not found, no changes provided, conflicting tag ops, or an I/O error): Status: error plus a message describing the problem.

search_by_tag(tag, limit=10)

Find conversations tagged with a specific tag — a universal metadata field populated by importers or set via update_conversation (e.g. starred, archived, workspace:my-project). Exact match, case-sensitive. Requires SQLite FTS to be enabled; without it, returns an error message.

search_by_session_id(session_id, limit=10)

Find all conversations sharing a session_id, useful for reconstructing a multi-turn session that spans several stored conversation records (e.g. a Cursor working session, a Claude thread continued across days). Results are sorted chronologically (oldest first). Requires SQLite FTS to be enabled; without it, returns an error message.

search_by_conversation_type(conversation_type, limit=10)

Find conversations by conversation_type (e.g. chat, code, analysis). Exact match, most recent first. Requires SQLite FTS to be enabled; without it, returns an error message.

Architecture

~/claude-memory/
├── conversations/
│   ├── 2025/
│   │   └── 06-june/
│   │       └── 2025-06-01_topic-name.md
│   ├── index.json          # Search index
│   └── topics.json         # Topic frequency
└── summaries/
    └── weekly/
        └── week-2025-06-01.md

Configuration

Claude Desktop Integration

Add to your Claude Desktop MCP config:

{
  "mcpServers": {
    "claude-memory": {
      "command": "python",
      "args": ["/absolute/path/to/universal-memory-mcp/src/universal_memory_mcp/server_fastmcp.py"],
      "cwd": "/absolute/path/to/universal-memory-mcp"
    }
  }
}

Upgrading from before the package move (#225): the server script moved from src/universal_memory_mcp/server_fastmcp.py to src/universal_memory_mcp/server_fastmcp.py. Update the args path in your config, or the server will fail to start with No such file or directory. python -m universal_memory_mcp.server_fastmcp also works if the package is installed.

Configuration Precedence

Settings are resolved by src/universal_memory_mcp/config.py's Config.load(), consulted in this order (highest wins):

  1. Environment variables (CLAUDE_MEMORY_* / CLAUDE_MCP_*)
  2. Config file (default ~/.claude-memory/config.json)
  3. Platform profile (default, claude, chatgpt, or cursor — selects a partial set of defaults, e.g. log_format)
  4. Built-in defaults

Environment Variables

Variable Purpose Default
CLAUDE_MEMORY_PATH Conversation storage directory ~/claude-memory
CLAUDE_MEMORY_DISABLE_SQLITE Set true to disable SQLite FTS and fall back to JSON linear search. Inverse alias of CLAUDE_MCP_ENABLE_SQLITE; wins if both are set. unset (SQLite enabled)
CLAUDE_MCP_LOG_FORMAT Log output format: text or json text
CLAUDE_MCP_LOG_LEVEL Log level: DEBUG, INFO, WARNING, ERROR, CRITICAL INFO
CLAUDE_MCP_ENABLE_SQLITE Enable/disable SQLite FTS search (boolean: true/false, 1/0, yes/no, on/off) true
CLAUDE_MCP_CONSOLE_OUTPUT Echo logs to stdout in addition to the log file (boolean) false
CLAUDE_MCP_PLATFORM_PROFILE Platform profile to apply: default, claude, chatgpt, or cursor default

When CLAUDE_MEMORY_PATH is set explicitly, the path may live outside your home directory (e.g. a separate data drive on Windows: D:\claude-memory). Paths that are not explicitly configured are still restricted to the home or project directory for safety.

Config File

As an alternative to environment variables, settings can be placed in ~/.claude-memory/config.json. The file is optional — a missing file falls back to platform-profile/built-in defaults. Example:

{
  "storage_path": "~/claude-memory",
  "log_format": "json",
  "log_level": "INFO",
  "enable_sqlite": true,
  "console_output": false,
  "platform_profile": "default"
}

Unknown keys in the file raise a configuration error rather than being silently ignored. Environment variables still override anything set here.

Disabling SQLite

SQLite FTS5 search is enabled by default. On platforms where SQLite/FTS5 is unavailable (e.g. some Windows Python builds), disable it to fall back to JSON-based linear search:

export CLAUDE_MEMORY_DISABLE_SQLITE=true

Logging Configuration

Log Format

Switch between human-readable text logs (default) and structured JSON logs for production:

# JSON format (for production log aggregation)
export CLAUDE_MCP_LOG_FORMAT=json

# Text format (default, for development)
export CLAUDE_MCP_LOG_FORMAT=text

JSON Log Example:

{
  "timestamp": "2025-01-15T10:30:45",
  "level": "INFO",
  "logger": "claude_memory_mcp",
  "function": "add_conversation",
  "line": 145,
  "message": "Added conversation successfully",
  "context": {
    "type": "performance",
    "duration_seconds": 0.045,
    "conversation_id": "conv_abc123"
  }
}

JSON logging is ideal for:

  • Production deployments with log aggregation (Datadog, ELK, CloudWatch)
  • Automated monitoring and alerting
  • Structured log analysis and querying
  • Performance tracking and debugging

See docs/json-logging.md for detailed JSON logging documentation.

File Structure

universal-memory-mcp/
├── src/
│   ├── server_fastmcp.py       # Main MCP server
│   ├── conversation_memory.py  # Core memory engine + SQLite FTS5
│   ├── format_detector.py      # Auto-detect AI platform format
│   ├── validators.py           # Input validation
│   ├── logging_config.py       # Structured logging (text/JSON)
│   ├── importers/              # Platform-specific importers
│   │   ├── chatgpt_importer.py
│   │   ├── claude_importer.py
│   │   ├── cursor_importer.py
│   │   └── generic_importer.py
│   └── schemas/                # JSON schema validation
├── tests/                      # 435 tests, 98.68% coverage
├── data/                       # Consolidated app data
├── scripts/                    # Import and utility scripts
└── docs/                       # Documentation

Performance

scripts/benchmark_search.py was broken (unawaited async calls, measuring coroutine construction instead of real search time) from October 2025 until this was found and fixed. The previous numbers below were never actually measured and have been replaced with real ones. Reproduce with:

python scripts/generate_test_data.py --conversations 159
python scripts/benchmark_search.py --storage-path ~/claude-memory-test --iterations 5

Measured on a 159-conversation / 7.7MB local dataset (WSL2, Python 3.12) — treat as order-of-magnitude, not a precise SLA, results vary by machine:

  • Search Speed (SQLite FTS5): mean 15–18ms, median 10–13ms per query, range 0.5–82ms across 12 query types (was claimed 0.2–0.5ms; that figure was never measured)
  • Search vs. linear JSON scan: SQLite FTS5 is ~10x faster (mean 14.7ms vs 154.2ms; median 10.5ms vs 152.0ms) — the old "4.4x" claim had the right direction but was also never actually measured
  • Topic Search: mean 3.4ms, median 2.5ms (was claimed 0.3–0.4ms; that figure was never measured)
  • Write Speed: mean 14ms, median 14ms per ~49KB conversation, SQLite indexing included (was claimed ~33ms; that figure was never measured)
  • Capacity: 371 conversations in production use over 10 months
  • Test Coverage: 98.68% (435 tests) — 0 code smells, 0 security hotspots (SonarCloud verified)

Last benchmarked: July 2026 | Detailed Report

Note for Developers: Performance benchmarks create a ~/claude-memory-test directory for isolated testing. Normal MCP usage only uses ~/claude-memory/. If you see ~/claude-memory-test, it can be safely deleted.

Search Examples

# Technical topics
search_conversations("terraform azure")
search_conversations("mcp server setup")
search_conversations("python debugging")

# Project discussions
search_conversations("interview preparation")
search_conversations("product management")
search_conversations("architecture decisions")

# Specific problems
search_conversations("dependency issues")
search_conversations("authentication error")
search_conversations("deployment configuration")

Development

Adding New Features

  1. Topic Extraction: Modify _extract_topics() in ConversationMemoryServer
  2. Search Algorithm: Enhance search_conversations() method
  3. Summary Generation: Improve generate_weekly_summary() logic

Testing

# Run validation suite
python3 tests/validate_system.py

# Run full test suite with coverage
python3 -m pytest tests/ --cov=src --cov-report=term

# Import test data
python3 scripts/bulk_import_enhanced.py test_data.json --dry-run

Test Data Storage (Developers Only): If you run performance benchmarks or test data generators, they create a ~/claude-memory-test directory to isolate test data from your production ~/claude-memory directory. This is only for development/testing - normal MCP usage does not create this directory.

To clean up test data after running benchmarks:

rm -rf ~/claude-memory-test

Or using the Makefile cleanup target:

make clean-test-data

Troubleshooting

Common Issues

MCP Import Errors:

pip install mcp[cli]  # Include CLI extras

Search Returns No Results:

  • Check conversation indexing: ls ~/claude-memory/conversations/index.json
  • Verify file permissions
  • Run validation: python3 tests/validate_system.py

Weekly Summary Timezone Errors:

  • Ensure all datetime objects use consistent timezone handling
  • Recent fix addresses timezone-aware vs naive comparison

System Requirements

  • Python: 3.10+ (CI runs 3.14)
  • Disk Space: ~10MB per 100 conversations
  • Memory: <100MB RAM usage
  • OS: Linux/WSL and Windows are both verified in CI on every PR (Ubuntu + windows-latest). macOS is expected to work but is not covered by a CI runner.

Contributing

  1. Fork the repository
  2. Create a feature branch: git checkout -b feature-name
  3. Commit changes: git commit -am 'Add feature'
  4. Push to branch: git push origin feature-name
  5. Submit a Pull Request

A note for fork PRs: GitHub does not give forks access to repository secrets, so the SonarCloud scan and the performance-results comment are skipped on your PR rather than run. That is expected and is not something you can or should fix — the test suite, linting, CodeQL and the Windows run all still execute normally, and coverage on your changes is checked when the branch lands on main. If you see those two skipped, nothing is wrong.

Releasing

Publishing is tag-gated and uses Trusted Publishing (OIDC) — there is no PyPI token stored in this repo. .github/workflows/publish.yml fires only on a vX.Y.Z tag.

One-time setup on PyPI (publisher settings for the project, or a pending publisher while the name is still unclaimed):

field value
Owner adamkwhite
Repository universal-memory-mcp
Workflow publish.yml
Environment pypi

To cut a release:

# 1. bump `version` in pyproject.toml, commit, merge to main
# 2. tag the merged commit — the workflow refuses a tag that disagrees with pyproject
git tag v0.1.0 && git push origin v0.1.0

The workflow builds, runs twine check, installs the wheel into a clean venv and asserts that every module imports and that no generic top-level name leaked, then publishes. Add required reviewers to the pypi environment in repo settings for a manual approval gate as well.

Rehearse on TestPyPI before the first real upload — the first upload claims the name permanently, and a version number can never be reused:

rm -rf dist && uv build
uv run --with twine --no-project twine upload --repository testpypi dist/*
# TestPyPI does not mirror mcp/jsonschema/aiofiles, so pull deps from real PyPI:
uv pip install --index-url https://test.pypi.org/simple/ \
               --extra-index-url https://pypi.org/simple/ universal-memory-mcp

License

MIT License - see LICENSE file for details

Acknowledgments


Status: Production ready ✅ Last Updated: April 2026 Version: 2.0.0

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

universal_memory_mcp-0.1.1.tar.gz (194.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

universal_memory_mcp-0.1.1-py3-none-any.whl (109.3 kB view details)

Uploaded Python 3

File details

Details for the file universal_memory_mcp-0.1.1.tar.gz.

File metadata

  • Download URL: universal_memory_mcp-0.1.1.tar.gz
  • Upload date:
  • Size: 194.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for universal_memory_mcp-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2a557c012fee031f6bbd70fa115299b80ec7ad7970ce4962d949d60014560ec9
MD5 f5d4e71cbfe45f2a0c18b0498fff50aa
BLAKE2b-256 5abd49b3a9c24f6ad9f22505599b28bab1acea6fef5c9559cebaf8e03f0f5700

See more details on using hashes here.

Provenance

The following attestation bundles were made for universal_memory_mcp-0.1.1.tar.gz:

Publisher: publish.yml on adamkwhite/universal-memory-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file universal_memory_mcp-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for universal_memory_mcp-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 4685c6f1c4accbbfe5c4c04bb6f514d818a60f4d0666c2f671be98c2d354ae3f
MD5 0b99f902f4ec16f6b8fed73fc4ab8772
BLAKE2b-256 3b9b4546186965d3adf98bc8e08dce49cb61510b12477ae41ff7519498f0905d

See more details on using hashes here.

Provenance

The following attestation bundles were made for universal_memory_mcp-0.1.1-py3-none-any.whl:

Publisher: publish.yml on adamkwhite/universal-memory-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page