Files
mcp-home/CLAUDE.md
T
Stefan Lohmaier fb642e47c8 Initial commit: 5 MCP servers for Mail, Calendar, Contacts, Files, Notes
Self-hosted MCP servers with OAuth client_credentials auth.
Each server connects to a different backend:
- Mail: reads Maildir IMAP backups
- Calendar/Tasks: CalDAV against Radicale
- Contacts: CardDAV against Radicale
- Files: WebDAV against oCIS
- Notes: Joplin REST API

Credentials externalized to config.json (not in repo).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 06:22:42 +02:00

3.0 KiB

mcp-home

Self-hosted MCP (Model Context Protocol) servers for Claude. Provides access to personal data services via remote HTTP endpoints with OAuth client_credentials auth.

Architecture

5 independent MCP servers, each on its own port, behind nginx reverse proxy at mcp.home.slohmaier.de:

  • Mail (Port 5100) — searches IMAP backup Maildirs
  • Calendar (Port 5101) — CalDAV against Radicale (events + tasks/reminders)
  • Contacts (Port 5102) — CardDAV against Radicale
  • Files (Port 5103) — WebDAV against oCIS
  • Notes (Port 5104) — Joplin REST API

All servers share common.py for OAuth token handling and user resolution.

Auth Flow

OAuth client_credentials grant — no browser redirect needed:

  1. Client POSTs to /<service>/token with client_id + client_secret
  2. Server returns access_token (valid 24h)
  3. Client sends Authorization: Bearer <token> with MCP requests
  4. User is identified by client_id (matches tokens.json)

OAuth metadata at /<service>/.well-known/oauth-authorization-server.

User Separation

tokens.json (not in git, chmod 600) maps client_id → user. Each user only sees their own data. Shared CalDAV calendars are visible to both users.

Files

  • common.py — OAuth endpoints, Bearer middleware, user resolution via contextvars
  • tokens.json — client_id/secret per user (generate with python3 -c "import secrets; print(secrets.token_urlsafe(48))")
  • mail/server.py — Maildir reader, search across subject/from/to/body
  • calendar/server.py — CalDAV REPORT queries, event/task CRUD, vobject serialization
  • contacts/server.py — CardDAV addressbook-query, vCard parsing, contact CRUD
  • files/server.py — WebDAV PROPFIND/GET, recursive search, text file reading
  • notes/server.py — Joplin REST API wrapper (needs per-user API token in code)

Dependencies

pip install mcp[cli] httpx vobject python-dateutil

Python 3.12+, venv at ./venv/.

Deployment

Each server runs as systemd unit (mcp-<name>.service), managed by uvicorn. nginx at mcp.home.slohmaier.de proxies /<service>/ to the right port. TLS via Certbot.

Adding a New Service

  1. Create <name>/server.py with FastMCP instance + create_app() using the same pattern
  2. Import get_current_user, OAUTH_ROUTES, BearerAuthMiddleware from common.py
  3. Add nginx location block for /<name>/
  4. Create systemd unit mcp-<name>.service
  5. Update tokens.json if the new service needs different user mapping

Tool Design Guidelines

  • Every tool docstring is the first thing Claude sees — make it actionable ("Call this first", "Use the UID from search results")
  • Use Annotated[str, Field(description="...")] with example values for every parameter
  • Indicate which parameters are optional ("Leave empty for all")
  • Reference other tools in descriptions ("Use get_contact with the UID for full details")
  • Return structured text, not JSON — Claude parses text faster
  • Include UIDs/keys in output so Claude can chain to detail tools without asking the user