From 97fa9ef8a70db9cc06595a90182a62e17f14ce07 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Wed, 29 Oct 2025 01:36:30 +0100 Subject: [PATCH] build: Update helm chart README and instructions --- helm/nextcloud-mcp-server/README.md | 65 +++++++++++++++++-- helm/nextcloud-mcp-server/templates/NOTES.txt | 15 ++++- .../templates/_helpers.tpl | 33 ++++++++++ .../templates/deployment.yaml | 4 +- helm/nextcloud-mcp-server/values.yaml | 31 +++++++-- 5 files changed, 131 insertions(+), 17 deletions(-) diff --git a/helm/nextcloud-mcp-server/README.md b/helm/nextcloud-mcp-server/README.md index 1dea9db..64df8b5 100644 --- a/helm/nextcloud-mcp-server/README.md +++ b/helm/nextcloud-mcp-server/README.md @@ -93,9 +93,13 @@ ingress: | Parameter | Description | Default | |-----------|-------------|---------| -| `nextcloud.host` | URL of your Nextcloud instance | `""` | -| `nextcloud.mcpServerUrl` | MCP server URL for OAuth callbacks (OAuth only) | `""` | -| `nextcloud.publicIssuerUrl` | Public issuer URL for OAuth (OAuth only) | `""` | +| `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 @@ -203,6 +207,8 @@ resources: ### Example 2: Using Existing Secrets +#### Basic Auth with Existing Secret + Create a secret manually: ```bash @@ -214,6 +220,9 @@ kubectl create secret generic nextcloud-credentials \ Then reference it in your values: ```yaml +nextcloud: + host: https://cloud.example.com + auth: mode: basic basic: @@ -222,17 +231,61 @@ auth: passwordKey: password ``` -### Example 3: OAuth with Document Processing +#### 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: https://mcp.example.com - publicIssuerUrl: 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 diff --git a/helm/nextcloud-mcp-server/templates/NOTES.txt b/helm/nextcloud-mcp-server/templates/NOTES.txt index 64afb4d..fdc5e15 100644 --- a/helm/nextcloud-mcp-server/templates/NOTES.txt +++ b/helm/nextcloud-mcp-server/templates/NOTES.txt @@ -31,15 +31,26 @@ Your Nextcloud MCP Server has been deployed in {{ .Values.auth.mode }} authentic {{- if eq .Values.auth.mode "basic" }} 3. Basic Authentication Mode: + {{- if .Values.auth.basic.existingSecret }} + - Credentials: (using existing secret {{ .Values.auth.basic.existingSecret }}) + {{- else }} - Username: {{ .Values.auth.basic.username }} - Password: (stored in secret {{ include "nextcloud-mcp-server.basicAuthSecretName" . }}) + {{- end }} - Connected to: {{ .Values.nextcloud.host }} {{- else if eq .Values.auth.mode "oauth" }} 3. OAuth Authentication Mode: - - Server URL: {{ .Values.nextcloud.mcpServerUrl }} - - Issuer URL: {{ .Values.nextcloud.publicIssuerUrl }} + - Server URL: {{ include "nextcloud-mcp-server.mcpServerUrl" . }} + - Issuer URL: {{ include "nextcloud-mcp-server.publicIssuerUrl" . }} - Connected to: {{ .Values.nextcloud.host }} + {{- if .Values.auth.oauth.existingSecret }} + - Using existing OAuth client secret: {{ .Values.auth.oauth.existingSecret }} + {{- else if and .Values.auth.oauth.clientId .Values.auth.oauth.clientSecret }} + - Using pre-registered OAuth client + {{- else }} + - Using Dynamic Client Registration (DCR) + {{- end }} {{- if .Values.auth.oauth.persistence.enabled }} - OAuth client credentials are persisted in PVC: {{ include "nextcloud-mcp-server.oauthPvcName" . }} {{- end }} diff --git a/helm/nextcloud-mcp-server/templates/_helpers.tpl b/helm/nextcloud-mcp-server/templates/_helpers.tpl index 3efacaf..c54b510 100644 --- a/helm/nextcloud-mcp-server/templates/_helpers.tpl +++ b/helm/nextcloud-mcp-server/templates/_helpers.tpl @@ -111,3 +111,36 @@ Return the image tag {{- define "nextcloud-mcp-server.imageTag" -}} {{- .Values.image.tag | default .Chart.AppVersion }} {{- end }} + +{{/* +Return the public issuer URL for OAuth +Defaults to nextcloud.host if not specified +*/}} +{{- define "nextcloud-mcp-server.publicIssuerUrl" -}} +{{- if .Values.nextcloud.publicIssuerUrl }} +{{- .Values.nextcloud.publicIssuerUrl }} +{{- else }} +{{- .Values.nextcloud.host }} +{{- end }} +{{- end }} + +{{/* +Return the MCP server URL for OAuth callbacks +If not specified: + - Uses ingress host if ingress is enabled + - Otherwise defaults to http://localhost:8000 (for port-forward setups) +*/}} +{{- define "nextcloud-mcp-server.mcpServerUrl" -}} +{{- if .Values.nextcloud.mcpServerUrl }} +{{- .Values.nextcloud.mcpServerUrl }} +{{- else if .Values.ingress.enabled }} +{{- $host := index .Values.ingress.hosts 0 }} +{{- if .Values.ingress.tls }} +{{- printf "https://%s" $host.host }} +{{- else }} +{{- printf "http://%s" $host.host }} +{{- end }} +{{- else }} +{{- printf "http://localhost:%d" (int .Values.mcp.port) }} +{{- end }} +{{- end }} diff --git a/helm/nextcloud-mcp-server/templates/deployment.yaml b/helm/nextcloud-mcp-server/templates/deployment.yaml index 7586741..23b95e8 100644 --- a/helm/nextcloud-mcp-server/templates/deployment.yaml +++ b/helm/nextcloud-mcp-server/templates/deployment.yaml @@ -76,9 +76,9 @@ spec: {{- else if eq .Values.auth.mode "oauth" }} # OAuth mode - name: NEXTCLOUD_MCP_SERVER_URL - value: {{ .Values.nextcloud.mcpServerUrl | quote }} + value: {{ include "nextcloud-mcp-server.mcpServerUrl" . | quote }} - name: NEXTCLOUD_PUBLIC_ISSUER_URL - value: {{ .Values.nextcloud.publicIssuerUrl | quote }} + value: {{ include "nextcloud-mcp-server.publicIssuerUrl" . | quote }} - name: NEXTCLOUD_OIDC_CLIENT_STORAGE value: "/app/.oauth/nextcloud_oauth_client.json" - name: NEXTCLOUD_OIDC_SCOPES diff --git a/helm/nextcloud-mcp-server/values.yaml b/helm/nextcloud-mcp-server/values.yaml index 6735f3c..99f3f8c 100644 --- a/helm/nextcloud-mcp-server/values.yaml +++ b/helm/nextcloud-mcp-server/values.yaml @@ -21,11 +21,15 @@ nextcloud: # Example: https://cloud.example.com host: "" - # MCP server URL for OAuth callbacks (only needed for OAuth mode) + # 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 OAuth (only needed for OAuth mode) + # Public issuer URL for OAuth (OAuth mode only) + # If not specified, defaults to nextcloud.host + # Only set this if your Nextcloud is accessible at a different URL for OAuth # Example: https://cloud.example.com publicIssuerUrl: "" @@ -39,11 +43,17 @@ auth: # Basic authentication settings basic: - # Nextcloud username + # Nextcloud username (ignored if existingSecret is set) username: "" - # Nextcloud password or app password (recommended) + # 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" @@ -55,13 +65,20 @@ auth: port: 8001 # OAuth token type: "jwt" or "opaque" tokenType: "jwt" - # Pre-registered OAuth client ID (optional, will auto-register if not provided) + # 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) + # 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 credentials + # 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"