Sagent 3b575bbf83
PR Checks / hadolint (pull_request) Successful in 12s
Docker Build and Push / test (pull_request) Successful in 2m17s
Docker Build and Push / integration-test (pull_request) Successful in 2m38s
PR Checks / pytest (pull_request) Successful in 2m19s
Docker Build and Push / build (pull_request) Successful in 2m39s
PR Checks / build-test (pull_request) Successful in 3m5s
fix(indexer): restore module-level embedding/batch constants
The "make indexer importable without env" refactor (e32806a, merged via PR
#52 on 2026-10-09) removed EMBEDDING_MODEL_NAME, BATCH_SIZE and
EMBEDDING_BATCH_SIZE from the module scope while main() kept referencing
them, so every indexer run died before reaching Qdrant:

    File "/app/src/indexer.py", line 264, in main
        print(f"Loading embedding model: {EMBEDDING_MODEL_NAME}...")
    NameError: name 'EMBEDDING_MODEL_NAME' is not defined

CI never caught it because no test executes main(). Both *-indexer cronjobs
have been failing (BackoffLimitExceeded) since 2026-10-16, i.e. the first
run after the image pin moved to v0.0.22-latest.

- restore the three constants with their pre-refactor defaults
- cover them in tests/test_indexer.py and cross-check that the indexer
  embeds with the same model as server.py (vectors must stay comparable)
- add a ruff F821 gate to the unit job so undefined names fail CI

Fixes mcp-maildir-cabilloteu-indexer and mcp-maildir-gmail-indexer.
2026-10-17 21:04:34 +00:00
2026-02-26 16:34:25 -05:00
2026-02-26 16:34:25 -05:00
2026-02-27 10:32:42 -05:00
2026-02-26 16:34:25 -05:00
2026-06-22 16:12:05 +00:00

mcp-maildir

mcp-maildir is an MCP (Model Context Protocol) server allowing AI agents (Claude, OpenHands, Cursor, etc.) to explore, search, and read your email archives in a 100% offline, local, and strict Read-Only (R/O) manner.

This project uses an email dump in the Maildir format (e.g., generated via offlineimap), vectorizes the content locally for semantic search, and stores everything in Qdrant to provide ultra-fast hybrid search (Semantic + Exact filtering on metadata like dates or senders).

✨ Features

  • 🔒 Strict Read-Only: The AI interacts with a Qdrant index; it has no direct access to your actual mailbox or the maildir files. Zero risk of accidental deletion or sending.
  • 🧠 Hybrid Search:
    • Semantic: Find concepts ("farewell party organization") via local sentence-transformers.
    • Factual: Filter deterministically by sender or exact date ranges (thanks to Qdrant's native payload indexes).
  • 🚀 MCP Standard: Instantly compatible with any client supporting the Model Context Protocol.

🏗️ Architecture

  1. Source: Your local Maildir folder.
  2. Indexer (indexer.py): A Python script that parses emails, extracts raw text, generates local embeddings, and pushes everything to Qdrant along with metadata.
  3. Database: Qdrant (running locally via Docker).
  4. MCP Server (server.py): Exposes search and read tools to the AI agent via FastMCP.

🛠️ Prerequisites

  • Python 3.10+
  • Docker (to run Qdrant)
  • An email folder in Maildir format

🚀 Installation & Setup

1. Clone and prepare the environment

git clone https://github.com/your-username/mcp-maildir.git
cd mcp-maildir

# Create a virtual environment
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate

# Install dependencies
pip install mcp fastmcp qdrant-client sentence-transformers

2. Start Qdrant (Vector Database)

Run Qdrant locally in the background using Docker:

docker run -p 6333:6333 -p 6334:6334 \
    -v $(pwd)/qdrant_storage:/qdrant/storage:z \
    qdrant/qdrant

3. Configuration

Create a .env file or modify the variables in the code to point to your Maildir folder:

MAILDIR_PATH=/path/to/your/maildir/dump
QDRANT_URL=<http://localhost:6333>
COLLECTION_NAME=my_emails

4. Initial Indexing (Ingestion)

Before the AI can search, you need to index your emails. Run the ingestion script (to be executed every time you sync new emails):

python indexer.py

Note: The indexer.py script automatically configures Qdrant payload indexes for metadata (sender as KEYWORD, date as DATETIME) to guarantee fast and deterministic static searches.

🤖 Usage with an MCP Client

Tools exposed by the server

The server.py script exposes the following tools to the AI:

  • search_emails(query: str, sender: str, start_date: str, end_date: str): Performs a hybrid search. Metadata parameters are optional.
  • read_email(message_id: str): Returns the full text content (cleaned of HTML) of a specific email.
S
Description
No description provided
Readme
281 KiB
0 Stars 4 Watchers 0 Forks
Languages
Python 98.7%
Dockerfile 1.3%