16 Commits

Author SHA1 Message Date
Stefan Lohmaier a811e87029 Update docs: CLAUDE.md, README, config example
- CLAUDE.md: subdomains, OAuth Auth Code+PKCE, shared token store,
  all backends incl Joplin Data API, content types, current tool list
- README: full tool inventory per service, correct setup steps
- config.json.example: joplin_login + joplin_data_api fields documented

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 12:35:35 +02:00
Stefan Lohmaier c06e6d6b4c Joplin via Data API + Mail attachments
Notes server rewritten to use Joplin CLI Data API (joplin-cli sync
clients on host, ports 41184/41185). Clean fast search, proper
resource handling. New tools: list_note_resources, read_resource
(attachments as inline image/document/text).

Mail server: read_mail now lists attachments; new read_attachment
tool returns images inline, PDFs/docs as EmbeddedResource, text directly.

Tests: 54 total. Notes now real (notebooks, list, create+read).
Mail attachment listing + fetch tested.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 12:26:26 +02:00
Stefan Lohmaier 38cf147eec Fix Files tests: isolated test dir, auto-create and cleanup
Tests create /.mcp-tests/ in oCIS at start, delete at end.
No interference with user's real files. Fixed for stefan's
actual oCIS account (was using admin before).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 10:51:58 +02:00
Stefan Lohmaier e721250552 Expand test suite to 51 tests with full CRUD coverage
Test collections: calendar-test, contacts-test, /mcp-tests/
- OAuth: 30 tests (metadata, credentials, PKCE, rejection, tools list × 5 servers)
- Mail: 5 tests (accounts, folders, search, empty search, read full mail)
- Calendar: 5 tests (list, tasks, create event + verify, create task + verify, date range)
- Contacts: 4 tests (search, empty, create + verify, get details)
- Files: 6 tests (list, info, write+read+delete, create+delete folder, move, search)
- Notes: 1 test (list notebooks)

All tests create unique timestamped data and clean up after themselves.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 10:36:29 +02:00
Stefan Lohmaier 2618ecfc86 Add test client and automated integration test suite
- 'test' OAuth client maps to stefan's data via USER_ALIASES
- 38 tests covering OAuth (metadata, client_credentials, PKCE, invalid
  secret, no auth), Mail (accounts, folders, search), Calendar
  (calendars, tasks, events, search), Contacts (search, empty),
  Files (list, info), Notes (notebooks)
- Daily systemd timer (05:00) with NTFY notification on failure
- Shared token store (.active_tokens.json) for cross-process auth

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 10:33:01 +02:00
Stefan Lohmaier ef37d1e467 Fix Mail Maildir paths and oCIS auth
Mail: INBOX is a subfolder (INBOX/cur), not the account root.
Removed special-case mapping that pointed INBOX to root dir.

Files: oCIS user may differ from MCP user (e.g. stefan -> admin).
Added _ocis_user() mapping for WebDAV paths and auth.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 10:22:27 +02:00
Stefan Lohmaier 80fc323374 Fix XML namespace handling for Radicale responses
Radicale uses default DAV: namespace (no d: prefix) and CR: for CardDAV
instead of c:. Fixed all regex patterns to handle both variants:
- <href> and <d:href>
- <displayname> and <d:displayname>
- <CR:address-data> and <c:address-data>
- <C:calendar-data> and <c:calendar-data>
- </response> and </d:response>

Also fixed calendar discovery to match <C:calendar/> resourcetype
instead of looking for VEVENT string in the response.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 10:17:14 +02:00
Stefan Lohmaier 45cd6935fb Security: verify client_secret in authorization_code flow + shared token store
- Token exchange now requires valid client_secret (was missing)
- Access tokens stored in shared .active_tokens.json (cross-process)
- nginx rate limiting on /authorize and /token (10r/m, burst=5)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 09:34:18 +02:00
Stefan Lohmaier 30351f1bcf Switch to per-service subdomains, shared token store
URLs: mail.mcp.home.slohmaier.de, calendar.mcp..., etc.
No more path-prefix routing — each service has its own domain.
OAuth tokens stored in shared .active_tokens.json file so all
services can validate tokens issued by any service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 09:13:54 +02:00
Stefan Lohmaier 7f0b03606a Add OAuth Authorization Code flow with PKCE for claude.ai
claude.ai uses the full OAuth Authorization Code flow, not client_credentials.
Flow: GET /authorize → auto-approve → redirect with code → POST /token
with code + code_verifier (PKCE S256).

Also fixes OAuth metadata URLs to use correct external scheme/host/prefix
via X-Forwarded-Proto, Host, and X-Forwarded-Prefix headers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 08:48:34 +02:00
Stefan Lohmaier 1f98695821 Add create_draft tool to Mail server
Creates email drafts via IMAP APPEND to the Drafts folder.
Supports Stefan (1blu, Drafts folder) and Kati (Gmail, Entwürfe).
Draft can be reviewed and sent from Roundcube or phone.

IMAP credentials externalized to config.json.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 08:16:53 +02:00
Stefan Lohmaier 5190e8c849 Add write_file, create_folder, delete_file, move_file to Files server
Full CRUD for oCIS files:
- write_file: text or base64 binary content
- create_folder: MKCOL
- delete_file: DELETE (files and folders)
- move_file: MOVE (rename or relocate)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 08:08:08 +02:00
Stefan Lohmaier b88adc4c50 read_file: pass binary documents as EmbeddedResource
PDF, docx, xlsx, pptx etc. are returned as EmbeddedResource with
BlobResourceContents (base64 + mimeType). claude.ai processes these
client-side, same as Google Drive/Dropbox MCP connectors.

Fallback chain: text → image → embedded resource (binary).
MIME type guessed from extension when server returns octet-stream.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 08:02:32 +02:00
Stefan Lohmaier a9359beead Add image support to Files and contact photos to Contacts
Files:
- read_file returns images inline (jpg/png/gif/webp up to 10MB)
- Text files returned as text, binary files as metadata only

Contacts:
- get_contact includes contact photo as inline image if available
- New tool: set_contact_photo (base64 jpeg/png → VCard PHOTO)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 07:53:55 +02:00
Stefan Lohmaier 924366ac6c Add travel time, geocoding, and reminders to create_event
- travel_minutes: shows as gray block before event on iPhone
- location geocoding via Nominatim → X-APPLE-STRUCTURED-LOCATION with geo coords
- reminder_minutes: VALARM trigger before event
- Also externalized all credentials to config.json

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-12 07:28:00 +02:00
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