# 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 `//token` with `client_id` + `client_secret` 2. Server returns `access_token` (valid 24h) 3. Client sends `Authorization: Bearer ` with MCP requests 4. User is identified by `client_id` (matches `tokens.json`) OAuth metadata at `//.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-.service`), managed by uvicorn. nginx at `mcp.home.slohmaier.de` proxies `//` to the right port. TLS via Certbot. ## Adding a New Service 1. Create `/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 `//` 4. Create systemd unit `mcp-.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