PIM MCP Server
A self-hosted MCP server for managing your email, calendar, and contacts through AI assistants.
Connect your existing mail server (IMAP/SMTP) and CalDAV/CardDAV services to any MCP-compatible client.
Prerequisites
- Docker and Docker Compose (recommended), OR Python 3.12+
- An email account with IMAP/SMTP access
- (Optional) A CalDAV server for calendars (Nextcloud, Fastmail, Radicale, etc.)
- (Optional) A CardDAV server for contacts
Setup
Option 1: Docker Compose (Recommended)
-
Clone the repository
git clone https://github.com/your-repo/pim-mcp-server.git cd pim-mcp-server -
Create your environment file
cp .env.example .env -
Edit
.envwith your credentials# Required: Generate an API key MCP_API_KEY=$(python3 -c "import secrets; print(secrets.token_urlsafe(32))") # Then edit .env with your mail server details nano .env -
Start the server
docker compose up -d -
Verify it's running
curl http://localhost:8000/mcp
Option 2: Local Python
-
Clone and setup environment
git clone https://github.com/your-repo/pim-mcp-server.git cd pim-mcp-server python -m venv venv source venv/bin/activate # Windows: venv\Scripts\activate pip install -r requirements.txt -
Configure
cp .env.example .env nano .env # Add your credentials -
Initialize database
# Create initial migration (first time only) alembic revision --autogenerate -m "Initial tables" alembic upgrade head -
Run
python src/server.py
Configuration
Edit .env with your service credentials. Only configure the services you want to use.
Minimal Setup (Email Only)
# Server
MCP_API_KEY=your-secret-key-here
PORT=8000
# Email
IMAP_HOST=imap.example.com
IMAP_USERNAME=you@example.com
IMAP_PASSWORD=your-password
SMTP_HOST=smtp.example.com
SMTP_USERNAME=you@example.com
SMTP_PASSWORD=your-password
SMTP_FROM_EMAIL=you@example.com
# Disable other services
ENABLE_CALENDAR=false
ENABLE_CONTACTS=false
Full Setup (Email + Calendar + Contacts)
# Server
MCP_API_KEY=your-secret-key-here
PORT=8000
# Email (IMAP/SMTP)
IMAP_HOST=imap.example.com
IMAP_PORT=993
IMAP_USERNAME=you@example.com
IMAP_PASSWORD=your-password
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_USERNAME=you@example.com
SMTP_PASSWORD=your-password
SMTP_FROM_EMAIL=you@example.com
SMTP_FROM_NAME=Your Name
# Calendar (CalDAV)
CALDAV_URL=https://caldav.example.com/dav
CALDAV_USERNAME=you@example.com
CALDAV_PASSWORD=your-password
# Contacts (CardDAV)
CARDDAV_URL=https://carddav.example.com/dav
CARDDAV_USERNAME=you@example.com
CARDDAV_PASSWORD=your-password
Provider-Specific Examples
Fastmail
IMAP_HOST=imap.fastmail.com
IMAP_PORT=993
SMTP_HOST=smtp.fastmail.com
SMTP_PORT=587
CALDAV_URL=https://caldav.fastmail.com/dav/calendars/user/you@fastmail.com
CARDDAV_URL=https://carddav.fastmail.com/dav/addressbooks/user/you@fastmail.com
Use an app-specific password.
Nextcloud
# Use your mail server for IMAP/SMTP
IMAP_HOST=mail.example.com
SMTP_HOST=mail.example.com
# Nextcloud for CalDAV/CardDAV
CALDAV_URL=https://cloud.example.com/remote.php/dav
CARDDAV_URL=https://cloud.example.com/remote.php/dav
CALDAV_USERNAME=your-nextcloud-user
CARDDAV_USERNAME=your-nextcloud-user
Gmail
IMAP_HOST=imap.gmail.com
IMAP_PORT=993
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
You must use an App Password (not your regular password).
Note: Gmail's CalDAV/CardDAV requires OAuth2, which is not currently supported.
Mailcow
IMAP_HOST=mail.example.com
SMTP_HOST=mail.example.com
CALDAV_URL=https://mail.example.com/SOGo/dav
CARDDAV_URL=https://mail.example.com/SOGo/dav
Radicale (Self-hosted)
CALDAV_URL=https://radicale.example.com/user/
CARDDAV_URL=https://radicale.example.com/user/
Connecting to MCP Clients
MCP Inspector (Testing)
npx @modelcontextprotocol/inspector
- Transport: Streamable HTTP
- URL:
http://localhost:8000/mcp
Claude Desktop
Add to your Claude Desktop config (~/.config/claude/claude_desktop_config.json on Linux/Mac):
{
"mcpServers": {
"pim": {
"transport": "http",
"url": "http://localhost:8000/mcp"
}
}
}
Poke
Go to poke.com/settings/connections and add your server URL.
Available Tools
Once connected, your AI assistant can use these tools:
| Category | Tools |
|---|---|
list_mailboxes, list_emails, read_email, search_emails, move_email, delete_email, send_email |
|
| Calendar | list_calendars, list_events, get_event, create_event, update_event, delete_event |
| Contacts | list_addressbooks, list_contacts, get_contact, create_contact, update_contact, delete_contact |
| System | get_server_info |
Database Migrations
The server uses SQLModel with Alembic for database migrations.
When you update the code
# Pull latest changes
git pull
# Run any new migrations
alembic upgrade head
# Restart
docker compose restart
# or: python src/server.py
Adding custom fields
- Edit
src/database/models.py - Generate migration:
alembic revision --autogenerate -m "Description" - Apply:
alembic upgrade head
Troubleshooting
Connection refused
- Check the server is running:
docker compose psorcurl localhost:8000/mcp - Check logs:
docker compose logs -f
Authentication failed (IMAP/SMTP)
- Verify credentials in
.env - Many providers require app-specific passwords (Gmail, Fastmail, etc.)
- Check if 2FA is enabled on your account
CalDAV/CardDAV not working
- Verify the URL is correct (try opening it in a browser)
- Check if your provider requires a specific URL format
- Some providers need the full path including username
Service disabled
If you see "service: disabled (not configured)", check that:
- All required env vars are set (host, username, password)
ENABLE_*is not set tofalse
View logs
# Docker
docker compose logs -f
# Local
# Logs print to stdout
Project Structure
├── src/
│ ├── server.py # Entry point
│ ├── config.py # Environment configuration
│ ├── database/ # SQLModel ORM
│ │ ├── models.py # Table definitions
│ │ └── connection.py # Database connection
│ ├── models/ # Pydantic models (API)
│ ├── services/ # Business logic
│ └── tools/ # MCP tool definitions
├── migrations/ # Alembic migrations
├── docker-compose.yml
├── Dockerfile
├── .env.example
└── requirements.txt
Security Notes
- Never commit
.envfiles - Use app-specific passwords where available
- The Docker container runs as non-root
- Consider running behind a reverse proxy with HTTPS for remote access
- The
MCP_API_KEYis optional but recommended for production
License
MIT