Skip to content

Configuration

Complete configuration reference for Gmail Secretary MCP.

Configuration File

The server requires a config.yaml file (read-only) and a token.json file (read-write for OAuth tokens).

bash
# Copy sample config
cp config.sample.yaml config.yaml

# After OAuth setup, token.json is created automatically

Critical: Separate Token Storage

OAuth tokens are stored in token.json, NOT in config.yaml. This allows:

  • config.yaml mounted read-only (:ro) for security
  • token.json mounted read-write for token refresh
  • No risk of config overwrites during token updates

Required Fields

Bearer Authentication

Strongly Recommended

Enable bearer auth to protect your email from unauthorized access. Without it, anyone who can reach the server has full access to your email.

yaml
bearer_auth:
  enabled: true
  token: "your-secure-token-here"

Generate a unique token:

bash
uuidgen
bash
# uuidgen (install uuid-runtime if not available)
uuidgen

# Or use OpenSSL (always available)
openssl rand -hex 32
powershell
[guid]::NewGuid().ToString()

Linux Note

On some Linux distributions, uuidgen requires the uuid-runtime package:

bash
# Debian/Ubuntu
sudo apt install uuid-runtime

# RHEL/CentOS/Fedora
sudo dnf install util-linux

User Identity

yaml
identity:
  email: your-email@gmail.com
  full_name: "Your Full Name"
  aliases: []  # Empty list if you have no aliases

Fields:

  • email (required): Your primary Gmail address
  • full_name (optional): Used to detect if you're mentioned in email body
  • aliases (required): Additional email addresses, or [] if none

Always Include aliases

Even if you have no aliases, you must include the field:

yaml
aliases: []  # Required - empty list if no aliases

Used by:

  • get_daily_briefing: Signals is_addressed_to_me and mentions_my_name
  • quick_clean_inbox: Determines which emails can be auto-cleaned

IMAP Configuration

yaml
imap:
  host: imap.gmail.com
  port: 993
  username: your-email@gmail.com
  use_ssl: true

OAuth credentials are stored in token.json after running auth setup—not in config.yaml.

Gmail-Only

This server is designed for Gmail. While built on IMAP/SMTP protocols, it uses Gmail-specific features (labels, OAuth, threading) that won't work with other providers.

SMTP Configuration

yaml
smtp:
  host: smtp.gmail.com
  port: 587
  username: your-email@gmail.com
  use_tls: true

Uses the same OAuth token from token.json for authentication.

Timezone

yaml
timezone: Europe/Amsterdam  # IANA timezone format

Valid formats: IANA Time Zone Database names:

  • America/Los_Angeles (not PST)
  • Europe/London (not GMT)
  • Asia/Tokyo (not JST)

Working Hours

yaml
working_hours:
  start: "09:00"  # HH:MM format, 24-hour clock
  end: "17:00"
  workdays: [1, 2, 3, 4, 5]  # 1=Monday, 7=Sunday

Rules:

  • Times must be in HH:MM format (e.g., 09:00, not 9:00 AM)
  • Workdays: 1=Monday through 7=Sunday
  • Tools like suggest_reschedule() only suggest times within these constraints
  • Agents will still ask before declining meetings outside working hours

VIP Senders

yaml
vip_senders:
  - boss@company.com
  - ceo@company.com
  - important-client@example.com

Or if you have no VIPs:

yaml
vip_senders: []

Rules:

  • Exact email addresses (case-insensitive)
  • Emails from these senders get is_from_vip=true in signals

Database Configuration

Secretary MCP supports two database backends for email caching.

SQLite (Default)

No configuration needed—SQLite is automatic:

yaml
database:
  backend: sqlite  # Default, can be omitted

Cache location: config/email_cache.db (same directory as config.yaml)

When to use SQLite:

  • Single-user deployments
  • Local development
  • Simple setups without semantic search

PostgreSQL with pgvector

For semantic search capabilities (search by meaning, find related emails):

yaml
database:
  backend: postgres
  
  postgres:
    host: postgres          # Docker service name, or localhost
    port: 5432
    database: secretary
    user: secretary
    password: ${POSTGRES_PASSWORD}
    ssl_mode: prefer
  
  embeddings:
    enabled: true
    provider: gemini
    gemini_api_key: ${GEMINI_API_KEY}
    gemini_model: text-embedding-004
    dimensions: 3072
    batch_size: 100
    task_type: RETRIEVAL_DOCUMENT

When to use PostgreSQL:

  • Need semantic search ("find emails about budget concerns")
  • Want find_related_emails for context gathering
  • Multi-instance deployments with shared database

See Semantic Search and Embeddings Guide for complete setup.

Optional Fields

Allowed Folders

Restrict which folders the AI can access:

yaml
allowed_folders:
  - INBOX
  - "[Gmail]/Sent Mail"
  - "[Gmail]/All Mail"

Default: If omitted, all folders are accessible.

Gmail Folder Names

Gmail uses [Gmail]/ prefix for system folders:

  • [Gmail]/Sent Mail
  • [Gmail]/Drafts
  • [Gmail]/All Mail
  • [Gmail]/Trash

Calendar Configuration

yaml
calendar:
  enabled: true

