0b8afec494
Add Login Flow v2 as a fourth auth mode alongside basic, multi-user-basic, and oauth. This enables multi-user deployments using Nextcloud's native Login Flow v2 without requiring OAuth patches to user_oidc. - Add loginFlow section to values.yaml with token encryption config - Add login-flow env vars, args, volume mounts to deployment.yaml - Add login-flow secret and oauth-storage PVC templates - Add loginFlowSecretName helper, update dataStorageEnabled - Add multi-user-basic and login-flow sections to NOTES.txt - Add version footer and ArtifactHub changelog annotations - Update README with 4 auth modes and docker-compose profiles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
554 lines
18 KiB
YAML
554 lines
18 KiB
YAML
# Default values for nextcloud-mcp-server
|
|
# This is a YAML-formatted file.
|
|
# Declare variables to be passed into your templates.
|
|
|
|
# Number of replicas
|
|
replicaCount: 1
|
|
|
|
image:
|
|
repository: ghcr.io/cbcoutinho/nextcloud-mcp-server
|
|
pullPolicy: IfNotPresent
|
|
# Image tag is automatically set to chart appVersion
|
|
|
|
imagePullSecrets: []
|
|
nameOverride: ""
|
|
fullnameOverride: ""
|
|
|
|
# Nextcloud connection settings
|
|
nextcloud:
|
|
# URL of your Nextcloud instance (required)
|
|
# Example: https://cloud.example.com
|
|
host: ""
|
|
|
|
# MCP server URL for OAuth callbacks (OAuth mode only)
|
|
# If not specified, will be constructed from ingress.hosts[0] if ingress is enabled,
|
|
# or defaults to http://localhost:8000 (suitable for port-forward setups)
|
|
# Example: https://mcp.example.com
|
|
mcpServerUrl: ""
|
|
|
|
# Public issuer URL for browser-accessible OAuth authorization endpoints (OAuth mode only)
|
|
# ONLY used to make authorization endpoints accessible to users' browsers
|
|
# All server-to-server communication (token endpoint, JWKS, introspection, userinfo)
|
|
# uses URLs from OIDC discovery without any rewriting
|
|
#
|
|
# Use case: When MCP server accesses Nextcloud at one URL but browsers need a different
|
|
# public URL for OAuth login (e.g., server uses internal DNS, browsers use public domain)
|
|
#
|
|
# If not specified, defaults to nextcloud.host (works when MCP server and browsers
|
|
# both access Nextcloud at the same URL)
|
|
# Example: https://cloud.example.com
|
|
publicIssuerUrl: ""
|
|
|
|
# Authentication configuration
|
|
# Choose one mode: "basic", "multi-user-basic", "oauth", or "login-flow"
|
|
auth:
|
|
# Authentication mode: "basic", "multi-user-basic", "oauth", or "login-flow"
|
|
# basic: Single-user with username/password (recommended for personal use)
|
|
# multi-user-basic: Multi-user with BasicAuth pass-through (credentials in request headers)
|
|
# oauth: Uses OAuth2/OIDC (experimental, requires patches)
|
|
# login-flow: Multi-user via Nextcloud Login Flow v2 (experimental, ADR-022)
|
|
mode: basic
|
|
|
|
# Basic authentication settings (single-user mode)
|
|
basic:
|
|
# Nextcloud username (ignored if existingSecret is set)
|
|
username: ""
|
|
# Nextcloud password or app password (recommended) (ignored if existingSecret is set)
|
|
password: ""
|
|
# Use existing secret instead of creating one
|
|
# If set, username and password above are ignored
|
|
# Secret must contain keys specified in usernameKey and passwordKey
|
|
# Example:
|
|
# kubectl create secret generic my-nextcloud-creds \
|
|
# --from-literal=username=myuser \
|
|
# --from-literal=password=mypassword
|
|
existingSecret: ""
|
|
# Keys in the existing secret
|
|
usernameKey: "username"
|
|
passwordKey: "password"
|
|
|
|
# Multi-user BasicAuth settings (pass-through mode)
|
|
# Users provide credentials in request headers (Authorization: Basic ...)
|
|
# Server optionally stores app passwords for background operations
|
|
multiUserBasic:
|
|
# Enable offline access (background operations using app passwords via Astrolabe)
|
|
# When enabled, requires token encryption key. OAuth client credentials are optional (uses DCR if not provided)
|
|
enableOfflineAccess: false
|
|
# Token encryption key (required if enableOfflineAccess: true, ignored if existingSecret is set)
|
|
# Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
tokenEncryptionKey: ""
|
|
# Token storage database path
|
|
tokenStorageDb: "/app/data/tokens.db"
|
|
# OAuth client credentials (optional - uses Dynamic Client Registration if not provided)
|
|
# Only needed if enableOfflineAccess: true
|
|
clientId: ""
|
|
clientSecret: ""
|
|
# OAuth scopes to request (space-separated)
|
|
scopes: "openid profile email offline_access notes:read notes:write calendar:read calendar:write contacts:read contacts:write cookbook:read cookbook:write deck:read deck:write tables:read tables:write files:read files:write sharing:read sharing:write todo:read todo:write"
|
|
# Use existing secret for multi-user basic auth credentials
|
|
# If set, tokenEncryptionKey, clientId, and clientSecret above are ignored
|
|
# Secret should contain keys specified in the *Key fields below
|
|
# Example:
|
|
# kubectl create secret generic my-multiuser-creds \
|
|
# --from-literal=token_encryption_key=ESF1BvEQ... \
|
|
# --from-literal=client_id=my-client-id \
|
|
# --from-literal=client_secret=my-client-secret
|
|
existingSecret: ""
|
|
# Keys in the existing secret
|
|
tokenEncryptionKeyKey: "token_encryption_key"
|
|
clientIdKey: "client_id"
|
|
clientSecretKey: "client_secret"
|
|
# Persistent storage for token database
|
|
persistence:
|
|
enabled: true
|
|
# Storage class (leave empty for default)
|
|
storageClass: ""
|
|
accessMode: ReadWriteOnce
|
|
size: 100Mi
|
|
# Use existing PVC
|
|
existingClaim: ""
|
|
|
|
# OAuth2/OIDC settings (experimental)
|
|
oauth:
|
|
# OAuth token type: "jwt" or "opaque"
|
|
tokenType: "jwt"
|
|
# Pre-registered OAuth client ID (optional, ignored if existingSecret is set)
|
|
# If not provided and no existingSecret, will use Dynamic Client Registration (DCR)
|
|
clientId: ""
|
|
# Pre-registered OAuth client secret (optional, ignored if existingSecret is set)
|
|
clientSecret: ""
|
|
# OAuth scopes to request (space-separated)
|
|
scopes: "openid profile email notes:read notes:write calendar:read calendar:write contacts:read contacts:write cookbook:read cookbook:write deck:read deck:write tables:read tables:write files:read files:write sharing:read sharing:write todo:read todo:write"
|
|
# Use existing secret for OAuth client credentials
|
|
# If set, clientId and clientSecret above are ignored
|
|
# Secret must contain keys specified in clientIdKey and clientSecretKey
|
|
# Example:
|
|
# kubectl create secret generic my-oauth-creds \
|
|
# --from-literal=clientId=my-client-id \
|
|
# --from-literal=clientSecret=my-client-secret
|
|
existingSecret: ""
|
|
# Keys in the existing secret
|
|
clientIdKey: "clientId"
|
|
clientSecretKey: "clientSecret"
|
|
# Persistent storage for OAuth client credentials
|
|
persistence:
|
|
enabled: true
|
|
# Storage class (leave empty for default)
|
|
storageClass: ""
|
|
accessMode: ReadWriteOnce
|
|
size: 100Mi
|
|
# Use existing PVC
|
|
existingClaim: ""
|
|
|
|
# Login Flow v2 settings (experimental, ADR-022)
|
|
# Uses Nextcloud's native Login Flow v2 to obtain app passwords per user.
|
|
# No OAuth patches required — works with stock Nextcloud.
|
|
# See: docs/ADR-022-deployment-mode-consolidation.md
|
|
loginFlow:
|
|
# Token encryption key (required, ignored if existingSecret is set)
|
|
# Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
tokenEncryptionKey: ""
|
|
# Token storage database path
|
|
tokenStorageDb: "/app/data/tokens.db"
|
|
# Use existing secret instead of creating one
|
|
existingSecret: ""
|
|
# Key in the existing secret
|
|
tokenEncryptionKeyKey: "token_encryption_key"
|
|
|
|
# Data Storage Configuration
|
|
# Persistent volume for /app/data directory
|
|
# Used for: token databases, qdrant persistent storage, and any app data
|
|
# When disabled, uses emptyDir (non-persistent, but still writable)
|
|
dataStorage:
|
|
# Enable persistent storage for /app/data
|
|
# Set to true when using:
|
|
# - Multi-user basic auth with offline access (stores tokens.db)
|
|
# - Login flow mode (stores app passwords in tokens.db)
|
|
# - Qdrant persistent mode (stores vector database)
|
|
# - Any feature requiring persistent app data
|
|
# Set to false for basic auth without persistence (uses emptyDir)
|
|
enabled: false
|
|
# Storage class (leave empty for default)
|
|
storageClass: ""
|
|
accessMode: ReadWriteOnce
|
|
# Size for data storage (should accommodate tokens.db and/or qdrant data)
|
|
# Recommended: 1Gi minimum, 5Gi for production with qdrant
|
|
size: 1Gi
|
|
# Use existing PVC
|
|
existingClaim: ""
|
|
|
|
# MCP server configuration
|
|
mcp:
|
|
# Transport mode (default: streamable-http for SSE)
|
|
transport: "streamable-http"
|
|
# Port for MCP server (both basic auth and OAuth modes)
|
|
port: 8000
|
|
# Additional command-line arguments to pass to nextcloud-mcp-server
|
|
# Example: ["--log-level", "debug", "--enable-app", "notes"]
|
|
extraArgs: []
|
|
|
|
# Document processing configuration (optional)
|
|
documentProcessing:
|
|
# Enable document processing (PDF, DOCX, images, etc.)
|
|
enabled: false
|
|
# Default processor: unstructured, tesseract, or custom
|
|
defaultProcessor: "unstructured"
|
|
# Progress reporting interval in seconds
|
|
progressInterval: 10
|
|
|
|
# Unstructured.io processor
|
|
unstructured:
|
|
enabled: false
|
|
# Unstructured API endpoint
|
|
apiUrl: "http://unstructured:8000"
|
|
# Request timeout in seconds
|
|
timeout: 120
|
|
# Parsing strategy: auto, fast, or hi_res
|
|
strategy: "auto"
|
|
# OCR languages (comma-separated ISO 639-3 codes)
|
|
languages: "eng,deu"
|
|
|
|
# Tesseract processor (local OCR)
|
|
tesseract:
|
|
enabled: false
|
|
# Path to tesseract executable (optional, auto-detected if in PATH)
|
|
cmd: ""
|
|
# OCR language (e.g., eng, deu, eng+deu for multiple)
|
|
lang: "eng"
|
|
|
|
# Custom processor
|
|
custom:
|
|
enabled: false
|
|
# Unique name for your processor
|
|
name: "my_ocr"
|
|
# Custom processor API endpoint
|
|
url: ""
|
|
# Optional API key for authentication
|
|
apiKey: ""
|
|
# Request timeout in seconds
|
|
timeout: 60
|
|
# Comma-separated MIME types your processor supports
|
|
types: "application/pdf,image/jpeg,image/png"
|
|
|
|
serviceAccount:
|
|
# Specifies whether a service account should be created
|
|
create: true
|
|
# Automatically mount a ServiceAccount's API credentials?
|
|
automount: true
|
|
# Annotations to add to the service account
|
|
annotations: {}
|
|
# The name of the service account to use.
|
|
# If not set and create is true, a name is generated using the fullname template
|
|
name: ""
|
|
|
|
podAnnotations: {}
|
|
podLabels: {}
|
|
|
|
podSecurityContext:
|
|
fsGroup: 2000
|
|
|
|
securityContext:
|
|
capabilities:
|
|
drop:
|
|
- ALL
|
|
readOnlyRootFilesystem: true
|
|
runAsNonRoot: true
|
|
runAsUser: 1000
|
|
|
|
# Observability Configuration
|
|
observability:
|
|
# Prometheus metrics
|
|
metrics:
|
|
enabled: true
|
|
port: 9090
|
|
path: /metrics
|
|
|
|
# OpenTelemetry tracing
|
|
tracing:
|
|
enabled: false
|
|
endpoint: "" # e.g., "http://opentelemetry-collector:4317"
|
|
serviceName: "nextcloud-mcp-server"
|
|
samplingRate: 1.0
|
|
|
|
# Logging configuration
|
|
logging:
|
|
format: json # "json" or "text"
|
|
level: INFO
|
|
includeTraceContext: true
|
|
|
|
# Prometheus ServiceMonitor (requires Prometheus Operator)
|
|
serviceMonitor:
|
|
enabled: false
|
|
interval: 30s
|
|
scrapeTimeout: 10s
|
|
labels: {}
|
|
# Additional labels for ServiceMonitor (e.g., for Prometheus selector)
|
|
# Example: { prometheus: kube-prometheus }
|
|
|
|
# Prometheus alert rules (requires Prometheus Operator)
|
|
prometheusRule:
|
|
enabled: false
|
|
labels: {}
|
|
# Additional labels for PrometheusRule (e.g., for Prometheus selector)
|
|
# Example: { prometheus: kube-prometheus }
|
|
|
|
# Grafana dashboards (requires Grafana with sidecar enabled)
|
|
dashboards:
|
|
# Enable automatic dashboard provisioning via ConfigMap
|
|
enabled: false
|
|
# Grafana folder name where dashboards will be imported
|
|
# The grafana-sidecar looks for ConfigMaps with label "grafana_dashboard: 1"
|
|
# and reads the folder name from annotation "grafana_folder" (supports spaces)
|
|
grafanaFolder: "Nextcloud MCP"
|
|
# Additional labels for dashboard ConfigMap
|
|
# These will be added alongside the required "grafana_dashboard: 1" label
|
|
labels: {}
|
|
# Additional annotations for dashboard ConfigMap
|
|
annotations: {}
|
|
|
|
service:
|
|
type: ClusterIP
|
|
port: 8000
|
|
annotations: {}
|
|
|
|
ingress:
|
|
enabled: false
|
|
className: ""
|
|
annotations: {}
|
|
# kubernetes.io/ingress.class: nginx
|
|
# kubernetes.io/tls-acme: "true"
|
|
# cert-manager.io/cluster-issuer: letsencrypt-prod
|
|
hosts:
|
|
- host: mcp.example.com
|
|
paths:
|
|
- path: /
|
|
pathType: Prefix
|
|
tls: []
|
|
# - secretName: nextcloud-mcp-tls
|
|
# hosts:
|
|
# - mcp.example.com
|
|
|
|
resources:
|
|
# We recommend setting resource requests and limits
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 512Mi
|
|
requests:
|
|
cpu: 100m
|
|
memory: 128Mi
|
|
|
|
# Liveness probe configuration
|
|
# Checks if the application process is running
|
|
livenessProbe:
|
|
httpGet:
|
|
path: /health/live
|
|
port: http
|
|
scheme: HTTP
|
|
initialDelaySeconds: 30
|
|
periodSeconds: 10
|
|
timeoutSeconds: 5
|
|
failureThreshold: 3
|
|
|
|
# Readiness probe configuration
|
|
# Checks if the application is ready to serve traffic
|
|
readinessProbe:
|
|
httpGet:
|
|
path: /health/ready
|
|
port: http
|
|
scheme: HTTP
|
|
initialDelaySeconds: 10
|
|
periodSeconds: 5
|
|
timeoutSeconds: 3
|
|
failureThreshold: 3
|
|
|
|
# Autoscaling configuration
|
|
autoscaling:
|
|
enabled: false
|
|
minReplicas: 1
|
|
maxReplicas: 10
|
|
targetCPUUtilizationPercentage: 80
|
|
# targetMemoryUtilizationPercentage: 80
|
|
|
|
# Additional volumes on the output Deployment definition.
|
|
volumes: []
|
|
# - name: foo
|
|
# secret:
|
|
# secretName: mysecret
|
|
# optional: false
|
|
|
|
# Additional volumeMounts on the output Deployment definition.
|
|
volumeMounts: []
|
|
# - name: foo
|
|
# mountPath: "/etc/foo"
|
|
# readOnly: true
|
|
|
|
nodeSelector: {}
|
|
|
|
tolerations: []
|
|
|
|
affinity: {}
|
|
|
|
# Init containers
|
|
initContainers: []
|
|
|
|
# Additional environment variables
|
|
extraEnv: []
|
|
# - name: CUSTOM_VAR
|
|
# value: "custom_value"
|
|
|
|
# Additional environment variables from ConfigMaps or Secrets
|
|
extraEnvFrom: []
|
|
# - configMapRef:
|
|
# name: my-configmap
|
|
# - secretRef:
|
|
# name: my-secret
|
|
|
|
# Semantic Search Configuration
|
|
# Enable semantic search with BM25 hybrid search and background synchronization
|
|
# of Nextcloud content into vector database
|
|
semanticSearch:
|
|
# Enable semantic search and background vector synchronization
|
|
enabled: false
|
|
# Scan interval in seconds (how often to check for changes)
|
|
scanInterval: 3600
|
|
# Number of concurrent processor workers
|
|
processorWorkers: 3
|
|
# Maximum queue size for documents pending indexing
|
|
queueMaxSize: 10000
|
|
|
|
# Document Chunking Configuration
|
|
# Controls how documents are split into chunks before embedding
|
|
# Only relevant when semanticSearch.enabled is true
|
|
documentChunking:
|
|
# Number of words per chunk (default: 512)
|
|
# Smaller chunks (256-384): Better for precise searches, more chunks to store
|
|
# Medium chunks (512-768): Balanced approach (recommended for most use cases)
|
|
# Larger chunks (1024+): Better for context, less precise matching
|
|
chunkSize: 512
|
|
# Number of overlapping words between chunks (default: 50)
|
|
# Recommended: 10-20% of chunkSize for context preservation across boundaries
|
|
# Must be less than chunkSize
|
|
chunkOverlap: 50
|
|
|
|
# Qdrant Vector Database Configuration
|
|
# Three deployment modes available:
|
|
# 1. Local In-Memory: Fast, ephemeral, zero-config (mode: "memory")
|
|
# 2. Local Persistent: File-based, survives restarts (mode: "persistent")
|
|
# 3. Network: Dedicated Qdrant service, production-ready (mode: "network")
|
|
qdrant:
|
|
# Qdrant mode: "memory", "persistent", or "network"
|
|
# - memory: In-memory storage (:memory:) - default, zero config, data lost on restart
|
|
# - persistent: Local file storage - data persists across restarts, suitable for small/medium deployments
|
|
# - network: Dedicated Qdrant service (see networkMode below)
|
|
mode: "memory"
|
|
|
|
# Collection name for vector data
|
|
collection: "nextcloud_content"
|
|
|
|
# Local persistent mode configuration (only used when mode: "persistent")
|
|
localPersistence:
|
|
# Enable persistent volume for local Qdrant data
|
|
enabled: true
|
|
# Storage class (leave empty for default)
|
|
storageClass: ""
|
|
accessMode: ReadWriteOnce
|
|
# Size for local Qdrant storage
|
|
size: 1Gi
|
|
# Path where Qdrant data is stored (relative to /app/data)
|
|
# Default: /app/data/qdrant
|
|
dataPath: "/app/data/qdrant"
|
|
# Use existing PVC
|
|
existingClaim: ""
|
|
|
|
# Network mode configuration (only used when mode: "network")
|
|
networkMode:
|
|
# Deploy Qdrant as a subchart (if true) or use external Qdrant (if false)
|
|
deploySubchart: false
|
|
# External Qdrant URL (used when deploySubchart: false)
|
|
# Example: "http://qdrant.default.svc.cluster.local:6333"
|
|
externalUrl: ""
|
|
# Optional API key for Qdrant authentication
|
|
apiKey: ""
|
|
# Use existing secret for API key
|
|
existingSecret: ""
|
|
secretKey: "api-key"
|
|
|
|
# Qdrant subchart configuration (only used when mode: "network" and networkMode.deploySubchart: true)
|
|
# All values are passed through to the qdrant/qdrant chart.
|
|
# See https://github.com/qdrant/qdrant-helm for full configuration options.
|
|
subchart:
|
|
# Number of Qdrant replicas
|
|
replicaCount: 1
|
|
image:
|
|
# Qdrant version
|
|
tag: v1.12.5
|
|
config:
|
|
cluster:
|
|
# Enable distributed cluster mode
|
|
enabled: false
|
|
# Persistent storage for vector data
|
|
persistence:
|
|
size: 10Gi
|
|
storageClass: ""
|
|
accessModes:
|
|
- ReadWriteOnce
|
|
# Resource limits and requests
|
|
resources:
|
|
requests:
|
|
cpu: 200m
|
|
memory: 512Mi
|
|
limits:
|
|
cpu: 1000m
|
|
memory: 2Gi
|
|
|
|
# Ollama Embedding Service
|
|
# Deployed as a subchart when enabled. All values are passed through to the ollama/ollama chart.
|
|
# See https://github.com/otwld/ollama-helm for full configuration options.
|
|
ollama:
|
|
# Enable Ollama subchart deployment
|
|
# Set to true to deploy Ollama as a subchart, or false to use an external Ollama instance
|
|
enabled: false
|
|
# External Ollama URL (use this if you have Ollama deployed elsewhere)
|
|
# When set, use enabled: false to prevent deploying the subchart
|
|
# Example: "http://ollama.default.svc.cluster.local:11434"
|
|
url: ""
|
|
# Embedding model to use
|
|
embeddingModel: "nomic-embed-text"
|
|
# Verify SSL certificates when connecting to Ollama
|
|
verifySsl: true
|
|
# Number of Ollama replicas (only used when subchart is deployed)
|
|
replicaCount: 1
|
|
# Ollama configuration (only used when subchart is deployed)
|
|
ollama:
|
|
# Models to automatically pull on startup
|
|
models:
|
|
pull:
|
|
- nomic-embed-text
|
|
# Persistent storage for models (only used when subchart is deployed)
|
|
persistentVolume:
|
|
enabled: true
|
|
size: 20Gi
|
|
storageClass: ""
|
|
# Resource limits and requests (only used when subchart is deployed)
|
|
resources:
|
|
requests:
|
|
cpu: 500m
|
|
memory: 1Gi
|
|
limits:
|
|
cpu: 2000m
|
|
memory: 4Gi
|
|
|
|
# OpenAI-compatible Embedding Provider
|
|
# Alternative to Ollama for embedding generation. Can be used with OpenAI or any compatible API.
|
|
openai:
|
|
# Enable OpenAI embedding provider
|
|
enabled: false
|
|
# OpenAI API key (only used if existingSecret is not set)
|
|
apiKey: ""
|
|
# Name of existing secret containing the API key
|
|
existingSecret: ""
|
|
# Key in the secret that contains the API key
|
|
secretKey: "api-key"
|
|
# Optional custom API endpoint (e.g., for Azure OpenAI or local compatible services)
|
|
baseUrl: ""
|