Security
Architecture
Two separate OAuth layers: MCP clients authorize against this service (OAuth 2.1, PKCE S256 only, no implicit flow), and this service holds a delegated Microsoft grant per connected account. Client-facing tokens carry only opaque identifiers; Microsoft tokens never leave the server-side vault.
Credential storage
Microsoft tokens are sealed with AES-256-GCM before they touch storage, with key versioning for rotation. Vault identifiers and ownership keys are one-way HMAC derivations, so knowing someone's Microsoft account id does not locate their vault. A Durable Object id alone is not authorization: every read requires the matching ownership key.
Abuse controls
Dynamic client registration is rate-limited per address, and each account has a per-minute Graph-work budget. Every tool also has independent work-unit, deadline, Graph-response, argument, and result-size ceilings; batches are charged by subrequest and retries are charged again. Resumable mutations use encrypted, leased journals and exact markers or postconditions instead of blindly repeating an ambiguous write. Destructive tools (deleting tasks, lists, or contacts) are not part of the default surface; an operator enables them per deployment. The tenant offboarding route has a bearer key independent of the read-only status key and preserves post-snapshot reconnects. Browser pages run no JavaScript and send a restrictive Content-Security-Policy.
Stated residual risks
Deliberate tradeoffs, documented so reviewers do not have to guess: the per-account rate-limit window is in-memory and resets if the vault restarts; audit events carry no account attribution by design, so per-user abuse forensics are intentionally not possible; and task or contact content that reaches your MCP client is processed by that client's model provider.
Reporting a vulnerability
Please report security issues to Ian Anderson. Do not open a public issue for a vulnerability that could expose user data.