-- Per-user MCP access tokens. Users mint tokens from the settings UI and -- paste them into their local Claude (`claude mcp add --transport http ...`). -- The plaintext token is shown ONCE at creation time; we only store the hash. -- -- token_hash is a SHA-256 hex digest of the plaintext token. Lookup on -- incoming requests: hash the bearer, look up the row, accept if not revoked. -- -- revoked_at is NULL for active tokens. Tokens are never deleted (audit -- trail); revocation is a soft delete. CREATE TABLE IF NOT EXISTS mcp_tokens ( id TEXT PRIMARY KEY, user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE, token_hash TEXT NOT NULL UNIQUE, name TEXT NOT NULL DEFAULT '', created_at TEXT NOT NULL, last_used_at TEXT, revoked_at TEXT ); CREATE INDEX IF NOT EXISTS idx_mcp_tokens_user_active ON mcp_tokens(user_id) WHERE revoked_at IS NULL; CREATE INDEX IF NOT EXISTS idx_mcp_tokens_hash_active ON mcp_tokens(token_hash) WHERE revoked_at IS NULL;