Skip to main content
Glama
rumbitopi

mail-cal-drive-mcp

by rumbitopi

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

Related MCP server: productivity-mcp

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

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rumbitopi/mail-cal-drive-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server