Files
mcp-nextcloud/charts/nextcloud-mcp-server/README.md
T
Chris CoutinhoandClaude e32c8f4aec feat: add optional vector database and semantic search to helm chart
Add support for deploying Qdrant vector database and Ollama embedding
service as optional helm chart dependencies. Enables semantic search
capabilities for Nextcloud content with flexible deployment options.

Chart Dependencies:
- Add Qdrant v0.9.0 from qdrant/qdrant-helm (conditional)
- Add Ollama v1.33.0 from otwld/ollama-helm (conditional)
- Both dependencies only deploy when enabled

Configuration (values.yaml):
- vectorSync: Background sync settings (interval, workers, queue size)
- qdrant: Subchart config with persistence, resources, clustering
- ollama: Subchart config with model pull, persistence, resources
  - Support for external Ollama via ollama.url (no subchart deployment)
- openai: Alternative embedding provider (OpenAI or compatible API)

Environment Variables (deployment.yaml):
- VECTOR_SYNC_* variables when vectorSync.enabled
- QDRANT_URL, QDRANT_COLLECTION when qdrant.enabled
- OLLAMA_BASE_URL, OLLAMA_EMBEDDING_MODEL when ollama enabled or URL set
- OPENAI_API_KEY when openai.enabled

Documentation:
- README: New "Vector Search & Semantic Capabilities" section
- README: Example 5 showing three deployment patterns
- NOTES.txt: Conditional guidance when vector features enabled
- Secret template for OpenAI API key management

All features disabled by default for backward compatibility.
Tested with helm template and helm lint.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-09 00:03:51 +01:00

635 lines
17 KiB
Markdown

