mail-cal-drive-mcp

mail-cal-drive-mcp

A self-hosted MCP server for managing email, calendar, and cloud storage across Microsoft 365, Google Workspace, and IMAP accounts, enabling natural language interaction through any MCP client.

Category
Visit Server

README

mail-cal-drive-mcp

License: MIT Node.js Docker MCP

A self-hosted Model Context Protocol (MCP) server for multi-account email, calendar, and cloud storage. Connect Microsoft 365, Google Workspace, and IMAP accounts to any MCP client — Claude Desktop, Claude Code, VS Code, Cursor, and more.

Runs locally in Docker with Postgres. Credentials encrypted at rest. Survives reboots without re-authorization.

Provider Email Calendar Drive
Microsoft 365 ✅ OneDrive
Google Workspace ✅ Google Drive
IMAP

Prerequisites

Quick Start

# 1. Clone
git clone https://github.com/rumbitopi/mail-cal-drive-mcp.git
cd mail-cal-drive-mcp

# 2. Configure
cp .env.example .env

# 3. Generate keys (run 3 times — one for each)
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Paste into .env as POSTGRES_PASSWORD, CREDENTIAL_ENCRYPTION_KEY, and API_KEY
# Update DATABASE_URL to use the same POSTGRES_PASSWORD

# 4. Start (server runs with zero providers — configure them later)
docker compose up --build -d

# 5. Verify health
curl http://localhost:3100/health

# 6. Verify MCP
curl -X POST http://localhost:3100/mcp \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -d '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0.0"}},"id":1}'

Architecture

┌──────────────────────────────────────────────┐
│  Docker Compose                              │
│  ┌─────────────┐    ┌──────────────┐         │
│  │ workspace   │◄──►│ postgres:5432│         │
│  │ -mcp :3100  │    │ (persistent) │         │
│  │ Streamable  │    └──────────────┘         │
│  │ HTTP + Auth │                             │
│  └─────────────┘                             │
└──────────────────────────────────────────────┘

Protocol: MCP over Streamable HTTP (2024-11-05), MCP SDK 1.25.3

What persists across reboots (in Postgres):

  • Credentials (AES-256-GCM encrypted)
  • MSAL token cache (silent Microsoft refresh — no re-auth)
  • Pending auth flows (survive restarts mid-auth)

What's ephemeral (in memory):

  • MCP sessions (clients auto-reconnect)

Client Configuration

Claude Desktop

Claude Desktop speaks stdio, not HTTP. supergateway bridges the two.

Add to ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):

{
  "mcpServers": {
    "workspace": {
      "command": "npx",
      "args": [
        "-y", "supergateway",
        "--streamableHttp", "http://localhost:3100/mcp",
        "--header", "Authorization: Bearer YOUR_API_KEY"
      ]
    }
  }
}

Claude Code

Add to .claude/settings.local.json in your project:

