--- category: reference tags: - vs-2 - oauth - mcp - infrastructure last_updated: 2026-03-15 --- # VS-2: Persistent MCP OAuth for Claude.ai ## Problem The otterwiki-mcp server used FastMCP's `InMemoryOAuthProvider` for OAuth 2.1. All OAuth state (registered clients, authorization codes, access/refresh tokens) was lost on every server restart, forcing Claude.ai to re-authorize each time. ## Solution Replaced `InMemoryOAuthProvider` with `SQLiteOAuthProvider` — a drop-in persistent provider backed by a local SQLite database. ## Changes | File | Description | |------|-------------| | `otterwiki_mcp/oauth_store.py` | New SQLiteOAuthProvider implementing FastMCP's OAuthProvider interface | | `otterwiki_mcp/server.py` | Swapped InMemoryOAuthProvider for SQLiteOAuthProvider | | `otterwiki_mcp/config.py` | Added `MCP_OAUTH_DB` env var (default: `mcp_oauth.db`) | | `tests/test_oauth_store.py` | 20 tests covering registration, auth flow, tokens, refresh, revocation, persistence | | `tests/test_server_auth.py` | Updated to expect SQLiteOAuthProvider; uses `:memory:` DB for test isolation | | `.gitignore` | Added `*.db` pattern | ## Configuration - **`MCP_OAUTH_DB`** — Path to the SQLite database file. Default: `mcp_oauth.db` in the working directory. Set to `:memory:` for ephemeral (test) usage. ## Token Lifetimes | Token Type | Expiry | |------------|--------| | Authorization code | 10 minutes | | Access token | 1 hour | | Refresh token | 30 days | ## Schema Three tables, auto-created on first use: - **oauth_clients** — Registered OAuth clients (client_id, full client JSON, created_at) - **oauth_codes** — Authorization codes (code, client_id, redirect_uri, PKCE challenge, scopes, expiry, resource) - **oauth_tokens** — Access and refresh tokens stored as paired rows (token, client_id, scopes, expiry, type, paired counterpart, resource) Token pairs are linked: revoking either token in a pair removes both. ## Branch `feat/persistent-oauth` on otterwiki-mcp repo. Not pushed, not merged. ## Test Results All 133 tests pass (20 new + 113 existing).