Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e6ef90423 | |||
| c5f2c8369f | |||
| b79ac29a9d | |||
| 334d62825c | |||
| 2233cb423c | |||
| 196a6cdfb2 | |||
| 93f5e70128 | |||
| e5248e70ee | |||
| 018b946b5b | |||
| 863ba0d52a | |||
| d3903c5e2e | |||
| 6ea97c5b88 | |||
| c12c825b11 | |||
| 3d8f7692a8 | |||
| b21c874c14 | |||
| a4661099e5 | |||
| a46d74d999 | |||
| 92f69c8dba | |||
| 6692a85007 | |||
| 1f09079b5a | |||
| 2535c95f4e | |||
| 4fac0ca40d | |||
| 719a432a95 | |||
| 14c4512ef8 | |||
| 6f482c9245 | |||
| a6ad3707c6 | |||
| b34f8d96e3 | |||
| d948f51b10 | |||
| 5eb5b5023c | |||
| 504213ae79 | |||
| 5eeaafbe95 | |||
| 0ddc62c371 | |||
| 36d901d5ae | |||
| 0a3052d0d9 | |||
| 2b691f1792 | |||
| e3da2e006c | |||
| 4539f2f486 | |||
| c85ad95faf | |||
| 60f7234908 | |||
| 1dd5698389 | |||
| 3a0096f8df | |||
| 7bcffd1e96 | |||
| 9674366312 | |||
| a7581a1d1b | |||
| 0ff442d61c |
@@ -33,7 +33,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run Claude Code Review
|
- name: Run Claude Code Review
|
||||||
id: claude-review
|
id: claude-review
|
||||||
uses: anthropics/claude-code-action@0ed5eeaa54d3b0170e79f1ff29996342cf0605f1 # v1.0.40
|
uses: anthropics/claude-code-action@b113f49a56229d8276e2bf05743ad6900121239c # v1.0.45
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
allowed_bots: "renovate-bot-cbcoutinho"
|
allowed_bots: "renovate-bot-cbcoutinho"
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Run Claude Code
|
- name: Run Claude Code
|
||||||
id: claude
|
id: claude
|
||||||
uses: anthropics/claude-code-action@0ed5eeaa54d3b0170e79f1ff29996342cf0605f1 # v1.0.40
|
uses: anthropics/claude-code-action@b113f49a56229d8276e2bf05743ad6900121239c # v1.0.45
|
||||||
with:
|
with:
|
||||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
|
|
||||||
- name: Run docker compose with vector sync
|
- name: Run docker compose with vector sync
|
||||||
uses: hoverkraft-tech/compose-action@05da55b2bb8a5a759d1c4732095044bd9018c050 # v2.4.3
|
uses: hoverkraft-tech/compose-action@4894d2492015c1774ee5a13a95b1072093087ec3 # v2.5.0
|
||||||
with:
|
with:
|
||||||
compose-file: |
|
compose-file: |
|
||||||
./docker-compose.yml
|
./docker-compose.yml
|
||||||
@@ -42,7 +42,7 @@ jobs:
|
|||||||
VECTOR_SYNC_SCAN_INTERVAL: "5"
|
VECTOR_SYNC_SCAN_INTERVAL: "5"
|
||||||
|
|
||||||
- name: Install the latest version of uv
|
- name: Install the latest version of uv
|
||||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
||||||
|
|
||||||
- name: Wait for Nextcloud to be ready
|
- name: Wait for Nextcloud to be ready
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ jobs:
|
|||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||||
- name: Install uv
|
- name: Install uv
|
||||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
||||||
- name: Install Python 3.11
|
- name: Install Python 3.11
|
||||||
run: uv python install 3.11
|
run: uv python install 3.11
|
||||||
- name: Build
|
- name: Build
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
||||||
- name: Install the latest version of uv
|
- name: Install the latest version of uv
|
||||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
||||||
- name: Check format
|
- name: Check format
|
||||||
run: |
|
run: |
|
||||||
uv run --frozen ruff format --diff
|
uv run --frozen ruff format --diff
|
||||||
@@ -66,14 +66,14 @@ jobs:
|
|||||||
|
|
||||||
|
|
||||||
- name: Run docker compose
|
- name: Run docker compose
|
||||||
uses: hoverkraft-tech/compose-action@05da55b2bb8a5a759d1c4732095044bd9018c050 # v2.4.3
|
uses: hoverkraft-tech/compose-action@4894d2492015c1774ee5a13a95b1072093087ec3 # v2.5.0
|
||||||
with:
|
with:
|
||||||
compose-file: "./docker-compose.yml"
|
compose-file: "./docker-compose.yml"
|
||||||
#compose-flags: "--profile qdrant"
|
#compose-flags: "--profile qdrant"
|
||||||
up-flags: "--build"
|
up-flags: "--build"
|
||||||
|
|
||||||
- name: Install the latest version of uv
|
- name: Install the latest version of uv
|
||||||
uses: astral-sh/setup-uv@61cb8a9741eeb8a550a1b8544337180c0fc8476b # v7.2.0
|
uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0
|
||||||
|
|
||||||
- name: Install Playwright dependencies
|
- name: Install Playwright dependencies
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ All notable changes to the Nextcloud MCP Server will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||||
and this project adheres to [PEP 440](https://peps.python.org/pep-0440/).
|
and this project adheres to [PEP 440](https://peps.python.org/pep-0440/).
|
||||||
|
|
||||||
|
## v0.63.2 (2026-02-07)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- use CalDAV time-range filter for calendar date range queries
|
||||||
|
|
||||||
|
## v0.63.1 (2026-02-03)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **helm**: add backward compatibility for legacy persistence configs
|
||||||
|
|
||||||
## v0.63.0 (2026-01-28)
|
## v0.63.0 (2026-01-28)
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
FROM docker.io/library/python:3.12-slim-trixie@sha256:5e2dbd4bbdd9c0e67412aea9463906f74a22c60f89eb7b5bbb7d45b66a2b68a6
|
FROM docker.io/library/python:3.12-slim-trixie@sha256:9e01bf1ae5db7649a236da7be1e94ffbbbdd7a93f867dd0d8d5720d9e1f89fab
|
||||||
|
|
||||||
COPY --from=ghcr.io/astral-sh/uv:0.9.26@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.10.0@sha256:78a7ff97cd27b7124a5f3c2aefe146170793c56a1e03321dd31a289f6d82a04f /uv /uvx /bin/
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
# 1. git (required for caldav dependency from git)
|
# 1. git (required for caldav dependency from git)
|
||||||
|
|||||||
+2
-2
@@ -12,12 +12,12 @@
|
|||||||
# - Per-session app password authentication
|
# - Per-session app password authentication
|
||||||
# - Multi-user support via Smithery session config
|
# - Multi-user support via Smithery session config
|
||||||
|
|
||||||
FROM docker.io/library/python:3.12-slim-trixie@sha256:5e2dbd4bbdd9c0e67412aea9463906f74a22c60f89eb7b5bbb7d45b66a2b68a6
|
FROM docker.io/library/python:3.12-slim-trixie@sha256:9e01bf1ae5db7649a236da7be1e94ffbbbdd7a93f867dd0d8d5720d9e1f89fab
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Install uv for fast dependency management
|
# Install uv for fast dependency management
|
||||||
COPY --from=ghcr.io/astral-sh/uv:0.9.26@sha256:9a23023be68b2ed09750ae636228e903a54a05ea56ed03a934d00fe9fbeded4b /uv /uvx /bin/
|
COPY --from=ghcr.io/astral-sh/uv:0.10.0@sha256:78a7ff97cd27b7124a5f3c2aefe146170793c56a1e03321dd31a289f6d82a04f /uv /uvx /bin/
|
||||||
|
|
||||||
# Install dependencies
|
# Install dependencies
|
||||||
# 1. git (required for caldav dependency from git)
|
# 1. git (required for caldav dependency from git)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[tool.commitizen]
|
[tool.commitizen]
|
||||||
name = "cz_conventional_commits"
|
name = "cz_conventional_commits"
|
||||||
version = "0.57.26"
|
version = "0.57.39"
|
||||||
tag_format = "nextcloud-mcp-server-$version"
|
tag_format = "nextcloud-mcp-server-$version"
|
||||||
version_scheme = "semver"
|
version_scheme = "semver"
|
||||||
update_changelog_on_bump = true
|
update_changelog_on_bump = true
|
||||||
|
|||||||
@@ -14,6 +14,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Configurable resource limits
|
- Configurable resource limits
|
||||||
- Grafana dashboard annotations
|
- Grafana dashboard annotations
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.39 (2026-02-07)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.38 (2026-02-07)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.37 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.36 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.35 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.34 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.33 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.32 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.31 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.30 (2026-02-06)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.29 (2026-02-04)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.28 (2026-02-03)
|
||||||
|
|
||||||
|
## nextcloud-mcp-server-0.57.27 (2026-02-03)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **helm**: add backward compatibility for legacy persistence configs
|
||||||
|
|
||||||
## nextcloud-mcp-server-0.57.26 (2026-01-31)
|
## nextcloud-mcp-server-0.57.26 (2026-01-31)
|
||||||
|
|
||||||
## nextcloud-mcp-server-0.57.25 (2026-01-31)
|
## nextcloud-mcp-server-0.57.25 (2026-01-31)
|
||||||
|
|||||||
@@ -4,6 +4,6 @@ dependencies:
|
|||||||
version: 1.16.3
|
version: 1.16.3
|
||||||
- name: ollama
|
- name: ollama
|
||||||
repository: https://otwld.github.io/ollama-helm
|
repository: https://otwld.github.io/ollama-helm
|
||||||
version: 1.40.0
|
version: 1.41.0
|
||||||
digest: sha256:d8cbf3eab778b3e28818dd1f9cbd71c99ce968fb2a46880b162f988a59a5fedf
|
digest: sha256:1d5b958a64eb2102cf347ec199638bfac5b289bafdecff2529099ee6bce03b86
|
||||||
generated: "2026-01-30T11:10:10.104463708Z"
|
generated: "2026-02-04T11:09:21.837825534Z"
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ apiVersion: v2
|
|||||||
name: nextcloud-mcp-server
|
name: nextcloud-mcp-server
|
||||||
description: A Helm chart for Nextcloud MCP Server - enables AI assistants to interact with Nextcloud
|
description: A Helm chart for Nextcloud MCP Server - enables AI assistants to interact with Nextcloud
|
||||||
type: application
|
type: application
|
||||||
version: 0.57.26
|
version: 0.57.39
|
||||||
appVersion: "0.63.0"
|
appVersion: "0.63.2"
|
||||||
keywords:
|
keywords:
|
||||||
- nextcloud
|
- nextcloud
|
||||||
- mcp
|
- mcp
|
||||||
@@ -31,6 +31,6 @@ dependencies:
|
|||||||
repository: https://qdrant.github.io/qdrant-helm
|
repository: https://qdrant.github.io/qdrant-helm
|
||||||
condition: qdrant.networkMode.deploySubchart
|
condition: qdrant.networkMode.deploySubchart
|
||||||
- name: ollama
|
- name: ollama
|
||||||
version: "1.40.0"
|
version: "1.41.0"
|
||||||
repository: https://otwld.github.io/ollama-helm
|
repository: https://otwld.github.io/ollama-helm
|
||||||
condition: ollama.enabled
|
condition: ollama.enabled
|
||||||
|
|||||||
@@ -118,6 +118,25 @@ ingress:
|
|||||||
| `auth.oauth.persistence.enabled` | Enable persistent storage for OAuth | `true` |
|
| `auth.oauth.persistence.enabled` | Enable persistent storage for OAuth | `true` |
|
||||||
| `auth.oauth.persistence.size` | Size of OAuth storage PVC | `100Mi` |
|
| `auth.oauth.persistence.size` | Size of OAuth storage PVC | `100Mi` |
|
||||||
|
|
||||||
|
#### Data Storage
|
||||||
|
|
||||||
|
The `/app/data` directory is used for application data (token databases, Qdrant persistent storage, etc.). It is always mounted as writable to support the read-only root filesystem security context.
|
||||||
|
|
||||||
|
| Parameter | Description | Default |
|
||||||
|
|-----------|-------------|---------|
|
||||||
|
| `dataStorage.enabled` | Enable persistent storage for `/app/data` | `false` |
|
||||||
|
| `dataStorage.size` | Size of data storage PVC | `1Gi` |
|
||||||
|
| `dataStorage.storageClass` | Storage class (leave empty for default) | `""` |
|
||||||
|
| `dataStorage.accessMode` | Access mode | `ReadWriteOnce` |
|
||||||
|
| `dataStorage.existingClaim` | Use existing PVC | `""` |
|
||||||
|
|
||||||
|
**When to enable persistence:**
|
||||||
|
- Multi-user basic auth with offline access (stores `tokens.db`)
|
||||||
|
- Qdrant persistent mode (stores vector database)
|
||||||
|
- Any feature requiring persistent app data
|
||||||
|
|
||||||
|
**When persistence is disabled:** Uses `emptyDir` (non-persistent, data lost on pod restart, but directory remains writable).
|
||||||
|
|
||||||
#### MCP Server Configuration
|
#### MCP Server Configuration
|
||||||
|
|
||||||
| Parameter | Description | Default |
|
| Parameter | Description | Default |
|
||||||
|
|||||||
@@ -120,6 +120,55 @@ Your Nextcloud MCP Server has been deployed in {{ .Values.auth.mode }} authentic
|
|||||||
The dashboard JSON is available in the chart at charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json
|
The dashboard JSON is available in the chart at charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{- $legacyMultiUserBasic := eq (include "nextcloud-mcp-server.legacyMultiUserBasicPersistence" .) "true" }}
|
||||||
|
{{- $legacyQdrant := eq (include "nextcloud-mcp-server.legacyQdrantPersistence" .) "true" }}
|
||||||
|
{{- if or $legacyMultiUserBasic $legacyQdrant }}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
DEPRECATION WARNING
|
||||||
|
================================================================================
|
||||||
|
|
||||||
|
You are using deprecated persistence configuration that will be removed in a
|
||||||
|
future release. Your deployment will continue to work, but please migrate to
|
||||||
|
the new unified dataStorage configuration.
|
||||||
|
|
||||||
|
Deprecated settings detected:
|
||||||
|
{{- if $legacyMultiUserBasic }}
|
||||||
|
- auth.multiUserBasic.persistence.* (currently enabled)
|
||||||
|
{{- end }}
|
||||||
|
{{- if $legacyQdrant }}
|
||||||
|
- qdrant.localPersistence.* (currently enabled)
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
To migrate, update your values.yaml:
|
||||||
|
|
||||||
|
dataStorage:
|
||||||
|
enabled: true
|
||||||
|
{{- if $legacyMultiUserBasic }}
|
||||||
|
size: {{ .Values.auth.multiUserBasic.persistence.size }}
|
||||||
|
{{- else if $legacyQdrant }}
|
||||||
|
size: {{ .Values.qdrant.localPersistence.size }}
|
||||||
|
{{- end }}
|
||||||
|
# storageClass: "" # Optional: specify storage class
|
||||||
|
# existingClaim: "" # Optional: use existing PVC to preserve data
|
||||||
|
|
||||||
|
After migrating, remove the deprecated settings:
|
||||||
|
{{- if $legacyMultiUserBasic }}
|
||||||
|
- auth.multiUserBasic.persistence.enabled
|
||||||
|
- auth.multiUserBasic.persistence.size
|
||||||
|
- auth.multiUserBasic.persistence.storageClass
|
||||||
|
- auth.multiUserBasic.persistence.accessMode
|
||||||
|
{{- end }}
|
||||||
|
{{- if $legacyQdrant }}
|
||||||
|
- qdrant.localPersistence.enabled
|
||||||
|
- qdrant.localPersistence.size
|
||||||
|
- qdrant.localPersistence.storageClass
|
||||||
|
- qdrant.localPersistence.accessMode
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
================================================================================
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
For more information and documentation:
|
For more information and documentation:
|
||||||
- GitHub: https://github.com/cbcoutinho/nextcloud-mcp-server
|
- GitHub: https://github.com/cbcoutinho/nextcloud-mcp-server
|
||||||
- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme
|
- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme
|
||||||
|
|||||||
@@ -127,6 +127,55 @@ Create the name of the PVC to use for Qdrant local persistent storage
|
|||||||
{{- end }}
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Create the name of the PVC to use for /app/data storage
|
||||||
|
*/}}
|
||||||
|
{{- define "nextcloud-mcp-server.dataStoragePvcName" -}}
|
||||||
|
{{- if .Values.dataStorage.existingClaim }}
|
||||||
|
{{- .Values.dataStorage.existingClaim }}
|
||||||
|
{{- else }}
|
||||||
|
{{- include "nextcloud-mcp-server.fullname" . }}-data-storage
|
||||||
|
{{- end }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Determine if data storage PVC should be enabled (backward compatible)
|
||||||
|
Checks new dataStorage.enabled OR legacy persistence configs
|
||||||
|
*/}}
|
||||||
|
{{- define "nextcloud-mcp-server.dataStorageEnabled" -}}
|
||||||
|
{{- if .Values.dataStorage.enabled -}}
|
||||||
|
true
|
||||||
|
{{- else if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled -}}
|
||||||
|
true
|
||||||
|
{{- else if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled -}}
|
||||||
|
true
|
||||||
|
{{- else -}}
|
||||||
|
false
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Check if legacy multi-user-basic persistence config is being used
|
||||||
|
*/}}
|
||||||
|
{{- define "nextcloud-mcp-server.legacyMultiUserBasicPersistence" -}}
|
||||||
|
{{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled (not .Values.dataStorage.enabled) -}}
|
||||||
|
true
|
||||||
|
{{- else -}}
|
||||||
|
false
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
{{/*
|
||||||
|
Check if legacy qdrant persistence config is being used
|
||||||
|
*/}}
|
||||||
|
{{- define "nextcloud-mcp-server.legacyQdrantPersistence" -}}
|
||||||
|
{{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled (not .Values.dataStorage.enabled) -}}
|
||||||
|
true
|
||||||
|
{{- else -}}
|
||||||
|
false
|
||||||
|
{{- end -}}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
{{/*
|
{{/*
|
||||||
Return the MCP server port
|
Return the MCP server port
|
||||||
*/}}
|
*/}}
|
||||||
|
|||||||
@@ -286,14 +286,8 @@ spec:
|
|||||||
- name: oauth-storage
|
- name: oauth-storage
|
||||||
mountPath: /app/.oauth
|
mountPath: /app/.oauth
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled }}
|
- name: data-storage
|
||||||
- name: token-storage
|
|
||||||
mountPath: /app/data
|
mountPath: /app/data
|
||||||
{{- end }}
|
|
||||||
{{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled }}
|
|
||||||
- name: qdrant-data
|
|
||||||
mountPath: /app/data
|
|
||||||
{{- end }}
|
|
||||||
{{- with .Values.volumeMounts }}
|
{{- with .Values.volumeMounts }}
|
||||||
{{- toYaml . | nindent 12 }}
|
{{- toYaml . | nindent 12 }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
@@ -305,15 +299,12 @@ spec:
|
|||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }}
|
claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled }}
|
- name: data-storage
|
||||||
- name: token-storage
|
{{- if eq (include "nextcloud-mcp-server.dataStorageEnabled" .) "true" }}
|
||||||
persistentVolumeClaim:
|
persistentVolumeClaim:
|
||||||
claimName: {{ include "nextcloud-mcp-server.multiUserBasicPvcName" . }}
|
claimName: {{ include "nextcloud-mcp-server.dataStoragePvcName" . }}
|
||||||
{{- end }}
|
{{- else }}
|
||||||
{{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled }}
|
emptyDir: {}
|
||||||
- name: qdrant-data
|
|
||||||
persistentVolumeClaim:
|
|
||||||
claimName: {{ include "nextcloud-mcp-server.qdrantPvcName" . }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
{{- with .Values.volumes }}
|
{{- with .Values.volumes }}
|
||||||
{{- toYaml . | nindent 8 }}
|
{{- toYaml . | nindent 8 }}
|
||||||
|
|||||||
@@ -16,38 +16,34 @@ spec:
|
|||||||
storage: {{ .Values.auth.oauth.persistence.size }}
|
storage: {{ .Values.auth.oauth.persistence.size }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
---
|
---
|
||||||
{{- if and (eq .Values.auth.mode "multi-user-basic") .Values.auth.multiUserBasic.enableOfflineAccess .Values.auth.multiUserBasic.persistence.enabled (not .Values.auth.multiUserBasic.persistence.existingClaim) }}
|
{{- if and (eq (include "nextcloud-mcp-server.dataStorageEnabled" .) "true") (not .Values.dataStorage.existingClaim) }}
|
||||||
|
{{- $legacyMultiUserBasic := eq (include "nextcloud-mcp-server.legacyMultiUserBasicPersistence" .) "true" }}
|
||||||
|
{{- $legacyQdrant := eq (include "nextcloud-mcp-server.legacyQdrantPersistence" .) "true" }}
|
||||||
|
{{- $accessMode := .Values.dataStorage.accessMode }}
|
||||||
|
{{- $storageClass := .Values.dataStorage.storageClass }}
|
||||||
|
{{- $size := .Values.dataStorage.size }}
|
||||||
|
{{- if $legacyMultiUserBasic }}
|
||||||
|
{{- $accessMode = .Values.auth.multiUserBasic.persistence.accessMode }}
|
||||||
|
{{- $storageClass = .Values.auth.multiUserBasic.persistence.storageClass }}
|
||||||
|
{{- $size = .Values.auth.multiUserBasic.persistence.size }}
|
||||||
|
{{- else if $legacyQdrant }}
|
||||||
|
{{- $accessMode = .Values.qdrant.localPersistence.accessMode }}
|
||||||
|
{{- $storageClass = .Values.qdrant.localPersistence.storageClass }}
|
||||||
|
{{- $size = .Values.qdrant.localPersistence.size }}
|
||||||
|
{{- end }}
|
||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
kind: PersistentVolumeClaim
|
kind: PersistentVolumeClaim
|
||||||
metadata:
|
metadata:
|
||||||
name: {{ include "nextcloud-mcp-server.fullname" . }}-token-storage
|
name: {{ include "nextcloud-mcp-server.fullname" . }}-data-storage
|
||||||
labels:
|
labels:
|
||||||
{{- include "nextcloud-mcp-server.labels" . | nindent 4 }}
|
{{- include "nextcloud-mcp-server.labels" . | nindent 4 }}
|
||||||
spec:
|
spec:
|
||||||
accessModes:
|
accessModes:
|
||||||
- {{ .Values.auth.multiUserBasic.persistence.accessMode }}
|
- {{ $accessMode }}
|
||||||
{{- if .Values.auth.multiUserBasic.persistence.storageClass }}
|
{{- if $storageClass }}
|
||||||
storageClassName: {{ .Values.auth.multiUserBasic.persistence.storageClass }}
|
storageClassName: {{ $storageClass }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
resources:
|
resources:
|
||||||
requests:
|
requests:
|
||||||
storage: {{ .Values.auth.multiUserBasic.persistence.size }}
|
storage: {{ $size }}
|
||||||
{{- end }}
|
|
||||||
---
|
|
||||||
{{- if and (eq .Values.qdrant.mode "persistent") .Values.qdrant.localPersistence.enabled (not .Values.qdrant.localPersistence.existingClaim) }}
|
|
||||||
apiVersion: v1
|
|
||||||
kind: PersistentVolumeClaim
|
|
||||||
metadata:
|
|
||||||
name: {{ include "nextcloud-mcp-server.fullname" . }}-qdrant-data
|
|
||||||
labels:
|
|
||||||
{{- include "nextcloud-mcp-server.labels" . | nindent 4 }}
|
|
||||||
spec:
|
|
||||||
accessModes:
|
|
||||||
- {{ .Values.qdrant.localPersistence.accessMode }}
|
|
||||||
{{- if .Values.qdrant.localPersistence.storageClass }}
|
|
||||||
storageClassName: {{ .Values.qdrant.localPersistence.storageClass }}
|
|
||||||
{{- end }}
|
|
||||||
resources:
|
|
||||||
requests:
|
|
||||||
storage: {{ .Values.qdrant.localPersistence.size }}
|
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
|||||||
@@ -139,6 +139,27 @@ auth:
|
|||||||
# Use existing PVC
|
# Use existing PVC
|
||||||
existingClaim: ""
|
existingClaim: ""
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
# - 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 server configuration
|
||||||
mcp:
|
mcp:
|
||||||
# Transport mode (default: streamable-http for SSE)
|
# Transport mode (default: streamable-http for SSE)
|
||||||
|
|||||||
+2
-2
@@ -23,7 +23,7 @@ services:
|
|||||||
restart: always
|
restart: always
|
||||||
|
|
||||||
app:
|
app:
|
||||||
image: docker.io/library/nextcloud:32.0.5@sha256:11a3a4f63bad8813c7455b4a3c473ccd1c41e2c48f55decb51718f15691e7568
|
image: docker.io/library/nextcloud:32.0.5@sha256:4b66e9bd8cb2c8af5457c1e2606c9937af2fcccbe4f6338956bc5990caec8968
|
||||||
restart: always
|
restart: always
|
||||||
ports:
|
ports:
|
||||||
- 127.0.0.1:8080:80
|
- 127.0.0.1:8080:80
|
||||||
@@ -54,7 +54,7 @@ services:
|
|||||||
retries: 30
|
retries: 30
|
||||||
|
|
||||||
recipes:
|
recipes:
|
||||||
image: docker.io/library/nginx:alpine@sha256:4870c12cd2ca986de501a804b4f506ad3875a0b1874940ba0a2c7f763f1855b2
|
image: docker.io/library/nginx:alpine@sha256:5878d06ae4c83d73285438255f705bb3f9a736f41cd24876ed25bb33faf76c7d
|
||||||
restart: always
|
restart: always
|
||||||
volumes:
|
volumes:
|
||||||
- ./tests/fixtures/test_recipe.html:/usr/share/nginx/html/test_recipe.html:ro
|
- ./tests/fixtures/test_recipe.html:/usr/share/nginx/html/test_recipe.html:ro
|
||||||
|
|||||||
@@ -255,8 +255,14 @@ class CalendarClient:
|
|||||||
"""List events in a calendar within date range."""
|
"""List events in a calendar within date range."""
|
||||||
calendar = self._get_calendar(calendar_name)
|
calendar = self._get_calendar(calendar_name)
|
||||||
|
|
||||||
# Get all events using caldav library (now with proper filter)
|
if start_datetime or end_datetime:
|
||||||
events = await calendar.events()
|
# Build CalDAV REPORT with time-range filter for server-side filtering
|
||||||
|
events = await self._search_events_by_date(
|
||||||
|
calendar, start_datetime, end_datetime
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
# No date filter — fetch all events
|
||||||
|
events = await calendar.events()
|
||||||
|
|
||||||
result = []
|
result = []
|
||||||
for event in events:
|
for event in events:
|
||||||
@@ -274,6 +280,52 @@ class CalendarClient:
|
|||||||
logger.debug(f"Found {len(result)} events")
|
logger.debug(f"Found {len(result)} events")
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
async def _search_events_by_date(
|
||||||
|
self,
|
||||||
|
calendar: AsyncCalendar,
|
||||||
|
start_datetime: Optional[dt.datetime] = None,
|
||||||
|
end_datetime: Optional[dt.datetime] = None,
|
||||||
|
) -> list:
|
||||||
|
"""Execute a CalDAV REPORT with time-range filter."""
|
||||||
|
from caldav.async_collection import AsyncEvent
|
||||||
|
from caldav.elements import cdav, dav
|
||||||
|
from lxml import etree # type: ignore[import-untyped]
|
||||||
|
|
||||||
|
# Ensure naive datetimes are treated as UTC
|
||||||
|
if start_datetime and start_datetime.tzinfo is None:
|
||||||
|
start_datetime = start_datetime.replace(tzinfo=dt.UTC)
|
||||||
|
if end_datetime and end_datetime.tzinfo is None:
|
||||||
|
end_datetime = end_datetime.replace(tzinfo=dt.UTC)
|
||||||
|
|
||||||
|
# Build comp-filter with time-range (mirrors sync Calendar.build_search_xml_query)
|
||||||
|
inner_comp_filter = cdav.CompFilter(name="VEVENT")
|
||||||
|
inner_comp_filter += cdav.TimeRange(start_datetime, end_datetime)
|
||||||
|
outer_comp_filter = cdav.CompFilter(name="VCALENDAR") + inner_comp_filter
|
||||||
|
filter_element = cdav.Filter() + outer_comp_filter
|
||||||
|
|
||||||
|
query = (
|
||||||
|
cdav.CalendarQuery() + [dav.Prop() + cdav.CalendarData()] + filter_element
|
||||||
|
)
|
||||||
|
|
||||||
|
body = etree.tostring(
|
||||||
|
query.xmlelement(), encoding="utf-8", xml_declaration=True
|
||||||
|
)
|
||||||
|
assert calendar.client is not None
|
||||||
|
response = await calendar.client.report(str(calendar.url), body, depth=1)
|
||||||
|
|
||||||
|
# Parse response (same pattern as AsyncCalendar.search)
|
||||||
|
objects = []
|
||||||
|
response_data = response.expand_simple_props([cdav.CalendarData()])
|
||||||
|
for href, props in response_data.items():
|
||||||
|
if href == str(calendar.url):
|
||||||
|
continue
|
||||||
|
cal_data = props.get(cdav.CalendarData.tag)
|
||||||
|
if cal_data:
|
||||||
|
obj = AsyncEvent(client=calendar.client, data=cal_data, parent=calendar)
|
||||||
|
objects.append(obj)
|
||||||
|
|
||||||
|
return objects
|
||||||
|
|
||||||
async def create_event(
|
async def create_event(
|
||||||
self, calendar_name: str, event_data: Dict[str, Any]
|
self, calendar_name: str, event_data: Dict[str, Any]
|
||||||
) -> Dict[str, Any]:
|
) -> Dict[str, Any]:
|
||||||
|
|||||||
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "nextcloud-mcp-server"
|
name = "nextcloud-mcp-server"
|
||||||
version = "0.63.0"
|
version = "0.63.2"
|
||||||
description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data"
|
description = "Model Context Protocol (MCP) server for Nextcloud integration - enables AI assistants to interact with Nextcloud data"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "Chris Coutinho", email = "chris@coutinho.io"}
|
{name = "Chris Coutinho", email = "chris@coutinho.io"}
|
||||||
@@ -114,7 +114,7 @@ caldav = { git = "https://github.com/cbcoutinho/caldav", branch = "feature/httpx
|
|||||||
qdrant-client = { git = "https://github.com/cbcoutinho/qdrant-client", branch = "fix/fusion-score-threshold" }
|
qdrant-client = { git = "https://github.com/cbcoutinho/qdrant-client", branch = "fix/fusion-score-threshold" }
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["uv_build>=0.9.4,<0.10.0"]
|
requires = ["uv_build>=0.10.0,<0.11.0"]
|
||||||
build-backend = "uv_build"
|
build-backend = "uv_build"
|
||||||
|
|
||||||
[tool.uv.build-backend]
|
[tool.uv.build-backend]
|
||||||
|
|||||||
@@ -380,6 +380,86 @@ async def test_event_with_url_and_categories(
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
async def test_list_events_date_range_filtering(
|
||||||
|
nc_client: NextcloudClient, temporary_calendar: str
|
||||||
|
):
|
||||||
|
"""Test that date range filtering actually excludes events outside the range.
|
||||||
|
|
||||||
|
Reproduces GH-538: get_calendar_events() accepted date range parameters
|
||||||
|
but returned events from the entire calendar history, ignoring date filters.
|
||||||
|
"""
|
||||||
|
calendar_name = temporary_calendar
|
||||||
|
past_uid = None
|
||||||
|
future_uid = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Create Event A: 30 days in the past
|
||||||
|
past_date = datetime.now() - timedelta(days=30)
|
||||||
|
past_event_data = {
|
||||||
|
"title": f"Past Event {uuid.uuid4().hex[:8]}",
|
||||||
|
"start_datetime": past_date.strftime("%Y-%m-%dT10:00:00"),
|
||||||
|
"end_datetime": past_date.strftime("%Y-%m-%dT11:00:00"),
|
||||||
|
"description": "Event in the past for date range test",
|
||||||
|
}
|
||||||
|
result_past = await nc_client.calendar.create_event(
|
||||||
|
calendar_name, past_event_data
|
||||||
|
)
|
||||||
|
past_uid = result_past["uid"]
|
||||||
|
logger.info(f"Created past event: {past_uid}")
|
||||||
|
|
||||||
|
# Create Event B: 1 day in the future
|
||||||
|
future_date = datetime.now() + timedelta(days=1)
|
||||||
|
future_event_data = {
|
||||||
|
"title": f"Future Event {uuid.uuid4().hex[:8]}",
|
||||||
|
"start_datetime": future_date.strftime("%Y-%m-%dT14:00:00"),
|
||||||
|
"end_datetime": future_date.strftime("%Y-%m-%dT15:00:00"),
|
||||||
|
"description": "Event in the future for date range test",
|
||||||
|
}
|
||||||
|
result_future = await nc_client.calendar.create_event(
|
||||||
|
calendar_name, future_event_data
|
||||||
|
)
|
||||||
|
future_uid = result_future["uid"]
|
||||||
|
logger.info(f"Created future event: {future_uid}")
|
||||||
|
|
||||||
|
# Query with date range: today → 7 days ahead
|
||||||
|
now = datetime.now()
|
||||||
|
week_ahead = now + timedelta(days=7)
|
||||||
|
|
||||||
|
events = await nc_client.calendar.get_calendar_events(
|
||||||
|
calendar_name=calendar_name,
|
||||||
|
start_datetime=now,
|
||||||
|
end_datetime=week_ahead,
|
||||||
|
limit=50,
|
||||||
|
)
|
||||||
|
|
||||||
|
event_uids = [e["uid"] for e in events]
|
||||||
|
|
||||||
|
# Future event (tomorrow) SHOULD be in results
|
||||||
|
assert future_uid in event_uids, (
|
||||||
|
f"Future event {future_uid} should be in date-filtered results"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Past event (30 days ago) should NOT be in results
|
||||||
|
assert past_uid not in event_uids, (
|
||||||
|
f"Past event {past_uid} should be excluded by date range filter "
|
||||||
|
f"(GH-538: date range was being ignored)"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
f"Date range filtering works: {len(events)} events returned, "
|
||||||
|
f"past event correctly excluded"
|
||||||
|
)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Cleanup both events
|
||||||
|
for uid in [past_uid, future_uid]:
|
||||||
|
if uid:
|
||||||
|
try:
|
||||||
|
await nc_client.calendar.delete_event(calendar_name, uid)
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Cleanup failed for event {uid}: {e}")
|
||||||
|
|
||||||
|
|
||||||
async def test_calendar_operations_error_handling(
|
async def test_calendar_operations_error_handling(
|
||||||
nc_client: NextcloudClient,
|
nc_client: NextcloudClient,
|
||||||
):
|
):
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[tool.commitizen]
|
[tool.commitizen]
|
||||||
name = "cz_conventional_commits"
|
name = "cz_conventional_commits"
|
||||||
version = "0.10.0"
|
version = "0.10.1"
|
||||||
tag_format = "astrolabe-v$version"
|
tag_format = "astrolabe-v$version"
|
||||||
version_scheme = "semver"
|
version_scheme = "semver"
|
||||||
update_changelog_on_bump = true
|
update_changelog_on_bump = true
|
||||||
|
|||||||
Vendored
+6
@@ -25,6 +25,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- Requires external MCP server deployment
|
- Requires external MCP server deployment
|
||||||
- See documentation for setup: https://github.com/cbcoutinho/nextcloud-mcp-server
|
- See documentation for setup: https://github.com/cbcoutinho/nextcloud-mcp-server
|
||||||
|
|
||||||
|
## astrolabe-v0.10.1 (2026-02-03)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- **helm**: add backward compatibility for legacy persistence configs
|
||||||
|
|
||||||
## astrolabe-v0.10.0 (2026-01-28)
|
## astrolabe-v0.10.0 (2026-01-28)
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|||||||
+1
-1
@@ -29,7 +29,7 @@ Astrolabe connects to a semantic search service that understands the meaning of
|
|||||||
|
|
||||||
See [documentation](https://github.com/cbcoutinho/nextcloud-mcp-server) for configuration details.
|
See [documentation](https://github.com/cbcoutinho/nextcloud-mcp-server) for configuration details.
|
||||||
]]></description>
|
]]></description>
|
||||||
<version>0.10.0</version>
|
<version>0.10.1</version>
|
||||||
<licence>agpl</licence>
|
<licence>agpl</licence>
|
||||||
<author homepage="https://github.com/cbcoutinho">Chris Coutinho</author>
|
<author homepage="https://github.com/cbcoutinho">Chris Coutinho</author>
|
||||||
<namespace>Astrolabe</namespace>
|
<namespace>Astrolabe</namespace>
|
||||||
|
|||||||
Vendored
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "astrolabe",
|
"name": "astrolabe",
|
||||||
"version": "0.10.0",
|
"version": "0.10.1",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^22.0.0",
|
"node": "^22.0.0",
|
||||||
|
|||||||
@@ -1988,7 +1988,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nextcloud-mcp-server"
|
name = "nextcloud-mcp-server"
|
||||||
version = "0.63.0"
|
version = "0.63.2"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "aiosqlite" },
|
{ name = "aiosqlite" },
|
||||||
|
|||||||
Reference in New Issue
Block a user