# Nextcloud MCP Server Helm Chart
This Helm chart deploys the Nextcloud MCP (Model Context Protocol) Server on a Kubernetes cluster, enabling AI assistants to interact with your Nextcloud instance.
## Prerequisites
- Kubernetes 1.19+
- Helm 3.0+
- A running Nextcloud instance (accessible from the Kubernetes cluster)
- Nextcloud credentials (username/password for basic auth OR OAuth client for OAuth mode)
## Installation
### Quick Start with Basic Authentication
```bash
# Install with basic auth (recommended for most users)
helm install nextcloud-mcp ./helm/nextcloud-mcp-server \
--set nextcloud.host=https://cloud.example.com \
--set auth.basic.username=myuser \
--set auth.basic.password=mypassword
```
### Using a values file
Create a `custom-values.yaml` file:
```yaml
nextcloud:
host: https://cloud.example.com
auth:
mode: basic
basic:
username: myuser
password: mypassword
resources:
limits:
cpu: 1000m
memory: 512Mi
requests:
cpu: 100m
memory: 128Mi
```
Install with your custom values:
```bash
helm install nextcloud-mcp ./helm/nextcloud-mcp-server -f custom-values.yaml
```
### OAuth Authentication Mode (Experimental)
**Warning:** OAuth mode is experimental and requires patches to the Nextcloud `user_oidc` app. See the [Authentication Guide](https://github.com/cbcoutinho/nextcloud-mcp-server#authentication) for details.
```yaml
nextcloud:
host: https://cloud.example.com
mcpServerUrl: https://mcp.example.com
publicIssuerUrl: https://cloud.example.com
auth:
mode: oauth
oauth:
# Optional: provide pre-registered client credentials
# If not provided, will use Dynamic Client Registration
clientId: "your-client-id"
clientSecret: "your-client-secret"
persistence:
enabled: true
size: 100Mi
ingress:
enabled: true
className: nginx
hosts:
- host: mcp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: nextcloud-mcp-tls
hosts:
- mcp.example.com
```
## Configuration
### Key Configuration Parameters
#### Nextcloud Connection
| Parameter | Description | Default |
|-----------|-------------|---------|
| `nextcloud.host` | URL of your Nextcloud instance (required) | `""` |
| `nextcloud.mcpServerUrl` | MCP server URL for OAuth callbacks (OAuth only, optional) | Smart default* |
| `nextcloud.publicIssuerUrl` | Public issuer URL for OAuth (OAuth only, optional) | Smart default** |
**Smart Defaults:**
- `*mcpServerUrl`: If not set, automatically uses ingress host (if enabled) or `http://localhost:8000` (for port-forward setups)
- `**publicIssuerUrl`: If not set, automatically defaults to `nextcloud.host` (which works when both clients and MCP server access Nextcloud at the same URL)
#### Authentication
| Parameter | Description | Default |
|-----------|-------------|---------|
| `auth.mode` | Authentication mode: `basic` or `oauth` | `basic` |
| `auth.basic.username` | Nextcloud username (basic auth) | `""` |
| `auth.basic.password` | Nextcloud password (basic auth) | `""` |
| `auth.basic.existingSecret` | Use existing secret for credentials | `""` |
| `auth.oauth.clientId` | OAuth client ID (OAuth mode, optional) | `""` |
| `auth.oauth.clientSecret` | OAuth client secret (OAuth mode, optional) | `""` |
| `auth.oauth.persistence.enabled` | Enable persistent storage for OAuth | `true` |
| `auth.oauth.persistence.size` | Size of OAuth storage PVC | `100Mi` |
#### MCP Server Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `mcp.transport` | Transport mode | `streamable-http` |
| `mcp.port` | Server port (used by both auth modes) | `8000` |
| `mcp.extraArgs` | Additional command-line arguments | `[]` |
The `extraArgs` parameter allows you to pass additional command-line arguments to the MCP server. This is useful for enabling debug logging, enabling specific apps, or other runtime configuration.
**Example:**
```yaml
mcp:
extraArgs:
- "--log-level"
- "debug"
- "--enable-app"
- "notes"
```
#### Image Configuration
| Parameter | Description | Default |
|-----------|-------------|---------|
| `image.repository` | Container image repository | `ghcr.io/cbcoutinho/nextcloud-mcp-server` |
| `image.pullPolicy` | Image pull policy | `IfNotPresent` |
**Note:** Image tag is automatically set to the chart's `appVersion` and cannot be overridden.
#### Resources
| Parameter | Description | Default |
|-----------|-------------|---------|
| `resources.limits.cpu` | CPU limit | `1000m` |
| `resources.limits.memory` | Memory limit | `512Mi` |
| `resources.requests.cpu` | CPU request | `100m` |
| `resources.requests.memory` | Memory request | `128Mi` |
#### Service
| Parameter | Description | Default |
|-----------|-------------|---------|
| `service.type` | Service type | `ClusterIP` |
| `service.port` | Service port | `8000` |
#### Ingress
| Parameter | Description | Default |
|-----------|-------------|---------|
| `ingress.enabled` | Enable ingress | `false` |
| `ingress.className` | Ingress class name | `""` |
| `ingress.hosts` | Ingress host configuration | See values.yaml |
| `ingress.tls` | Ingress TLS configuration | `[]` |
#### Autoscaling
| Parameter | Description | Default |
|-----------|-------------|---------|
| `autoscaling.enabled` | Enable HPA | `false` |
| `autoscaling.minReplicas` | Minimum replicas | `1` |
| `autoscaling.maxReplicas` | Maximum replicas | `10` |
| `autoscaling.targetCPUUtilizationPercentage` | Target CPU % | `80` |
#### Health Probes
| Parameter | Description | Default |
|-----------|-------------|---------|
| `livenessProbe.httpGet.path` | Liveness probe endpoint | `/health/live` |
| `livenessProbe.initialDelaySeconds` | Initial delay for liveness | `30` |
| `livenessProbe.periodSeconds` | Check interval for liveness | `10` |
| `readinessProbe.httpGet.path` | Readiness probe endpoint | `/health/ready` |
| `readinessProbe.initialDelaySeconds` | Initial delay for readiness | `10` |
| `readinessProbe.periodSeconds` | Check interval for readiness | `5` |
The application exposes HTTP health check endpoints:
- `/health/live` - Liveness probe (checks if application is running)
- `/health/ready` - Readiness probe (checks if application is ready to serve traffic)
#### Document Processing (Optional)
| Parameter | Description | Default |
|-----------|-------------|---------|
| `documentProcessing.enabled` | Enable document processing | `false` |
| `documentProcessing.defaultProcessor` | Default processor | `unstructured` |
| `documentProcessing.unstructured.enabled` | Enable Unstructured.io processor | `false` |
| `documentProcessing.unstructured.apiUrl` | Unstructured API URL | `http://unstructured:8000` |
| `documentProcessing.tesseract.enabled` | Enable Tesseract OCR | `false` |
#### Vector Search & Semantic Capabilities (Optional)
Enable semantic search capabilities by deploying a vector database (Qdrant) and embedding service (Ollama or OpenAI).
**Vector Sync Configuration:**
| Parameter | Description | Default |
|-----------|-------------|---------|
| `vectorSync.enabled` | Enable background vector synchronization | `false` |
| `vectorSync.scanInterval` | Scan interval in seconds | `3600` |
| `vectorSync.processorWorkers` | Number of concurrent processor workers | `3` |
| `vectorSync.queueMaxSize` | Maximum queue size for pending documents | `10000` |
**Qdrant Vector Database:**
Qdrant is deployed as a subchart when `qdrant.enabled` is `true`. All configuration values are passed through to the [qdrant/qdrant](https://github.com/qdrant/qdrant-helm) chart.
| Parameter | Description | Default |
|-----------|-------------|---------|
| `qdrant.enabled` | Deploy Qdrant as a subchart | `false` |
| `qdrant.replicaCount` | Number of Qdrant replicas | `1` |
| `qdrant.image.tag` | Qdrant version | `v1.12.5` |
| `qdrant.apiKey` | Optional API key for authentication | `""` |
| `qdrant.persistence.size` | Storage size for vector data | `10Gi` |
| `qdrant.persistence.storageClass` | Storage class | `""` |
| `qdrant.resources.requests.cpu` | CPU request | `200m` |
| `qdrant.resources.requests.memory` | Memory request | `512Mi` |
| `qdrant.resources.limits.cpu` | CPU limit | `1000m` |
| `qdrant.resources.limits.memory` | Memory limit | `2Gi` |
**Ollama Embedding Service:**
Ollama is deployed as a subchart when `ollama.enabled` is `true`. All configuration values are passed through to the [ollama/ollama](https://github.com/otwld/ollama-helm) chart. Alternatively, set `ollama.url` to use an external Ollama instance.
| Parameter | Description | Default |
|-----------|-------------|---------|
| `ollama.enabled` | Deploy Ollama as a subchart | `false` |
| `ollama.url` | External Ollama URL (use with `enabled: false`) | `""` |
| `ollama.embeddingModel` | Embedding model to use | `nomic-embed-text` |
| `ollama.verifySsl` | Verify SSL certificates | `true` |
| `ollama.replicaCount` | Number of Ollama replicas | `1` |
| `ollama.ollama.models.pull` | Models to pull on startup | `["nomic-embed-text"]` |
| `ollama.persistentVolume.enabled` | Enable persistent storage | `true` |
| `ollama.persistentVolume.size` | Storage size for models | `20Gi` |
| `ollama.resources.requests.cpu` | CPU request | `500m` |
| `ollama.resources.requests.memory` | Memory request | `1Gi` |
| `ollama.resources.limits.cpu` | CPU limit | `2000m` |
| `ollama.resources.limits.memory` | Memory limit | `4Gi` |
**OpenAI Embedding Provider (Alternative):**
Use OpenAI or any OpenAI-compatible API instead of Ollama.
| Parameter | Description | Default |
|-----------|-------------|---------|
| `openai.enabled` | Enable OpenAI embedding provider | `false` |
| `openai.apiKey` | OpenAI API key | `""` |
| `openai.existingSecret` | Use existing secret for API key | `""` |
| `openai.secretKey` | Key in secret containing API key | `api-key` |
| `openai.baseUrl` | Custom API endpoint (optional) | `""` |
## Examples
### Example 1: Basic Auth with Ingress
```yaml
nextcloud:
host: https://cloud.example.com
auth:
mode: basic
basic:
username: admin
password: secure-password
ingress:
enabled: true
className: nginx
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
hosts:
- host: mcp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: mcp-tls
hosts:
- mcp.example.com
resources:
limits:
cpu: 2000m
memory: 1Gi
requests:
cpu: 200m
memory: 256Mi
```
### Example 2: Using Existing Secrets
#### Basic Auth with Existing Secret
Create a secret manually:
```bash
kubectl create secret generic nextcloud-credentials \
--from-literal=username=myuser \
--from-literal=password=mypassword
```
Then reference it in your values:
```yaml
nextcloud:
host: https://cloud.example.com
auth:
mode: basic
basic:
existingSecret: nextcloud-credentials
usernameKey: username
passwordKey: password
```
#### OAuth with Existing Secret (Pre-registered Client)
If you have a pre-registered OAuth client:
```bash
kubectl create secret generic nextcloud-oauth-creds \
--from-literal=clientId=my-oauth-client-id \
--from-literal=clientSecret=my-oauth-client-secret
```
Then reference it in your values:
```yaml
nextcloud:
host: https://cloud.example.com
# mcpServerUrl and publicIssuerUrl are optional!
# If not set, mcpServerUrl defaults to ingress host or localhost
# publicIssuerUrl defaults to nextcloud.host
auth:
mode: oauth
oauth:
existingSecret: nextcloud-oauth-creds
clientIdKey: clientId
clientSecretKey: clientSecret
persistence:
enabled: true
ingress:
enabled: true
hosts:
- host: mcp.example.com
paths:
- path: /
pathType: Prefix
tls:
- secretName: mcp-tls
hosts:
- mcp.example.com
```
### Example 3: OAuth with Document Processing and Dynamic Client Registration
This example shows OAuth without pre-registered credentials (using DCR) and optional URL values:
```yaml
nextcloud:
host: https://cloud.example.com
# mcpServerUrl will automatically use ingress host (https://mcp.example.com)
# publicIssuerUrl will automatically default to nextcloud.host
auth:
mode: oauth
oauth:
# No clientId/clientSecret - will use Dynamic Client Registration!
persistence:
enabled: true
storageClass: fast-ssd
size: 200Mi
documentProcessing:
enabled: true
defaultProcessor: unstructured
unstructured:
enabled: true
apiUrl: http://unstructured-api:8000
strategy: hi_res
languages: eng,deu,fra
ingress:
enabled: true
className: nginx
hosts:
- host: mcp.example.com
paths:
- path: /
pathType: Prefix
```
### Example 4: High Availability with Autoscaling
```yaml
replicaCount: 2
autoscaling:
enabled: true
minReplicas: 2
maxReplicas: 20
targetCPUUtilizationPercentage: 70
targetMemoryUtilizationPercentage: 80
resources:
limits:
cpu: 2000m
memory: 1Gi
requests:
cpu: 500m
memory: 512Mi
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app.kubernetes.io/name
operator: In
values:
- nextcloud-mcp-server
topologyKey: kubernetes.io/hostname
```
### Example 5: Semantic Search with Qdrant and Ollama
Deploy with vector search capabilities using embedded Qdrant and Ollama:
```yaml
nextcloud:
host: https://cloud.example.com
auth:
mode: basic
basic:
username: admin
password: secure-password
# Enable vector sync
vectorSync:
enabled: true
scanInterval: 1800 # Scan every 30 minutes
processorWorkers: 5
# Deploy Qdrant as a subchart
qdrant:
enabled: true
persistence:
size: 20Gi
storageClass: fast-ssd
resources:
requests:
cpu: 500m
memory: 1Gi
limits:
cpu: 2000m
memory: 4Gi
# Deploy Ollama as a subchart
ollama:
enabled: true
embeddingModel: nomic-embed-text
persistentVolume:
size: 30Gi
storageClass: standard
resources:
requests:
cpu: 1000m
memory: 2Gi
limits:
cpu: 4000m
memory: 8Gi
```
Or use an external Ollama instance:
```yaml
vectorSync:
enabled: true
qdrant:
enabled: true
# Use external Ollama instead of deploying subchart
ollama:
enabled: false
url: "http://ollama.ai-services.svc.cluster.local:11434"
embeddingModel: nomic-embed-text
```
Or use OpenAI for embeddings:
```yaml
vectorSync:
enabled: true
qdrant:
enabled: true
# Use OpenAI instead of Ollama
openai:
enabled: true
apiKey: "sk-..."
# Or use existing secret:
# existingSecret: openai-api-key
# secretKey: api-key
```
## Upgrading
### To upgrade an existing deployment:
```bash
helm upgrade nextcloud-mcp ./helm/nextcloud-mcp-server -f custom-values.yaml
```
### To upgrade with new values:
```bash
helm upgrade nextcloud-mcp ./helm/nextcloud-mcp-server \
--set resources.limits.memory=1Gi
```
## Uninstalling
```bash
helm uninstall nextcloud-mcp
```
**Note:** This will delete all resources including PVCs. If you want to preserve OAuth client data, backup the PVC before uninstalling.
## Troubleshooting
### Check pod status
```bash
kubectl get pods -l app.kubernetes.io/name=nextcloud-mcp-server
```
### View logs
```bash
kubectl logs -l app.kubernetes.io/name=nextcloud-mcp-server --tail=100 -f
```
### Check health endpoints
The application exposes health check endpoints for monitoring:
```bash
# Port forward to the service
kubectl port-forward svc/nextcloud-mcp 8000:8000
# Check liveness (if app is running)
curl http://localhost:8000/health/live
# Check readiness (if app is ready to serve traffic)
curl http://localhost:8000/health/ready
```
**Example responses:**
Liveness (always returns 200 if running):
```json
{
"status": "alive",
"mode": "basic"
}
```
Readiness (returns 200 if ready, 503 if not ready):
```json
{
"status": "ready",
"checks": {
"nextcloud_configured": "ok",
"auth_mode": "basic",
"auth_configured": "ok"
}
}
```
### Common Issues
1. **Connection refused to Nextcloud**
- Verify `nextcloud.host` is accessible from the Kubernetes cluster
- Check network policies and firewall rules
2. **Authentication failures**
- For basic auth: verify username/password are correct
- For OAuth: check that OIDC app is properly configured
3. **OAuth persistence issues**
- Verify PVC is bound: `kubectl get pvc`
- Check storage class exists: `kubectl get storageclass`
4. **Resource constraints**
- Increase memory limits if seeing OOM errors
- Adjust CPU requests based on load
## Security Considerations
1. **Secrets Management**: Consider using external secret management (e.g., Sealed Secrets, External Secrets Operator)
2. **TLS**: Always use TLS/HTTPS for production deployments
3. **Network Policies**: Restrict network access to necessary services only
4. **RBAC**: Review and customize ServiceAccount permissions as needed
5. **App Passwords**: For basic auth, use Nextcloud app passwords instead of main account passwords
## Support
- GitHub Issues: https://github.com/cbcoutinho/nextcloud-mcp-server/issues
- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme
## License
This chart is licensed under AGPL-3.0, consistent with the Nextcloud MCP Server project.