docs: optimize CLAUDE.md for db scripts, uv run, and deployment modes

- Discourage raw docker exec for database queries; use scripts/dbquery.py
  and scripts/sqlitequery.py exclusively
- Ensure all python commands use uv run prefix (mcp run, pytest, etc.)
- Replace Progressive Consent section with concise Deployment Modes
  overview (single-user, multi-user BasicAuth, Login Flow v2)
- Normalize docker-compose to docker compose throughout

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2026-04-01 15:52:51 +02:00
co-authored by Claude Opus 4.6
parent cbef665411
commit 270ef82527
+36 -75
View File
@@ -52,9 +52,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
- **Decorators**: `@require_scopes`, `@require_provisioning` for access control
- **Context pattern**: `await get_client(ctx)` to access authenticated NextcloudClient (async!)
- **FastMCP decorators**: `@mcp.tool()`, `@mcp.resource()`
- **Token acquisition**: `get_client()` handles both pass-through and token exchange modes
- Pass-through (default): Simple, stateless (ENABLE_TOKEN_EXCHANGE=false)
- Token exchange (opt-in): RFC 8693 delegation (ENABLE_TOKEN_EXCHANGE=true)
- **Token acquisition**: `get_client()` resolves credentials per deployment mode (see Deployment Modes below)
### MCP Tool Annotations (ADR-017)
@@ -199,20 +197,20 @@ uv run pytest tests/client/notes/test_notes_api.py -v
```
**Important**: After code changes, rebuild the correct container:
- Single-user tests: `docker-compose up --build -d mcp`
- OAuth tests: `docker-compose up --build -d mcp-oauth`
- Keycloak tests: `docker-compose up --build -d mcp-keycloak`
- Single-user tests: `docker compose up --build -d mcp`
- OAuth tests: `docker compose up --build -d mcp-oauth`
- Keycloak tests: `docker compose up --build -d mcp-keycloak`
### Running the Server
```bash
# Local development
export $(grep -v '^#' .env | xargs)
mcp run --transport sse nextcloud_mcp_server.app:mcp
uv run mcp run --transport sse nextcloud_mcp_server.app:mcp
# Docker development (rebuilds after code changes)
docker-compose up --build -d mcp # Single-user (port 8000)
docker-compose up --build -d mcp-oauth # Nextcloud OAuth (port 8001)
docker-compose up --build -d mcp-keycloak # Keycloak OAuth (port 8002)
docker compose up --build -d mcp # Single-user (port 8000)
docker compose up --build -d mcp-oauth # Nextcloud OAuth (port 8001)
docker compose up --build -d mcp-keycloak # Keycloak OAuth (port 8002)
```
### Environment Setup
@@ -239,9 +237,11 @@ uv run python -m tests.load.benchmark --output results.json --verbose
**Credentials**: root/password, nextcloud/password, database: `nextcloud`
### Quick Query Script (Recommended for Agents)
**Do NOT use `docker compose exec db mariadb` or `docker compose exec <service> sqlite3` directly.** Use the wrapper scripts below instead -- they handle credentials, output formatting, and avoid repeated docker exec approvals.
Use `scripts/dbquery.py` for single SQL statements without requiring approval for each `docker compose exec`:
### MariaDB (Nextcloud)
Use `scripts/dbquery.py` for all MariaDB queries:
```bash
# Basic query
@@ -254,27 +254,6 @@ Use `scripts/dbquery.py` for single SQL statements without requiring approval fo
./scripts/dbquery.py -u nextcloud -p nextcloud "SHOW TABLES"
```
### Direct Docker Access
For interactive sessions or complex operations:
```bash
# Connect to database
docker compose exec db mariadb -u root -ppassword nextcloud
# Check OAuth clients
docker compose exec db mariadb -u root -ppassword nextcloud -e \
"SELECT id, name, token_type FROM oc_oidc_clients ORDER BY id DESC LIMIT 10;"
# Check OAuth client scopes
docker compose exec db mariadb -u root -ppassword nextcloud -e \
"SELECT c.id, c.name, s.scope FROM oc_oidc_clients c LEFT JOIN oc_oidc_client_scopes s ON c.id = s.client_id WHERE c.name LIKE '%MCP%';"
# Check OAuth access tokens
docker compose exec db mariadb -u root -ppassword nextcloud -e \
"SELECT id, client_id, user_id, created_at FROM oc_oidc_access_tokens ORDER BY created_at DESC LIMIT 10;"
```
**Important Tables**:
- `oc_oidc_clients` - OAuth client registrations (DCR)
- `oc_oidc_client_scopes` - Client allowed scopes
@@ -283,9 +262,9 @@ docker compose exec db mariadb -u root -ppassword nextcloud -e \
- `oc_oidc_registration_tokens` - RFC 7592 registration tokens
- `oc_oidc_redirect_uris` - Redirect URIs
### SQLite Databases (MCP Services)
### SQLite (MCP Services)
Use `scripts/sqlitequery.py` to query SQLite databases in MCP service containers:
Use `scripts/sqlitequery.py` for all SQLite queries:
```bash
# List tables
@@ -338,48 +317,29 @@ Use `scripts/sqlitequery.py` to query SQLite databases in MCP service containers
3. MCP tools use context pattern: `get_client(ctx)` → `NextcloudClient`
4. All operations are async using httpx
### Progressive Consent Architecture (ADR-004)
### Deployment Modes
**Important**: Progressive consent is a *mechanism* for granting access, not a feature flag. The architecture is always present in OAuth mode. Whether provisioning tools are available is controlled by `ENABLE_OFFLINE_ACCESS`.
The server supports three deployment modes, controlled by environment variables and docker compose profiles:
**What is Progressive Consent?**
- Dual OAuth flow architecture that separates client authentication (Flow 1) from resource provisioning (Flow 2)
- Flow 1: MCP client authenticates directly to IdP with resource scopes (notes:*, calendar:*, etc.)
- Token audience: "mcp-server"
- Client receives resource-scoped token for MCP session
- Flow 2: Server explicitly provisions Nextcloud access via separate login (only when `ENABLE_OFFLINE_ACCESS=true`)
- Server requests: openid, profile, email, offline_access
- Token audience: "nextcloud"
- Server receives refresh token for offline access
- Client never sees this token
- Provides clear separation between session tokens and offline access tokens
**1. Single-User** (profile: `single-user`)
- Set `NEXTCLOUD_USERNAME` + `NEXTCLOUD_PASSWORD` (app password)
- One shared Nextcloud identity for all MCP requests
- Stateless, no persistent storage needed
- Best for: personal instances, local development
**Modes:**
- **Pass-through mode** (`ENABLE_OFFLINE_ACCESS=false`, default):
- No Flow 2 provisioning
- Server uses client's token to access Nextcloud (pass-through)
- No provisioning tools available
- Suitable for stateless, client-driven operations
- **Offline access mode** (`ENABLE_OFFLINE_ACCESS=true`):
- Flow 2 provisioning available
- Server stores refresh tokens for background operations
- Provisioning tools available: `provision_nextcloud_access`, `check_logged_in`
- Suitable for background jobs and server-initiated operations
**2. Multi-User BasicAuth** (profile: `multi-user-basic`)
- Set `ENABLE_MULTI_USER_BASIC_AUTH=true`
- Each MCP client provides credentials via HTTP Authorization header
- Per-request client creation from extracted credentials
- Best for: internal deployments where users manage their own Nextcloud credentials
**When to use OAuth mode:**
- Multi-user deployments
- Background jobs requiring offline access (with `ENABLE_OFFLINE_ACCESS=true`)
- Enhanced security with separate authorization contexts
- Explicit user control over resource access
**When to use BasicAuth instead:**
- Simple single-user deployments
- Local development and testing
**Key features:**
- No scope escalation - client gets exactly what it requests
- User explicitly authorizes via `provision_nextcloud_access` tool
- Clear security boundaries between MCP session and Nextcloud access
**3. Login Flow v2** (profile: `login-flow`)
- Browser-based app password acquisition via Nextcloud's native Login Flow v2 API
- Per-user app passwords stored encrypted in SQLite
- Application-level scope enforcement (defense-in-depth)
- Works with any Nextcloud 16+ instance (no special apps required)
- Best for: production multi-user deployments, OAuth MCP integration
- See `docs/ADR-022-login-flow-v2.md` for architecture details
## MCP Response Patterns (CRITICAL)
@@ -541,7 +501,7 @@ uv run pytest tests/server/oauth/test_oauth_core.py --browser firefox --headed -
**Setup**:
```bash
docker-compose up -d keycloak app mcp-keycloak
docker compose up -d keycloak app mcp-keycloak
curl http://localhost:8888/realms/nextcloud-mcp/.well-known/openid-configuration
docker compose exec app php occ user_oidc:provider keycloak
```
@@ -557,7 +517,8 @@ docker compose exec app php occ user_oidc:provider keycloak
## Integration Testing with Docker
**Nextcloud**: `docker compose exec app php occ ...` for occ commands
**MariaDB**: `docker compose exec db mariadb -u [user] -p [password] [database]` for queries
**MariaDB**: Use `./scripts/dbquery.py` for queries (see Database Inspection above)
**SQLite**: Use `./scripts/sqlitequery.py` for MCP service databases
### Querying Nextcloud Application Logs