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).
# Copy sample config
cp config.sample.yaml config.yaml
# After OAuth setup, token.json is created automaticallyCritical: Separate Token Storage
OAuth tokens are stored in token.json, NOT in config.yaml. This allows:
config.yamlmounted read-only (:ro) for securitytoken.jsonmounted 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.
bearer_auth:
enabled: true
token: "your-secure-token-here"Generate a unique token:
uuidgen# uuidgen (install uuid-runtime if not available)
uuidgen
# Or use OpenSSL (always available)
openssl rand -hex 32[guid]::NewGuid().ToString()Linux Note
On some Linux distributions, uuidgen requires the uuid-runtime package:
# Debian/Ubuntu
sudo apt install uuid-runtime
# RHEL/CentOS/Fedora
sudo dnf install util-linuxUser Identity
identity:
email: your-email@gmail.com
full_name: "Your Full Name"
aliases: [] # Empty list if you have no aliasesFields:
email(required): Your primary Gmail addressfull_name(optional): Used to detect if you're mentioned in email bodyaliases(required): Additional email addresses, or[]if none
Always Include aliases
Even if you have no aliases, you must include the field:
aliases: [] # Required - empty list if no aliasesUsed by:
get_daily_briefing: Signalsis_addressed_to_meandmentions_my_namequick_clean_inbox: Determines which emails can be auto-cleaned
IMAP Configuration
imap:
host: imap.gmail.com
port: 993
username: your-email@gmail.com
use_ssl: trueOAuth 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
smtp:
host: smtp.gmail.com
port: 587
username: your-email@gmail.com
use_tls: trueUses the same OAuth token from token.json for authentication.
Timezone
timezone: Europe/Amsterdam # IANA timezone formatValid formats: IANA Time Zone Database names:
America/Los_Angeles(notPST)Europe/London(notGMT)Asia/Tokyo(notJST)
Working Hours
working_hours:
start: "09:00" # HH:MM format, 24-hour clock
end: "17:00"
workdays: [1, 2, 3, 4, 5] # 1=Monday, 7=SundayRules:
- Times must be in
HH:MMformat (e.g.,09:00, not9:00 AM) - Workdays:
1=Monday through7=Sunday - Tools like
suggest_reschedule()only suggest times within these constraints - Agents will still ask before declining meetings outside working hours
VIP Senders
vip_senders:
- boss@company.com
- ceo@company.com
- important-client@example.comOr if you have no VIPs:
vip_senders: []Rules:
- Exact email addresses (case-insensitive)
- Emails from these senders get
is_from_vip=truein signals
Database Configuration
Secretary MCP supports two database backends for email caching.
SQLite (Default)
No configuration needed—SQLite is automatic:
database:
backend: sqlite # Default, can be omittedCache 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):
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_DOCUMENTWhen to use PostgreSQL:
- Need semantic search ("find emails about budget concerns")
- Want
find_related_emailsfor 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:
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
calendar:
enabled: trueDefault: Calendar tools disabled unless explicitly enabled.
Web UI Configuration
Configure the optional web interface:
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: 24Fields:
theme: UI theme (darkorlight)auth.method: Authentication methodpassword: Require password loginnone: No authentication (local development only)
auth.password_hash: Argon2 or bcrypt hash of your passwordauth.session_secret: Random string for session encryptionauth.session_expiry_hours: Session timeout in hours
Generating a password hash:
python -c "from argon2 import PasswordHasher; print(PasswordHasher().hash('your-password-here'))"python -c "import bcrypt; print(bcrypt.hashpw(b'your-password-here', bcrypt.gensalt()).decode())"docker exec -it workspace-secretary python -c "from argon2 import PasswordHasher; print(PasswordHasher().hash('your-password-here'))"Generating session secret:
# macOS/Linux
uuidgen
# Or use OpenSSL
openssl rand -hex 32Login 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:
| Variable | Config Path | Example |
|---|---|---|
IMAP_HOST | imap.host | imap.gmail.com |
IMAP_PORT | imap.port | 993 |
IMAP_USERNAME | imap.username | user@gmail.com |
WORKSPACE_TIMEZONE | timezone | America/New_York |
WORKING_HOURS_START | working_hours.start | 09:00 |
WORKING_HOURS_END | working_hours.end | 17:00 |
WORKING_HOURS_DAYS | working_hours.workdays | 1,2,3,4,5 |
VIP_SENDERS | vip_senders | boss@co.com,ceo@co.com |
POSTGRES_PASSWORD | database.postgres.password | (secret) |
OPENAI_API_KEY | database.embeddings.api_key | sk-... |
Docker Environment Example
# 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.comValidation
The server validates your config on startup:
- Timezone: Must be valid IANA timezone
- Working Hours: Times must be
HH:MMformat - 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):
- Environment variables
config.yamlfile- Default values
Complete Example
# 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 searchTroubleshooting
"Invalid timezone" Error
Problem: ValueError: Invalid timezone: 'PST'
Solution: Use IANA format:
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:
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:
# 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:
identity:
email: john@gmail.com
aliases: [] # Required!Next: Learn Agent Patterns for building intelligent workflows.