Default: Calendar tools disabled unless explicitly enabled.

Web UI Configuration

Configure the optional web interface:

yaml
web:
  theme: dark  # or "light"
  
  auth:
    method: password  # "password" or "none"
    password_hash: "$argon2id$v=19$m=65536,t=3,p=4$..."
    session_secret: "your-random-secret-here"
    session_expiry_hours: 24

Fields:

  • theme: UI theme (dark or light)
  • auth.method: Authentication method
    • password: Require password login
    • none: No authentication (local development only)
  • auth.password_hash: Argon2 or bcrypt hash of your password
  • auth.session_secret: Random string for session encryption
  • auth.session_expiry_hours: Session timeout in hours

Generating a password hash:

bash
python -c "from argon2 import PasswordHasher; print(PasswordHasher().hash('your-password-here'))"
bash
python -c "import bcrypt; print(bcrypt.hashpw(b'your-password-here', bcrypt.gensalt()).decode())"
bash
docker exec -it workspace-secretary python -c "from argon2 import PasswordHasher; print(PasswordHasher().hash('your-password-here'))"

Generating session secret:

bash
# macOS/Linux
uuidgen

# Or use OpenSSL
openssl rand -hex 32

Login Credentials

When logging into the web UI, enter your plaintext password (the one you used to generate the hash), NOT the hash itself.

  • ✅ Login with: your-password-here (what you hashed)
  • ❌ Don't use: $argon2id$v=19$m=65536... (the hash)

See Web UI Guide for complete setup instructions.

Environment Variables

All fields can be overridden via environment variables:

VariableConfig PathExample
IMAP_HOSTimap.hostimap.gmail.com
IMAP_PORTimap.port993
IMAP_USERNAMEimap.usernameuser@gmail.com
WORKSPACE_TIMEZONEtimezoneAmerica/New_York
WORKING_HOURS_STARTworking_hours.start09:00
WORKING_HOURS_ENDworking_hours.end17:00
WORKING_HOURS_DAYSworking_hours.workdays1,2,3,4,5
VIP_SENDERSvip_sendersboss@co.com,ceo@co.com
POSTGRES_PASSWORDdatabase.postgres.password(secret)
OPENAI_API_KEYdatabase.embeddings.api_keysk-...

Docker Environment Example

yaml
# docker-compose.yml
services:
  workspace-secretary:
    image: ghcr.io/johnneerdael/gmail-secretary-map:latest
    environment:
      - WORKSPACE_TIMEZONE=America/Los_Angeles
      - WORKING_HOURS_START=09:00
      - WORKING_HOURS_END=17:00
      - VIP_SENDERS=boss@company.com,ceo@company.com

Validation

The server validates your config on startup:

  • Timezone: Must be valid IANA timezone
  • Working Hours: Times must be HH:MM format
  • Workdays: Must be integers 1-7
  • VIP Senders: Normalized to lowercase for matching
  • Aliases: Must be present (use [] if empty)

Example error:

ValueError: Invalid timezone: 'PST'. Use IANA format like 'America/Los_Angeles'

Configuration Precedence

Order of precedence (highest to lowest):

  1. Environment variables
  2. config.yaml file
  3. Default values

Complete Example

yaml
# config.yaml - mount as read-only (:ro)

bearer_auth:
  enabled: true
  token: "a1b2c3d4-e5f6-7890-abcd-ef1234567890"

identity:
  email: john@gmail.com
  full_name: "John Smith"
  aliases: []  # No aliases

imap:
  host: imap.gmail.com
  port: 993
  username: john@gmail.com
  use_ssl: true

smtp:
  host: smtp.gmail.com
  port: 587
  username: john@gmail.com
  use_tls: true

timezone: America/New_York

working_hours:
  start: "09:00"
  end: "18:00"
  workdays: [1, 2, 3, 4, 5]

vip_senders:
  - manager@company.com
  - ceo@company.com

calendar:
  enabled: true

# Optional: PostgreSQL for semantic search
database:
  backend: sqlite  # or 'postgres' for semantic search

Troubleshooting

"Invalid timezone" Error

Problem: ValueError: Invalid timezone: 'PST'

Solution: Use IANA format:

yaml
timezone: America/Los_Angeles  # Not 'PST'

"Working hours must be HH:MM" Error

Problem: ValueError: start time must be in HH:MM format

Solution: Use 24-hour format with leading zeros:

yaml
working_hours:
  start: "09:00"  # Not "9:00 AM"

OAuth Token Refresh Fails

Problem: 401 Unauthorized after some time

Solution: Re-run auth setup to get fresh tokens:

bash
# Local
uv run python -m workspace_secretary.auth_setup \
  --config config.yaml \
  --token-output token.json

# Docker
 docker exec -it workspace-secretary \
   python -m workspace_secretary.auth_setup \
   --config /app/config/config.yaml \
   --token-output /app/config/token.json

"aliases" Field Missing

Problem: Validation error about missing aliases

Solution: Always include aliases, even if empty:

yaml
identity:
  email: john@gmail.com
  aliases: []  # Required!

Next: Learn Agent Patterns for building intelligent workflows.

Released under the MIT License.