{
  "mcpServers": {
    "workspace": {
      "type": "streamable-http",
      "url": "http://localhost:3100/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

VS Code (GitHub Copilot)

Add to .vscode/settings.json:

{
  "github.copilot.chat.mcpServers": {
    "workspace": {
      "type": "streamable-http",
      "url": "http://localhost:3100/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

Cursor

Add to .cursor/mcp.json:

{
  "mcpServers": {
    "workspace": {
      "url": "http://localhost:3100/mcp",
      "headers": {
        "Authorization": "Bearer YOUR_API_KEY"
      }
    }
  }
}

Provider Setup

Microsoft 365

Uses device code flow — no redirect URI needed.

Azure App Registration

  1. Go to Azure PortalAzure Active DirectoryApp registrationsNew registration
  2. Name: Workspace MCP (or anything)
  3. Supported account types: "Accounts in any organizational directory and personal Microsoft accounts"
  4. Redirect URI: Leave blank
  5. Click Register

Enable Public Client Flow

  1. Go to your app → Authentication
  2. Under Advanced settings, set "Allow public client flows" to Yes
  3. Click Save

Add API Permissions

  1. Go to API permissionsAdd a permissionMicrosoft GraphDelegated permissions
  2. Add:
    • Mail.ReadWrite, Mail.Send
    • Calendars.ReadWrite, Calendars.Read.Shared
    • Files.ReadWrite, Files.ReadWrite.All
    • User.Read, offline_access
  3. Click "Grant admin consent" if you're an admin

Configure .env

MS_ENABLED=true
MS_CLIENT_ID=<Application (client) ID from Overview page>
MS_TENANT_ID=<Directory (tenant) ID, or "common" for multi-tenant>

Connect

Call auth_start with provider: "microsoft". You'll get a URL and code. Visit the URL, enter the code, sign in. Then call auth_complete. One-time setup — refresh tokens persist across reboots.


Google Workspace

Uses OAuth callback flow — requires a redirect URI.

Google Cloud Setup

  1. Go to Google Cloud Console → create or select a project
  2. Enable APIs: Gmail API, Google Calendar API, Google Drive API
  3. OAuth consent screen:
    • User Type: External (or Internal for Workspace)
    • Add scopes: gmail.modify, gmail.labels, calendar, calendar.events, drive, drive.file
    • Add yourself as a test user
  4. CredentialsCreate OAuth client ID:
    • Type: Web application
    • Redirect URI: http://localhost:3100/auth/google/callback

Configure .env

GOOGLE_ENABLED=true
GOOGLE_CLIENT_ID=<Client ID>
GOOGLE_CLIENT_SECRET=<Client Secret>
GOOGLE_REDIRECT_URI=http://localhost:3100/auth/google/callback

Connect

Call auth_start with provider: "google". Open the URL, sign in, grant permissions. The callback saves your tokens. Then call auth_complete. One-time setup.


IMAP

No external setup needed — provide credentials directly.

Connect

Call auth_start with:

provider: "imap"
accountName: "Personal Email"
email: "user@example.com"
imapHost: "imap.example.com"
imapPort: 993
imapUsername: "user@example.com"
imapPassword: "your-app-password"
imapTls: true

No auth_complete needed — IMAP accounts are ready immediately.

Common IMAP Servers

Provider Host Port Notes
Gmail imap.gmail.com 993 Requires App Password
Outlook/Hotmail outlook.office365.com 993 Requires App Password
Yahoo imap.mail.yahoo.com 993 Requires App Password
Fastmail imap.fastmail.com 993 Requires App Password

MCP Tools (36 total)

Authentication (4)

Tool Description
auth_status List all accounts with connection status
auth_start Start OAuth/device code flow or IMAP setup
auth_complete Complete pending authentication
auth_revoke Remove an account

Email (10)

Tool Description
list_accounts List all configured email accounts
list_folders Get folders/labels for an account
list_messages Messages with pagination
get_message Full message with body and attachments
get_attachment Download attachment (text decoded, binary as blob)
search_messages Search with filters (see parameters below)
move_message Move to folder
delete_message Trash or permanent delete
mark_read Mark read/unread
bulk_mail_action Batch operations with dry-run support

Calendar (8)

Tool Description
list_calendars All calendars for an account
list_events Events in a date range
get_event Full event details
create_event Create with attendees, recurrence, conferencing
update_event Modify existing event
delete_event Delete event
find_free_time Find available time slots across accounts
check_conflicts Detect scheduling conflicts

Drive (14)

Tool Description
list_files List files and folders
get_file File metadata
get_file_content Download file content
search_files Search by name, content, or type
upload_file Upload new file (text or base64)
create_folder Create folder
move_file Move file/folder
copy_file Copy file
rename_file Rename file/folder
delete_file Delete (trash or permanent)
get_sharing View sharing permissions
share_file Share with user or create link
unshare_file Remove sharing
get_storage_quota Storage usage info

Tool Parameter Reference

get_attachment

Parameter Type Required Description
accountId string Yes Account ID
messageId string Yes Message ID
attachmentId string Yes Attachment ID from get_message

Returns text content for text-based files, or an MCP EmbeddedResource with blob for binary files (PDF, images, etc.). Max 5MB.

search_messages

Parameter Type Required Description
accountIds string[] Yes Account IDs to search
from string No Filter by sender email
to string No Filter by recipient email
subject string No Filter by subject (partial match)
body string No Search in message body
folder string No Limit to specific folder
hasAttachment boolean No Filter by attachment presence
isRead boolean No Filter by read status
isStarred boolean No Filter by starred status
after string No Messages after date (ISO 8601)
before string No Messages before date (ISO 8601)
labels string[] No Filter by labels (Gmail)
limit number No Max results per account (default: 50)

create_event

Parameter Type Required Description
accountId string Yes Account ID
title string Yes Event title
startTime string Yes Start time (ISO 8601)
endTime string Yes End time (ISO 8601)
calendarId string No Calendar ID (default: primary)
description string No Event description
location string No Event location
isAllDay boolean No All-day event
timeZone string No Time zone (default: UTC)
attendees array No [{email, optional?}]
visibility string No "public" or "private"
addConference boolean No Add video conference link

bulk_mail_action

Parameter Type Required Description
accountId string Yes Account ID
action string Yes "move", "delete", "markRead", "markUnread", "star", "unstar", "archive"
dryRun boolean No Preview without executing (default: false)
targetFolder string No Destination folder (required for "move")
from string No Filter by sender
subject string No Filter by subject
folder string No Limit to folder
isRead boolean No Filter by read status
after string No After date (ISO 8601)
before string No Before date (ISO 8601)
limit number No Max messages to process

find_free_time

Parameter Type Required Description
accountIds string[] Yes Account IDs to check
startDate string Yes Start of range (ISO 8601)
endDate string Yes End of range (ISO 8601)
duration number Yes Required duration in minutes
calendarIds string[] No Calendars to check (default: primary)

upload_file

Parameter Type Required Description
accountId string Yes Account ID
name string Yes File name
content string Yes File content (text or base64)
folderId string No Parent folder ID (default: root)
mimeType string No MIME type
isBase64 boolean No Content is base64 encoded

share_file

Parameter Type Required Description
accountId string Yes Account ID
fileId string Yes File ID
type string Yes "user", "group", or "anyone"
role string Yes "reader", "writer", or "commenter"
email string No Email (required for user/group)
sendNotification boolean No Send email notification
message string No Notification message

Environment Variables

Variable Required Default Description
DATABASE_URL Yes Postgres connection string
POSTGRES_PASSWORD Yes Postgres password (used by Docker Compose)
CREDENTIAL_ENCRYPTION_KEY Yes 64 hex chars (32 bytes) for AES-256-GCM
API_KEY Yes Min 32 chars, used as Bearer token
NODE_ENV No development development or production
MCP_PORT No 3100 Server port
LOG_LEVEL No info error, warn, info, debug
MS_ENABLED No false Enable Microsoft 365
MS_CLIENT_ID If MS Azure App client ID
MS_TENANT_ID If MS common Azure tenant ID
GOOGLE_ENABLED No false Enable Google Workspace
GOOGLE_CLIENT_ID If Google OAuth client ID
GOOGLE_CLIENT_SECRET If Google OAuth client secret
GOOGLE_REDIRECT_URI If Google OAuth callback URL
IMAP_ENABLED No true Enable IMAP provider

Endpoints

Endpoint Method Auth Description
/health GET No Health check
/mcp POST Bearer MCP JSON-RPC endpoint
/mcp GET Bearer SSE stream for notifications
/mcp DELETE Bearer Session cleanup
/auth/google/callback GET No Google OAuth redirect handler

Security

This server is designed for localhost use only. Do not expose it to the internet without additional hardening.

  • Encryption at rest: All credentials, MSAL token cache, and pending auth flows encrypted with AES-256-GCM before storage in Postgres
  • Bearer auth: Timing-safe token comparison (crypto.timingSafeEqual) on all protected endpoints
  • Session limits: Max 100 concurrent sessions, 30-minute TTL with automatic eviction
  • Network: Binds to 127.0.0.1 only — not accessible from other machines
  • Body size: 10MB request limit to prevent memory exhaustion
  • IMAP note: IMAP credentials are passwords (not OAuth tokens) — encrypted at rest, but inherently less secure than OAuth. Use app passwords where possible.
  • Logging: All logs to stderr (MCP requirement). No tokens, passwords, or keys logged.
  • Token rotation: To rotate the encryption key, generate a new one, re-run auth_start for each account, and update .env. There is no in-place re-encryption (accounts must be re-authorized).

See SECURITY.md for vulnerability reporting.

Troubleshooting

Container won't start

  • Check docker compose logs workspace-mcp for errors
  • Verify DATABASE_URL matches the Postgres container credentials
  • Ensure Postgres is healthy: docker compose logs postgres

Microsoft device code expired

  • Device codes expire after 15 minutes. Call auth_start again for a fresh code.

Google OAuth: "Access blocked" or consent screen issues

  • Make sure your Google Cloud app is in "Testing" mode with your email added as a test user
  • Verify the redirect URI in Google Cloud Console matches GOOGLE_REDIRECT_URI exactly

IMAP connection refused

  • Verify host, port, and TLS settings for your provider
  • Most providers require an App Password when 2FA is enabled (not your regular password)
  • Check if your provider blocks third-party IMAP access (Gmail: enable "Less secure apps" or use App Password)

"Invalid or expired session" on tool calls

  • MCP sessions expire after 30 minutes of inactivity and are lost on container restart. Your client should auto-reconnect. If not, restart the client.

Development

# Install dependencies
npm install

# Start with hot reload (requires local Postgres on DATABASE_URL)
npm run dev

# Build TypeScript
npm run build

# Production start
npm start

# Run tests
npm test

# Type check
npm run typecheck

# Migrate credentials from old file-based storage
DATABASE_URL=... CREDENTIAL_ENCRYPTION_KEY=... npm run migrate

Project Structure

mail-cal-drive-mcp/
├── src/
│   ├── index.ts              # Entry point
│   ├── server.ts             # Express server
│   ├── config.ts             # Environment config
│   ├── logger.ts             # Structured console logger
│   ├── auth/
│   │   ├── types.ts          # Credential interfaces
│   │   ├── storage.ts        # Postgres credential storage
│   │   └── bearer.ts         # Bearer token middleware
│   ├── storage/
│   │   ├── postgres.ts       # Postgres client + encrypted CRUD
│   │   ├── msal-cache.ts     # MSAL cache plugin (Postgres)
│   │   └── pending-flows.ts  # Pending auth flow storage
│   ├── providers/
│   │   ├── base.ts           # Abstract interfaces
│   │   ├── types.ts          # Shared types
│   │   ├── microsoft/        # Graph API (mail, calendar, drive)
│   │   ├── google/           # Google APIs (Gmail, Calendar, Drive)
│   │   └── imap/             # ImapFlow (mail only)
│   ├── mcp/
│   │   ├── handler.ts        # MCP request routing
│   │   ├── session.ts        # Session management
│   │   └── tools/            # 35 MCP tools
│   └── utils/                # Timezone, recurrence, MIME helpers
├── db/migrations/            # Postgres schema
├── docker-compose.yml
├── Dockerfile
└── .env                      # Configuration (gitignored)

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured