5e76ddc60d
Remove URL rewriting logic from MCP server that was converting
public URLs to internal Docker URLs. This was a workaround for
Nextcloud's overwritehost setting forcing URLs to localhost:8080.
Changes:
- Remove OIDC endpoint rewriting in app.py (setup_oauth_config)
- Remove OIDC_JWKS_URI override support (no longer needed)
- Remove URL rewriting in browser_oauth_routes.py
- Remove URL rewriting in token_broker.py
- Update Helm chart values and README
- Add hybrid auth setup unit tests
- Update Astrolabe admin UI for Vue 3
The proper fix is in the previous commit which removes the
overwritehost setting from Nextcloud, allowing it to respect
the Host header from incoming requests.
516 lines
17 KiB
YAML
516 lines
17 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", or "oauth"
|
|
auth:
|
|
# Authentication mode: "basic", "multi-user-basic", or "oauth"
|
|
# 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)
|
|
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: ""
|
|
|
|
# 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: ""
|