Tightens verifier consistency, closes test gaps, hardens the fire-and-forget eviction snapshot, and routes the new concurrency knob through Settings. - Pre-flight ``int()`` guard in ``_verify_notes`` mirrors ``_verify_deck_cards``, so a non-numeric note id produces a type-specific log line instead of falling through to the generic "unexpected error" branch. - Adds explicit 403 tests for the file and news verifiers (symmetry with the existing notes/deck 403 tests) plus a ``non_numeric_id_keeps`` test. - ``AppContext`` and ``OAuthAppContext`` no longer snapshot ``_vector_sync_state.eviction_task_group`` at lifespan-yield time. Both expose it as a ``@property`` that reads the singleton dynamically, removing the order-sensitive race where a future startup-ordering change could silently degrade fire-and-forget eviction to inline forever. - Adds ``verification_concurrency`` (env var ``VERIFICATION_CONCURRENCY``, default 20) to ``Settings`` with a dynaconf validator; ``verify_search_results`` resolves the cap lazily from settings when the caller doesn't override it. - Enriches the news verifier TODO to call out that ``batch_size=-1`` is intentional — a numeric ceiling would silently break correctness because any item beyond the cap would be missing from ``present_ids`` and dropped. - Updates ``Optional[TaskGroup]`` to ``TaskGroup | None`` per project style. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
26 KiB
Configuration
The Nextcloud MCP server requires configuration to connect to your Nextcloud instance. Configuration is provided through environment variables, typically stored in a .env file.
Note: Configuration was significantly simplified in v0.58.0. If you're upgrading from v0.57.x, see the Configuration Migration Guide.
Quick Start
We provide mode-specific configuration templates for quick setup:
# Choose a template based on your deployment mode:
cp env.sample.single-user .env # Simplest - one user, local dev
cp env.sample .env # Full reference with all options
# For multi-user Login Flow v2 (recommended), see the dedicated guide:
# docs/login-flow-v2.md#setup
# Edit .env with your Nextcloud details
Note: The legacy templates
env.sample.oauth-multi-userandenv.sample.oauth-advancedconfigure the deprecated direct-OAuth-to-Nextcloud modes. New deployments should use Login Flow v2 for multi-user setups.
Then choose your deployment mode:
- Single-User BasicAuth - Simplest for personal instances
- Multi-User BasicAuth - Internal deployments with credential pass-through
- Login Flow v2 - Recommended for hosted / OAuth-based MCP clients
- Deployment Mode Selection - Explicit mode declaration
Deployment Mode Selection
The server supports three deployment modes. See Authentication for the full comparison and Login Flow v2 for the recommended multi-user setup.
| Mode | When to use |
|---|---|
single_user_basic |
Personal use, dev — credentials in env vars |
multi_user_basic |
Internal deployments — clients send credentials via Authorization: Basic header |
login_flow_v2 |
Hosted / OAuth-based MCP clients (claude.ai, Astrolabe Cloud) — recommended for multi-user |
You can declare the mode explicitly:
MCP_DEPLOYMENT_MODE=login_flow_v2
If MCP_DEPLOYMENT_MODE is not set, the server auto-detects from the other env vars below.
Single-User BasicAuth Mode
The simplest mode. Use for personal instances, local development, and testing.
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
NEXTCLOUD_USERNAME=your_nextcloud_username
NEXTCLOUD_PASSWORD=your_app_password
| Variable | Required | Description |
|---|---|---|
NEXTCLOUD_HOST |
✅ Yes | Full URL of your Nextcloud instance |
NEXTCLOUD_USERNAME |
✅ Yes | Your Nextcloud username |
NEXTCLOUD_PASSWORD |
✅ Yes | Use a dedicated Nextcloud app password, not your login password |
Multi-User BasicAuth Mode
Each MCP client sends its own Nextcloud credentials in an Authorization: Basic header. The server passes them through per-request and never persists them.
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
ENABLE_MULTI_USER_BASIC_AUTH=true
# Optional: enable per-user app-password storage for background sync
TOKEN_ENCRYPTION_KEY=<fernet-key>
TOKEN_STORAGE_DB=/app/data/tokens.db
NEXTCLOUD_USERNAME and NEXTCLOUD_PASSWORD must NOT be set in this mode.
Login Flow v2 Mode
The recommended multi-user mode. MCP clients authenticate to the MCP server via OAuth; the server holds per-user Nextcloud app passwords (encrypted) obtained via Login Flow v2.
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
ENABLE_LOGIN_FLOW=true
# App-password storage (required)
TOKEN_ENCRYPTION_KEY=<fernet-key>
TOKEN_STORAGE_DB=/app/data/tokens.db
# Public URLs for browser redirects
NEXTCLOUD_MCP_SERVER_URL=https://mcp.example.com
NEXTCLOUD_PUBLIC_ISSUER_URL=https://your.nextcloud.instance.com
| Variable | Required | Description |
|---|---|---|
NEXTCLOUD_HOST |
✅ Yes | Internal URL of your Nextcloud instance (server-to-server) |
ENABLE_LOGIN_FLOW |
✅ Yes | Set to true to enable Login Flow v2 |
TOKEN_ENCRYPTION_KEY |
✅ Yes | Fernet key for app-password encryption — generate with python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" |
TOKEN_STORAGE_DB |
✅ Yes | Path to SQLite DB for stored app passwords (use a persistent volume) |
NEXTCLOUD_MCP_SERVER_URL |
✅ Yes | Public URL of the MCP server (used as the audience claim and for browser redirects) |
NEXTCLOUD_PUBLIC_ISSUER_URL |
✅ Yes | Public URL of Nextcloud (for browser redirects during Login Flow v2) |
NEXTCLOUD_OIDC_CLIENT_ID |
⚠️ Optional (preferred) | OIDC client ID for the MCP server's relying-party registration with the IdP (Nextcloud OIDC by default; Keycloak / Cognito / etc. via OIDC_DISCOVERY_URL). If unset and the IdP advertises a registration_endpoint, RFC 7591 DCR is used as fallback. |
NEXTCLOUD_OIDC_CLIENT_SECRET |
⚠️ Optional (preferred) | OIDC client secret paired with NEXTCLOUD_OIDC_CLIENT_ID. |
OIDC_DISCOVERY_URL |
Optional | Override the IdP discovery URL. Defaults to ${NEXTCLOUD_HOST}/.well-known/openid-configuration (Nextcloud's built-in OIDC). Set to a Keycloak realm or AWS Cognito user-pool discovery URL to use an external IdP. |
See Login Flow v2 for full setup, scope reference, and troubleshooting.
SSL/TLS Configuration (Optional)
If your Nextcloud instance uses a self-signed certificate or a private CA (common with reverse proxies like Traefik or Caddy), the MCP server will reject the connection by default. Use these settings to configure certificate verification.
Custom CA Bundle (Recommended)
Point the server at your CA certificate file:
NEXTCLOUD_CA_BUNDLE=/etc/ssl/certs/my-ca.pem
With Docker, mount the certificate as a read-only volume:
docker run \
-v /path/to/my-ca.pem:/etc/ssl/certs/my-ca.pem:ro \
-e NEXTCLOUD_CA_BUNDLE=/etc/ssl/certs/my-ca.pem \
-e NEXTCLOUD_HOST=https://nextcloud.local \
--env-file .env \
ghcr.io/cbcoutinho/nextcloud-mcp-server:latest
Disable Verification (Development Only)
Warning
Disabling TLS verification is insecure. Only use this for local development or testing.
NEXTCLOUD_VERIFY_SSL=false
Environment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
NEXTCLOUD_VERIFY_SSL |
⚠️ Optional | true |
Set to false to disable TLS certificate verification |
NEXTCLOUD_CA_BUNDLE |
⚠️ Optional | - | Path to a PEM CA bundle file for custom certificate authorities |
Scope
These settings apply to all outbound connections to Nextcloud and its OIDC endpoints, including:
- Nextcloud API calls (Notes, Calendar, Contacts, WebDAV, etc.)
- OIDC discovery and token endpoints
- OAuth client registration (DCR)
- Health checks
They do not affect connections to internal services (Ollama, Qdrant, Unstructured) which have their own SSL configuration.
Semantic Search Configuration (Optional)
New in v0.58.0: Simplified semantic search configuration with automatic dependency resolution.
The MCP server includes semantic search capabilities powered by vector embeddings. This feature requires a vector database (Qdrant) and an embedding service.
Quick Start
Single-User Mode:
NEXTCLOUD_HOST=http://localhost:8080
NEXTCLOUD_USERNAME=admin
NEXTCLOUD_PASSWORD=password
# Enable semantic search
ENABLE_SEMANTIC_SEARCH=true
# Vector database
QDRANT_LOCATION=:memory:
# Embedding provider
OLLAMA_BASE_URL=http://ollama:11434
Multi-User Login Flow v2 Mode:
NEXTCLOUD_HOST=https://nextcloud.example.com
MCP_DEPLOYMENT_MODE=login_flow_v2
ENABLE_LOGIN_FLOW=true
# Enable semantic search
# In multi-user modes, this AUTOMATICALLY enables background operations!
ENABLE_SEMANTIC_SEARCH=true
# Required for background operations (auto-enabled by semantic search)
TOKEN_ENCRYPTION_KEY=your-key-here
TOKEN_STORAGE_DB=/app/data/tokens.db
# Vector database
QDRANT_URL=http://qdrant:6333
# Embedding provider
OLLAMA_BASE_URL=http://ollama:11434
Note: In multi-user modes (Login Flow v2, Multi-User BasicAuth), enabling
ENABLE_SEMANTIC_SEARCHautomatically enables background operations and refresh token storage. You don't need to setENABLE_BACKGROUND_OPERATIONSseparately!
Qdrant Vector Database Modes
The server supports three Qdrant deployment modes:
- In-Memory Mode (Default) - Simplest for development and testing
- Persistent Local Mode - For single-instance deployments with persistence
- Network Mode - For production with dedicated Qdrant service
1. In-Memory Mode (Default)
No configuration needed! If neither QDRANT_URL nor QDRANT_LOCATION is set, the server defaults to in-memory mode:
# No Qdrant configuration needed - defaults to :memory:
ENABLE_SEMANTIC_SEARCH=true
Pros:
- Zero configuration
- Fast startup
- Perfect for testing
Cons:
- Data lost on restart
- Limited to available RAM
2. Persistent Local Mode
For single-instance deployments that need persistence without a separate Qdrant service:
# Local persistent storage
QDRANT_LOCATION=/app/data/qdrant # Or any writable path
ENABLE_SEMANTIC_SEARCH=true
Pros:
- Data persists across restarts
- No separate service needed
- Suitable for small/medium deployments
Cons:
- Limited to single instance
- Shares resources with MCP server
3. Network Mode
For production deployments with a dedicated Qdrant service:
# Network mode configuration
QDRANT_URL=http://qdrant:6333
QDRANT_API_KEY=your-secret-api-key # Optional
QDRANT_COLLECTION=nextcloud_content # Optional
ENABLE_SEMANTIC_SEARCH=true
Pros:
- Scalable and performant
- Can be shared across multiple MCP instances
- Supports clustering and replication
Cons:
- Requires separate Qdrant service
- More complex deployment
Qdrant Collection Naming
Collection names are automatically generated to include the embedding model, ensuring safe model switching and preventing dimension mismatches.
Auto-Generated Naming (Default)
Format: {deployment-id}-{model-name}
Components:
- Deployment ID:
OTEL_SERVICE_NAME(if configured) orhostname(fallback) - Model name:
OLLAMA_EMBEDDING_MODEL
Examples:
# With OTEL service name configured
OTEL_SERVICE_NAME=my-mcp-server
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
# → Collection: "my-mcp-server-nomic-embed-text"
# Simple Docker deployment (OTEL not configured)
# hostname=mcp-container
OLLAMA_EMBEDDING_MODEL=all-minilm
# → Collection: "mcp-container-all-minilm"
Switching Embedding Models
When you change OLLAMA_EMBEDDING_MODEL, a new collection is automatically created:
# Initial setup
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
# Collection: "my-server-nomic-embed-text" (768 dimensions)
# Change model
OLLAMA_EMBEDDING_MODEL=all-minilm
# Collection: "my-server-all-minilm" (384 dimensions)
# → New collection created, full re-embedding occurs
Important:
- Collections are mutually exclusive - vectors cannot be shared between different embedding models
- Switching models requires re-embedding all documents (may take time for large note collections)
- Old collection remains in Qdrant and can be deleted manually if no longer needed
Explicit Override
Set QDRANT_COLLECTION to use a specific collection name:
QDRANT_COLLECTION=my-custom-collection # Bypasses auto-generation
Use cases:
- Backward compatibility with existing deployments
- Custom naming schemes
- Sharing a collection across deployments (advanced)
Multi-Server Deployments
Each server should have a unique deployment ID to avoid collection collisions:
# Server 1 (Production)
OTEL_SERVICE_NAME=mcp-prod
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
# → Collection: "mcp-prod-nomic-embed-text"
# Server 2 (Staging)
OTEL_SERVICE_NAME=mcp-staging
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
# → Collection: "mcp-staging-nomic-embed-text"
# Server 3 (Different model)
OTEL_SERVICE_NAME=mcp-experimental
OLLAMA_EMBEDDING_MODEL=bge-large
# → Collection: "mcp-experimental-bge-large"
Benefits:
- Multiple MCP servers can share one Qdrant instance safely
- No naming collisions between deployments
- Clear collection ownership (can see which deployment and model)
Dimension Validation
The server validates collection dimensions on startup:
Dimension mismatch for collection 'my-server-nomic-embed-text':
Expected: 384 (from embedding model 'all-minilm')
Found: 768
This usually means you changed the embedding model.
Solutions:
1. Delete the old collection: Collection will be recreated with new dimensions
2. Set QDRANT_COLLECTION to use a different collection name
3. Revert OLLAMA_EMBEDDING_MODEL to the original model
What this prevents:
- Runtime errors from dimension mismatches
- Data corruption in Qdrant
- Confusing error messages during indexing
Background Indexing Configuration
Control background indexing behavior:
# Semantic search (ADR-007, ADR-021)
ENABLE_SEMANTIC_SEARCH=true # Enable background indexing
# Tuning parameters (advanced - only modify if needed)
VECTOR_SYNC_SCAN_INTERVAL=300 # Scan interval in seconds (default: 5 minutes)
VECTOR_SYNC_PROCESSOR_WORKERS=3 # Concurrent indexing workers (default: 3)
VECTOR_SYNC_QUEUE_MAX_SIZE=10000 # Max queued documents (default: 10000)
# Document chunking settings (for vector embeddings)
DOCUMENT_CHUNK_SIZE=512 # Words per chunk (default: 512)
DOCUMENT_CHUNK_OVERLAP=50 # Overlapping words between chunks (default: 50)
Note: The
VECTOR_SYNC_*tuning parameters keep their names as they're implementation details. Only the user-facing feature flag was renamed toENABLE_SEMANTIC_SEARCH.
Embedding Service Configuration
The server uses an embedding service to generate vector representations. Two options are available:
Ollama (Recommended)
Use a local Ollama instance for embeddings:
OLLAMA_BASE_URL=http://ollama:11434
OLLAMA_EMBEDDING_MODEL=nomic-embed-text # Default model
OLLAMA_VERIFY_SSL=true # Verify SSL certificates
Simple Embedding Provider (Fallback)
If OLLAMA_BASE_URL is not set, the server uses a simple random embedding provider for testing. This is not suitable for production as it generates random embeddings with no semantic meaning.
Document Chunking Configuration
The server chunks documents before embedding to handle documents larger than the embedding model's context window. Chunk size and overlap can be tuned based on your embedding model and content type.
Choosing Chunk Size
Smaller chunks (256-384 words):
- More precise matching
- Less context per chunk
- Better for finding specific information
- Higher storage requirements (more vectors)
Larger chunks (768-1024 words):
- More context per chunk
- Less precise matching
- Better for understanding broader topics
- Lower storage requirements (fewer vectors)
Default (512 words):
- Balanced approach suitable for most use cases
- Works well with typical note lengths
- Good compromise between precision and context
Choosing Overlap
Overlap preserves context across chunk boundaries. Recommended settings:
- 10-20% of chunk size (e.g., 50-100 words for 512-word chunks)
- Too small (<10%): May lose context at boundaries
- Too large (>20%): Redundant storage, diminishing returns
Examples:
# Precise matching for short notes
DOCUMENT_CHUNK_SIZE=256
DOCUMENT_CHUNK_OVERLAP=25
# Default balanced configuration
DOCUMENT_CHUNK_SIZE=512
DOCUMENT_CHUNK_OVERLAP=50
# More context for long documents
DOCUMENT_CHUNK_SIZE=1024
DOCUMENT_CHUNK_OVERLAP=100
Important: Changing chunk size requires re-embedding all documents. The collection naming strategy (see "Qdrant Collection Naming" above) helps manage this by creating separate collections for different configurations.
Verify-on-Read Latency Budget
Every semantic search request runs an access-control verification pass over its results before returning them, to filter out documents the user can no longer access (deleted, unshared, permissions changed). See ADR-019 for the full design.
This adds Nextcloud round-trips to the search path that operators should be aware of:
- Per-search cost: one Nextcloud round-trip per unique
(doc_id, doc_type)in the result set. Chunking means a 10-result page typically references 3-5 unique documents, so verification adds 3-5 round-trips. With the default 20-way concurrency this is one parallel batch — usually under 100 ms on a healthy connection. - Concurrency: all verifications fan out under a shared semaphore.
Tunable via the
VERIFICATION_CONCURRENCYenv var (settings fieldverification_concurrency, default 20) — lower it if your Nextcloud backend struggles with the parallel fan-out, or raise it on a healthy connection to speed up large result pages. - News API caveat: the News app has no per-item endpoint, so the news
verifier issues a single
news.get_items(batch_size=-1, get_read=True)call per search that contains any news result, then intersects locally. The payload is unbounded — for users with very large feed backlogs this can dominate verification latency. Disabling News in the indexer or running with a smaller backlog mitigates this; per-item paginated verification is tracked as a future improvement. - Eviction: when verification finds a definitive miss (404 / 403), the corresponding Qdrant points are deleted in the background on a lifespan-owned task group — fire-and-forget, does not block the search response. Eviction failures are logged but never propagated; the next query will re-verify and re-attempt (self-healing).
- Failure modes: transient errors (5xx, network) keep results visible (fail open) so a flaky link does not silently shrink result pages; only definitive 404 / 403 drops them.
If verification ever needs to be disabled (debugging, benchmarking), the
evict_on_missing=False flag on verify_search_results() skips eviction
without changing what is returned to the caller.
Environment Variables Reference
| Variable | Required | Default | Description |
|---|---|---|---|
ENABLE_SEMANTIC_SEARCH |
⚠️ Optional | false |
Enable semantic search with background indexing (replaces VECTOR_SYNC_ENABLED) |
QDRANT_URL |
⚠️ Optional | - | Qdrant service URL (network mode) - mutually exclusive with QDRANT_LOCATION |
QDRANT_LOCATION |
⚠️ Optional | :memory: |
Local Qdrant path (:memory: or /path/to/data) - mutually exclusive with QDRANT_URL |
QDRANT_API_KEY |
⚠️ Optional | - | Qdrant API key (network mode only) |
QDRANT_COLLECTION |
⚠️ Optional | Auto-generated | Qdrant collection name |
VECTOR_SYNC_SCAN_INTERVAL |
⚠️ Optional | 300 |
Document scan interval (seconds) |
VECTOR_SYNC_PROCESSOR_WORKERS |
⚠️ Optional | 3 |
Concurrent indexing workers |
VECTOR_SYNC_QUEUE_MAX_SIZE |
⚠️ Optional | 10000 |
Max queued documents |
OLLAMA_BASE_URL |
⚠️ Optional | - | Ollama API endpoint for embeddings |
OLLAMA_EMBEDDING_MODEL |
⚠️ Optional | nomic-embed-text |
Embedding model to use |
OLLAMA_VERIFY_SSL |
⚠️ Optional | true |
Verify SSL certificates |
DOCUMENT_CHUNK_SIZE |
⚠️ Optional | 512 |
Words per chunk for document embedding |
DOCUMENT_CHUNK_OVERLAP |
⚠️ Optional | 50 |
Overlapping words between chunks (must be < chunk size) |
Deprecated variables (still functional):
VECTOR_SYNC_ENABLED- UseENABLE_SEMANTIC_SEARCHinstead (will be removed in v1.0.0)
Docker Compose Example
Enable network mode Qdrant with docker-compose:
services:
mcp:
environment:
- QDRANT_URL=http://qdrant:6333
- ENABLE_SEMANTIC_SEARCH=true
qdrant:
image: qdrant/qdrant:latest
ports:
- 127.0.0.1:6333:6333
volumes:
- qdrant-data:/qdrant/storage
profiles:
- qdrant # Optional service
volumes:
qdrant-data:
Start with Qdrant service:
docker-compose --profile qdrant up
Or use default in-memory mode (no --profile needed):
docker-compose up
Loading Environment Variables
After creating your .env file, load the environment variables:
On Linux/macOS
# Load all variables from .env
export $(grep -v '^#' .env | xargs)
On Windows (PowerShell)
# Load variables from .env
Get-Content .env | ForEach-Object {
if ($_ -match '^\s*([^#][^=]*)\s*=\s*(.*)$') {
[Environment]::SetEnvironmentVariable($matches[1].Trim(), $matches[2].Trim(), "Process")
}
}
Via Docker
# Docker automatically loads .env when using --env-file
docker run -p 127.0.0.1:8000:8000 --env-file .env --rm \
ghcr.io/cbcoutinho/nextcloud-mcp-server:latest
CLI Configuration
Some configuration options can also be provided via CLI arguments. CLI arguments take precedence over environment variables.
OAuth-related CLI Options
uv run nextcloud-mcp-server --help
Options:
--oauth / --no-oauth Force OAuth mode (if enabled) or
BasicAuth mode (if disabled). By default,
auto-detected based on environment
variables.
--oauth-client-id TEXT OAuth client ID (can also use
NEXTCLOUD_OIDC_CLIENT_ID env var)
--oauth-client-secret TEXT OAuth client secret (can also use
NEXTCLOUD_OIDC_CLIENT_SECRET env var)
--mcp-server-url TEXT MCP server URL for OAuth callbacks (can
also use NEXTCLOUD_MCP_SERVER_URL env
var) [default: http://localhost:8000]
Server Options
Options:
-h, --host TEXT Server host [default: 127.0.0.1]
-p, --port INTEGER Server port [default: 8000]
-w, --workers INTEGER Number of worker processes
-r, --reload Enable auto-reload
-l, --log-level [critical|error|warning|info|debug|trace]
Logging level [default: info]
-t, --transport [sse|streamable-http|http]
MCP transport protocol [default: sse]
App Selection
Options:
-e, --enable-app [notes|tables|webdav|calendar|contacts|deck]
Enable specific Nextcloud app APIs. Can
be specified multiple times. If not
specified, all apps are enabled.
Example CLI Usage
# OAuth mode with custom client and port
uv run nextcloud-mcp-server --oauth \
--oauth-client-id abc123 \
--oauth-client-secret xyz789 \
--port 8080
# BasicAuth mode with specific apps only
uv run nextcloud-mcp-server --no-oauth \
--enable-app notes \
--enable-app calendar
Configuration Best Practices
For Development
- Use Single-User BasicAuth for the fastest local setup (one user, one app password)
- Store
.envfile in your project directory - Add
.envto.gitignore
For Production
Pick the mode that matches your deployment topology — there is no single "always" answer:
- Multi-user / hosted — use Login Flow v2. The MCP server registers with the chosen IdP (Nextcloud's built-in OIDC by default; Keycloak, AWS Cognito, etc. via
OIDC_DISCOVERY_URL) using staticNEXTCLOUD_OIDC_CLIENT_ID/NEXTCLOUD_OIDC_CLIENT_SECRET(generic OIDC creds, preferred) or RFC 7591 DCR (fallback). MCP clients authenticate via OAuth 2.1 + PKCE; per-user Nextcloud access is stored as encrypted app passwords. - Internal multi-user — Multi-User BasicAuth pass-through (clients send
Authorization: Basicheaders) is fully supported when users manage their own Nextcloud credentials. - Personal / self-hosted — Single-User BasicAuth with a Nextcloud app password is the simplest production setup.
In all modes:
- Use environment variables from your deployment platform (Docker secrets, Kubernetes ConfigMaps, etc.)
- Never commit credentials to version control
- SQLite database permissions are handled automatically by the server
For Docker
Mount two volumes for OAuth-mode deployments:
/app/.oauth— DCR-registered MCP-client state (only used when DCR is the chosen registration path; harmless to mount otherwise)./app/data— encrypted app-password store under Login Flow v2 (TOKEN_STORAGE_DB=/app/data/tokens.db).
docker run \
-v $(pwd)/.oauth:/app/.oauth \
-v $(pwd)/data:/app/data \
--env-file .env \
ghcr.io/cbcoutinho/nextcloud-mcp-server:latest --oauth
Use Docker secrets for sensitive values in production (TOKEN_ENCRYPTION_KEY, NEXTCLOUD_OIDC_CLIENT_SECRET, NEXTCLOUD_PASSWORD, etc.)
See Also
- Configuration Migration Guide v2 - New in v0.58.0: Migrate from old variable names
- Authentication - Authentication modes comparison
- Login Flow v2 - Recommended multi-user setup
- Running the Server - Starting the server with different configurations
- Troubleshooting - Common configuration issues
- ADR-021 - Configuration consolidation architecture decision
- ADR-022 - Deployment mode consolidation