diff --git a/.github/workflows/bump-version.yml b/.github/workflows/bump-version.yml index 1bc98b47..d3115b59 100644 --- a/.github/workflows/bump-version.yml +++ b/.github/workflows/bump-version.yml @@ -9,7 +9,7 @@ jobs: bump-version: if: "!startsWith(github.event.head_commit.message, 'bump:') && !startsWith(github.event.head_commit.message, 'chore(release):')" runs-on: ubuntu-latest - name: "Bump version and create changelog for monorepo components" + name: "Bump version and create changelog" permissions: contents: write packages: write @@ -35,94 +35,33 @@ jobs: git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Detect and bump component versions + - name: Detect and bump version id: bump run: | set -euo pipefail - # Track which components were bumped - BUMPED_COMPONENTS="" + echo "Checking for version bump..." - # Helper function to check for commits with specific scope since last tag - has_commits_since_tag() { - local tag_pattern="$1" - local scope_pattern="$2" + # Get the most recent tag + last_tag=$(git tag --sort=-creatordate | grep -E "^v[0-9]" | head -n 1 || echo "") - # Get the most recent tag matching the pattern - local last_tag=$(git tag --sort=-creatordate | grep -E "^${tag_pattern}" | head -n 1 || echo "") - - if [ -z "$last_tag" ]; then - # No previous tag, check all commits on master - local commit_range="master" - else - # Check commits since last tag - local commit_range="${last_tag}..HEAD" - fi - - # Count commits matching the scope pattern - local commit_count=$(git log "$commit_range" --oneline --grep="^${scope_pattern}" -E | wc -l) - - if [ "$commit_count" -gt 0 ]; then - echo "Found $commit_count commits for scope '$scope_pattern' since $last_tag" - return 0 - else - echo "No commits found for scope '$scope_pattern' since $last_tag" - return 1 - fi - } - - # Bump MCP server (default - all commits except helm scope) - echo "Checking MCP server for version bump..." - - # Get the most recent MCP tag - last_mcp_tag=$(git tag --sort=-creatordate | grep -E "^v[0-9]" | head -n 1 || echo "") - - if [ -z "$last_mcp_tag" ]; then + if [ -z "$last_tag" ]; then commit_range="master" else - commit_range="${last_mcp_tag}..HEAD" + commit_range="${last_tag}..HEAD" fi - # Count conventional commits that are NOT scoped to helm - mcp_commit_count=$(git log "$commit_range" --oneline --grep="^(feat|fix|docs|refactor|perf|test|build|ci|chore)" -E | \ - { grep -v "(helm)" || true; } | wc -l) + # Count conventional commits + commit_count=$(git log "$commit_range" --oneline --grep="^(feat|fix|docs|refactor|perf|test|build|ci|chore)" -E | wc -l) - MCP_BUMPED=false - if [ "$mcp_commit_count" -gt 0 ]; then - echo "Found $mcp_commit_count commits for MCP server since $last_mcp_tag" - echo "Bumping MCP server version..." + if [ "$commit_count" -gt 0 ]; then + echo "Found $commit_count commits since $last_tag" + echo "Bumping version..." ./scripts/bump-mcp.sh - BUMPED_COMPONENTS="$BUMPED_COMPONENTS mcp" - MCP_BUMPED=true - else - echo "No commits found for MCP server since $last_mcp_tag" - fi - - # Bump Helm chart (scope: helm OR when MCP appVersion changes) - echo "Checking Helm chart for version bump..." - HELM_HAS_COMMITS=false - if has_commits_since_tag "nextcloud-mcp-server-" "(feat|fix|docs|refactor|perf|test|build|ci|chore)\(helm\)(!)?:"; then - HELM_HAS_COMMITS=true - fi - - if [ "$HELM_HAS_COMMITS" = true ]; then - echo "Bumping Helm chart version (helm-scoped commits)..." - ./scripts/bump-helm.sh - BUMPED_COMPONENTS="$BUMPED_COMPONENTS helm" - elif [ "$MCP_BUMPED" = true ]; then - echo "Bumping Helm chart version (appVersion changed)..." - ./scripts/bump-helm.sh --increment PATCH - BUMPED_COMPONENTS="$BUMPED_COMPONENTS helm" - fi - - # Output summary - if [ -z "$BUMPED_COMPONENTS" ]; then - echo "No components required version bumps" - echo "bumped=false" >> $GITHUB_OUTPUT - else - echo "Bumped components:$BUMPED_COMPONENTS" echo "bumped=true" >> $GITHUB_OUTPUT - echo "components=$BUMPED_COMPONENTS" >> $GITHUB_OUTPUT + else + echo "No commits found since $last_tag" + echo "bumped=false" >> $GITHUB_OUTPUT fi - name: Push tags @@ -130,35 +69,19 @@ jobs: run: | git push git push --tags - echo "Pushed tags for components:${{ steps.bump.outputs.components }}" + echo "Pushed version tags" - name: Summary run: | if [ "${{ steps.bump.outputs.bumped }}" == "true" ]; then + tag=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1) echo "## Version Bump Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "The following components were bumped:" >> $GITHUB_STEP_SUMMARY + echo "- **MCP Server**: \`$tag\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - - for component in ${{ steps.bump.outputs.components }}; do - case $component in - mcp) - tag=$(git tag --sort=-creatordate | grep -E '^v[0-9]' | head -n 1) - echo "- **MCP Server**: \`$tag\`" >> $GITHUB_STEP_SUMMARY - ;; - helm) - tag=$(git tag --sort=-creatordate | grep -E '^nextcloud-mcp-server-' | head -n 1) - echo "- **Helm Chart**: \`$tag\`" >> $GITHUB_STEP_SUMMARY - ;; - esac - done - - echo "" >> $GITHUB_STEP_SUMMARY - echo "Tags have been pushed and release workflows will trigger automatically." >> $GITHUB_STEP_SUMMARY + echo "Tag has been pushed and release workflows will trigger automatically." >> $GITHUB_STEP_SUMMARY else echo "## Version Bump Summary" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - echo "✅ No version bumps required - no relevant commits found since last release." >> $GITHUB_STEP_SUMMARY - echo "" >> $GITHUB_STEP_SUMMARY - echo "The workflow completed successfully with no changes." >> $GITHUB_STEP_SUMMARY + echo "No version bump required - no relevant commits found since last release." >> $GITHUB_STEP_SUMMARY fi diff --git a/.github/workflows/helm-release.yml b/.github/workflows/helm-release.yml deleted file mode 100644 index 7d410614..00000000 --- a/.github/workflows/helm-release.yml +++ /dev/null @@ -1,137 +0,0 @@ -name: Release Charts - -on: - push: - tags: - - v* - - nextcloud-mcp-server-* - -jobs: - release: - # depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions - # see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token - permissions: - contents: write - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - fetch-depth: 0 - - - - name: Configure Git - run: | - git config user.name "$GITHUB_ACTOR" - git config user.email "$GITHUB_ACTOR@users.noreply.github.com" - - - name: Install Helm - uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1 - with: - version: v3.16.0 - - - name: Add Helm repositories and update dependencies - run: | - helm repo add qdrant https://qdrant.github.io/qdrant-helm - helm repo add ollama https://otwld.github.io/ollama-helm - helm repo update - helm dependency build charts/nextcloud-mcp-server - - - name: Run chart-releaser - uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f # v1.7.0 - with: - skip_existing: true - env: - CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - - - name: Update gh-pages with Chart README and Index - run: | - # Get the repository name - REPO_NAME="${GITHUB_REPOSITORY##*/}" - REPO_OWNER="${GITHUB_REPOSITORY%/*}" - - # Switch to gh-pages branch - git fetch origin gh-pages - git checkout gh-pages - - # Copy Chart README to root - git checkout ${GITHUB_REF#refs/tags/} -- charts/nextcloud-mcp-server/README.md - mv charts/nextcloud-mcp-server/README.md README.md || true - rm -rf charts 2>/dev/null || true - - # Create index.html with installation instructions - cat > index.html <<'EOF' - - - - - - Nextcloud MCP Server Helm Chart - - - -

Nextcloud MCP Server Helm Chart

- -

A Helm chart for deploying the Nextcloud MCP (Model Context Protocol) Server on Kubernetes, enabling AI assistants to interact with your Nextcloud instance.

- -

Installation

- -

Add the Helm repository:

-
helm repo add nextcloud-mcp https://REPO_OWNER.github.io/REPO_NAME/
-          helm repo update
- -

Install the chart:

-
helm install nextcloud-mcp nextcloud-mcp/nextcloud-mcp-server \
-            --set nextcloud.host=https://cloud.example.com \
-            --set auth.basic.username=myuser \
-            --set auth.basic.password=mypassword
- -

Documentation

- - - -

Quick Start

- -

See the full documentation for detailed configuration options, examples, and troubleshooting guides.

- -
-

Generated by chart-releaser

- - - EOF - - # Replace placeholders - sed -i "s/REPO_OWNER/$REPO_OWNER/g" index.html - sed -i "s/REPO_NAME/$REPO_NAME/g" index.html - - # Commit changes - git add README.md index.html - git commit -m "Update README and index from chart release" || echo "No changes to commit" - git push origin gh-pages diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 984cd395..132423e9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,58 +2,35 @@ ## Version Management -This monorepo uses commitizen for version management with **independent versioning** for two components: +This project uses [commitizen](https://commitizen-tools.github.io/commitizen/) for version management following PEP 440 (`major_version_zero = true`, 0.x.x for pre-1.0). -### Components - -| Component | Scope | Bump Command | Tag Example | -|-----------|-------|--------------|-------------| -| MCP Server | `mcp` or none | `./scripts/bump-mcp.sh` | `v0.54.0` | -| Helm Chart | `helm` | `./scripts/bump-helm.sh` | `nextcloud-mcp-server-0.54.0` | - -> **Note:** The Astrolabe Nextcloud app has been moved to its own repository at [cbcoutinho/astrolabe](https://github.com/cbcoutinho/astrolabe). +> **Note:** The Helm chart has been moved to [cbcoutinho/helm-charts](https://github.com/cbcoutinho/helm-charts). The Astrolabe Nextcloud app has been moved to [cbcoutinho/astrolabe](https://github.com/cbcoutinho/astrolabe). ### Commit Message Format -Use conventional commits with **scopes** to target specific components: +Use [conventional commits](https://www.conventionalcommits.org/): ```bash -# MCP server changes +feat: add new feature feat(mcp): add calendar sync API -fix(mcp): resolve authentication bug - -# Helm chart changes -feat(helm): add resource limits -docs(helm): update values documentation -``` - -**Unscoped commits** default to the MCP server: -```bash -feat: add new feature # → MCP server (v0.54.0) +fix: resolve authentication bug +docs: update README ``` ### Release Workflow -#### 1. Make Changes with Scoped Commits +#### 1. Make Changes with Conventional Commits ```bash -git commit -m "feat(helm): add ingress annotations" -git commit -m "feat(mcp): add calendar sync" +git commit -m "feat: add calendar sync" ``` -#### 2. Bump Component Versions +#### 2. Bump Version ```bash -# Bump MCP server (reads commits with scope=mcp or unscoped) ./scripts/bump-mcp.sh # → Creates tag: v0.54.0 -# → Updates: pyproject.toml, Chart.yaml:appVersion - -# Bump Helm chart (reads commits with scope=helm) -./scripts/bump-helm.sh -# → Creates tag: nextcloud-mcp-server-0.54.0 -# → Updates: Chart.yaml:version - +# → Updates: pyproject.toml ``` #### 3. Push Tags @@ -62,13 +39,6 @@ git commit -m "feat(mcp): add calendar sync" git push --follow-tags ``` -### Changelog Filtering - -Each component maintains its own `CHANGELOG.md`: - -- **MCP Server**: `CHANGELOG.md` (root) - includes `feat(mcp):` and unscoped commits -- **Helm Chart**: `charts/nextcloud-mcp-server/CHANGELOG.md` - includes `feat(helm):` only - ### Manual Version Bumps For specific increments: @@ -82,25 +52,4 @@ uv run cz bump --increment MINOR # Major bump (0.53.0 → 1.0.0) uv run cz bump --increment MAJOR - -# For non-MCP components, use --config -cd charts/nextcloud-mcp-server -uv run cz --config .cz.toml bump --increment MINOR ``` - -### Versioning Philosophy - -- **MCP Server**: Follows PEP 440, `major_version_zero = true` (0.x.x for pre-1.0) -- **Helm Chart**: Follows PEP 440, starts at 0.53.0 (continues from current) - -### Chart.yaml Version vs appVersion - -The Helm chart has TWO version fields: - -- **`version`**: Chart packaging version (bumped by `feat(helm):`) - - Example: `0.53.0` → `0.54.0` when adding resource limits - -- **`appVersion`**: MCP server version being deployed (bumped by `feat(mcp):`) - - Example: `"0.53.0"` → `"0.54.0"` when MCP server releases - -This allows the chart to evolve independently from the application. diff --git a/README.md b/README.md index b965bfd4..1cab6035 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ docker compose --profile login-flow up -d # Port 8004 **Next Steps:** - Connect your MCP client (Claude Desktop, IDEs, `mcp dev`, etc.) -- See [docs/installation.md](docs/installation.md) for other deployment options (local, Kubernetes) +- See [docs/installation.md](docs/installation.md) for other deployment options. For Kubernetes (Helm), see [cbcoutinho/helm-charts](https://github.com/cbcoutinho/helm-charts) ## Key Features @@ -60,7 +60,7 @@ docker compose --profile login-flow up -d # Port 8004 - **MCP Resources** - Structured data URIs for browsing Nextcloud data - **Semantic Search (Experimental)** - Optional vector-powered search for Notes, Files, News items, and Deck cards (requires Qdrant + Ollama) - **Document Processing** - OCR and text extraction from PDFs, DOCX, images with progress notifications -- **Flexible Deployment** - Docker, Kubernetes (Helm), VM, or local installation +- **Flexible Deployment** - Docker, Kubernetes ([Helm chart](https://github.com/cbcoutinho/helm-charts)), VM, or local installation - **Production-Ready Auth** - Basic Auth with app passwords (recommended) or OAuth2/OIDC (experimental) - **Multiple Transports** - SSE, HTTP, and streamable-http support @@ -146,7 +146,7 @@ This enables natural language queries and helps discover related content across ## Documentation ### Getting Started -- **[Installation](docs/installation.md)** - Docker, Kubernetes, local, or VM deployment +- **[Installation](docs/installation.md)** - Docker, local, or VM deployment. [Helm chart](https://github.com/cbcoutinho/helm-charts) for Kubernetes - **[Configuration](docs/configuration.md)** - Environment variables and advanced options - **[Authentication](docs/authentication.md)** - Basic Auth vs OAuth2/OIDC setup - **[Running the Server](docs/running.md)** - Start, manage, and troubleshoot diff --git a/charts/nextcloud-mcp-server/.cz.toml b/charts/nextcloud-mcp-server/.cz.toml deleted file mode 100644 index 9559d46d..00000000 --- a/charts/nextcloud-mcp-server/.cz.toml +++ /dev/null @@ -1,25 +0,0 @@ -[tool.commitizen] -name = "cz_conventional_commits" -version = "0.58.31" -tag_format = "nextcloud-mcp-server-$version" -version_scheme = "semver" -update_changelog_on_bump = true -major_version_zero = true - -# Update chart version only (NOT appVersion) -version_files = [ - "Chart.yaml:^version:" -] - -# Ignore tags from other components -ignored_tag_formats = [ - "v*", # MCP server tags - "astrolabe-v*", # Astrolabe tags -] - -# Filter commits by scope -# Includes helm-scoped commits AND MCP server version bumps (which update appVersion) -[tool.commitizen.customize] -changelog_pattern = "^((feat|fix|docs|refactor|perf|test|build|ci|chore)\\(helm\\)(!)?:|bump: version.*→.*)" -schema_pattern = "^(feat|fix|docs|refactor|perf|test|build|ci|chore)\\(helm\\)(!)?:\\s.+" -message_template = "{{change_type}}(helm): {{message}}" diff --git a/charts/nextcloud-mcp-server/.gitignore b/charts/nextcloud-mcp-server/.gitignore deleted file mode 100644 index ee3892e8..00000000 --- a/charts/nextcloud-mcp-server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -charts/ diff --git a/charts/nextcloud-mcp-server/.helmignore b/charts/nextcloud-mcp-server/.helmignore deleted file mode 100644 index 0e8a0eb3..00000000 --- a/charts/nextcloud-mcp-server/.helmignore +++ /dev/null @@ -1,23 +0,0 @@ -# Patterns to ignore when building packages. -# This supports shell glob matching, relative path matching, and -# negation (prefixed with !). Only one pattern per line. -.DS_Store -# Common VCS dirs -.git/ -.gitignore -.bzr/ -.bzrignore -.hg/ -.hgignore -.svn/ -# Common backup files -*.swp -*.bak -*.tmp -*.orig -*~ -# Various IDEs -.project -.idea/ -*.tmproj -.vscode/ diff --git a/charts/nextcloud-mcp-server/CHANGELOG.md b/charts/nextcloud-mcp-server/CHANGELOG.md deleted file mode 100644 index 8f8f3a54..00000000 --- a/charts/nextcloud-mcp-server/CHANGELOG.md +++ /dev/null @@ -1,1353 +0,0 @@ -# Changelog - Helm Chart - -All notable changes to the Helm chart will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - - -### Added -- Initial independent versioning release -- Support for Nextcloud MCP server deployment -- Qdrant subchart integration -- Ollama subchart integration -- Configurable resource limits -- Grafana dashboard annotations - -## nextcloud-mcp-server-0.58.31 (2026-04-07) - -### Refactor - -- change OAuth scope separator from colon to dot for IDP compatibility - -## nextcloud-mcp-server-0.58.30 (2026-04-07) - -## nextcloud-mcp-server-0.58.29 (2026-04-07) - -## nextcloud-mcp-server-0.58.28 (2026-04-05) - -### Fix - -- address PR review feedback for client registry and DCR proxy -- support cloud OAuth clients and graceful DCR fallback - -### Refactor - -- remove ALLOWED_MCP_CLOUD_CLIENTS and add keycloak CI profile -- consolidate ALLOWED_MCP_CLIENTS and add redirect URI validation - -## nextcloud-mcp-server-0.58.27 (2026-04-05) - -## nextcloud-mcp-server-0.58.26 (2026-04-04) - -### Fix - -- address PR review — remove token exchange tests, improve logging -- address PR review — stale mcp-oauth refs, Playwright TimeoutError catch -- update expected auth tools list for login-flow scope test - -### Refactor - -- remove RFC 8693 token exchange and Keycloak OAuth implementation -- remove oauth profile, migrate MCP/OAuth tests to login-flow - -## nextcloud-mcp-server-0.58.25 (2026-04-03) - -## nextcloud-mcp-server-0.58.24 (2026-04-02) - -## nextcloud-mcp-server-0.58.23 (2026-04-01) - -### Fix - -- convert BDAY datetime.date to string before Pydantic validation - -## nextcloud-mcp-server-0.58.22 (2026-04-01) - -## nextcloud-mcp-server-0.58.21 (2026-03-31) - -## nextcloud-mcp-server-0.58.20 (2026-03-31) - -### Feat - -- add web-based Login Flow v2 provisioning endpoint - -### Fix - -- require bearer token on provision endpoints (open redirect mitigation) -- address PR review round 3 — info disclosure, conditional routes, cleanup -- address PR review round 2 — expiry checks, race guards, poll tests -- address PR review — XSS escape, asyncio→anyio, URL rewrite dedup -- use app password auth for background sync in Login Flow mode -- discover Login Flow v2 users in OAuth mode user manager -- rewrite Login Flow v2 poll endpoint URL to use configured host -- handle internal hostname without port in Login Flow v2 URL rewriting - -### Refactor - -- use redirect-based Login Flow v2 provision instead of popup - -## nextcloud-mcp-server-0.58.19 (2026-03-31) - -## nextcloud-mcp-server-0.58.18 (2026-03-29) - -### Feat - -- add Tailscale Funnel config for Claude AI connector testing - -## nextcloud-mcp-server-0.58.17 (2026-03-29) - -### Fix - -- allow HTTPS redirect URIs for non-localhost OAuth clients -- move Astrolabe OAuth hook to before-starting for reliable OIDC client creation -- resolve OAuth compatibility issues for login-flow deployment - -## nextcloud-mcp-server-0.58.16 (2026-03-28) - -## nextcloud-mcp-server-0.58.15 (2026-03-28) - -### Fix - -- pin Renovate Nextcloud updates to matching major version - -## nextcloud-mcp-server-0.58.14 (2026-03-28) - -## nextcloud-mcp-server-0.58.13 (2026-03-28) - -## nextcloud-mcp-server-0.58.12 (2026-03-28) - -### Feat - -- add Nextcloud Collectives app support (#621) - -### Fix - -- address PR review feedback (round 9) -- address PR review feedback (round 8) -- address PR review feedback (round 7) and fix CI -- address PR review feedback (round 6) -- address PR review feedback (round 5) -- add trash/delete collective tools and address review feedback (round 4) -- address PR review feedback (round 3) -- address PR review feedback (round 2) -- correct tool annotations to match ADR-017 conventions -- address PR review feedback for Collectives support - -## nextcloud-mcp-server-0.58.11 (2026-03-27) - -### Fix - -- pin starlette<1.0 to prevent startup crash (#648) - -## nextcloud-mcp-server-0.58.10 (2026-03-27) - -## nextcloud-mcp-server-0.58.9 (2026-03-26) - -## nextcloud-mcp-server-0.58.8 (2026-03-23) - -## nextcloud-mcp-server-0.58.7 (2026-03-22) - -### Refactor - -- remove Smithery deployment mode - -## nextcloud-mcp-server-0.58.6 (2026-03-22) - -### Fix - -- increase vector sync wait timeout to prevent sampling test timeouts in CI -- reduce vector sync scan interval to 5s for single-user service -- expose public status endpoints in all modes and enable vector sync (#637) - -## nextcloud-mcp-server-0.58.5 (2026-03-22) - -## nextcloud-mcp-server-0.58.4 (2026-03-21) - -### Fix - -- resolve OIDC consent flow 500 errors on NC 32 -- address PR #632 review comments -- **ci**: build OIDC app for all test modes including single-user -- patch OIDC consent flow regression and add CI build step -- **caldav**: address PR #632 review feedback -- **caldav**: migrate to upstream caldav v3.0.1 to fix href handling (#629) - -## nextcloud-mcp-server-0.58.3 (2026-03-16) - -## nextcloud-mcp-server-0.58.2 (2026-03-14) - -## nextcloud-mcp-server-0.58.1 (2026-03-03) - -## nextcloud-mcp-server-0.58.0 (2026-03-03) - -### Feat - -- **auth**: implement OAuth AS proxy to fix audience mismatch (ADR-023) -- **ci**: add Nextcloud version matrix (NC 31, 32, 33) -- **helm**: add login-flow auth mode to Helm chart (ADR-022) -- add Docker Compose profiles and Login Flow v2 service - -### Fix - -- replace assert with proper guard and invalidate scope cache after provisioning -- disable NC rate limiting in dev/CI and add token endpoint diagnostics -- address review feedback — security, caching, CI 429 retry -- skip keycloak hook when profile inactive and update stale PRM test -- address remaining PR #589 review findings -- address PR #589 review findings -- address PR review issues for Login Flow v2 -- address PR #589 review feedback (round 2) -- **ci**: remove dev OIDC mount to fix HTTP 500 in single-user/multi-user-basic -- **ci**: fix health check timeout and per-profile MCP server URL routing -- **ci**: fix PHP gating, add multi-user-basic matrix entry, upload debug artifacts -- address PR #589 review feedback for Login Flow v2 -- **ci**: fix integration test collection and skip Playwright in CI -- **test**: fix 17 pre-existing unit test failures and add astrolabe CI build -- **ci**: keep third_party mount, always build submodules in CI -- **ci**: revert accidental third_party mount, use compose override for OIDC -- **ci**: don't block integration matrix on unit-test failures - -## nextcloud-mcp-server-0.57.94 (2026-03-03) - -### Fix - -- handle pythonvCard4 dict-format fields and missing phone numbers (#601) - -## nextcloud-mcp-server-0.57.93 (2026-03-03) - -## nextcloud-mcp-server-0.57.92 (2026-03-02) - -## nextcloud-mcp-server-0.57.91 (2026-03-02) - -## nextcloud-mcp-server-0.57.90 (2026-03-01) - -## nextcloud-mcp-server-0.57.89 (2026-03-01) - -## nextcloud-mcp-server-0.57.88 (2026-03-01) - -## nextcloud-mcp-server-0.57.87 (2026-03-01) - -## nextcloud-mcp-server-0.57.86 (2026-02-26) - -### Fix - -- **deps**: update dependency icalendar to v7 - -## nextcloud-mcp-server-0.57.85 (2026-02-25) - -## nextcloud-mcp-server-0.57.84 (2026-02-25) - -## nextcloud-mcp-server-0.57.83 (2026-02-25) - -## nextcloud-mcp-server-0.57.82 (2026-02-25) - -## nextcloud-mcp-server-0.57.81 (2026-02-25) - -## nextcloud-mcp-server-0.57.80 (2026-02-24) - -## nextcloud-mcp-server-0.57.79 (2026-02-24) - -## nextcloud-mcp-server-0.57.78 (2026-02-24) - -## nextcloud-mcp-server-0.57.77 (2026-02-24) - -## nextcloud-mcp-server-0.57.76 (2026-02-24) - -## nextcloud-mcp-server-0.57.75 (2026-02-23) - -## nextcloud-mcp-server-0.57.74 (2026-02-21) - -## nextcloud-mcp-server-0.57.73 (2026-02-21) - -### Fix - -- address PR #574 fourth review round -- address PR #574 third review round -- address PR #574 second review round -- address PR #574 review comments -- wrap raw list returns in response models to produce single TextContent block - -## nextcloud-mcp-server-0.57.72 (2026-02-20) - -## nextcloud-mcp-server-0.57.71 (2026-02-20) - -## nextcloud-mcp-server-0.57.70 (2026-02-20) - -### Fix - -- address PR #571 review comments -- resolve stale credentials causing astrolabe background sync test failures - -### Refactor - -- enforce PLC0415 (import-outside-top-level) for source code - -## nextcloud-mcp-server-0.57.69 (2026-02-20) - -## nextcloud-mcp-server-0.57.68 (2026-02-19) - -## nextcloud-mcp-server-0.57.67 (2026-02-19) - -## nextcloud-mcp-server-0.57.66 (2026-02-18) - -## nextcloud-mcp-server-0.57.65 (2026-02-18) - -## nextcloud-mcp-server-0.57.64 (2026-02-18) - -## nextcloud-mcp-server-0.57.63 (2026-02-18) - -## nextcloud-mcp-server-0.57.62 (2026-02-18) - -### Fix - -- **deps**: update dependency mcp to >=1.26,<1.27 - -## nextcloud-mcp-server-0.57.61 (2026-02-18) - -## nextcloud-mcp-server-0.57.60 (2026-02-18) - -## nextcloud-mcp-server-0.57.59 (2026-02-18) - -## nextcloud-mcp-server-0.57.58 (2026-02-18) - -## nextcloud-mcp-server-0.57.57 (2026-02-18) - -## nextcloud-mcp-server-0.57.56 (2026-02-18) - -## nextcloud-mcp-server-0.57.55 (2026-02-17) - -## nextcloud-mcp-server-0.57.54 (2026-02-17) - -## nextcloud-mcp-server-0.57.53 (2026-02-17) - -## nextcloud-mcp-server-0.57.52 (2026-02-17) - -## nextcloud-mcp-server-0.57.51 (2026-02-16) - -### Feat - -- add self-signed SSL certificate support for Nextcloud connections - -### Fix - -- add type: ignore for caldav ssl_verify_cert parameter -- convert CA bundle path to ssl.SSLContext to avoid httpx deprecation warning - -## nextcloud-mcp-server-0.57.50 (2026-02-16) - -## nextcloud-mcp-server-0.57.49 (2026-02-16) - -### Refactor - -- remove stale astrolabe references from commitizen config -- extract Astrolabe to separate repository - -## nextcloud-mcp-server-0.57.48 (2026-02-15) - -## nextcloud-mcp-server-0.57.47 (2026-02-15) - -## nextcloud-mcp-server-0.57.46 (2026-02-12) - -## nextcloud-mcp-server-0.57.45 (2026-02-12) - -## nextcloud-mcp-server-0.57.44 (2026-02-11) - -## nextcloud-mcp-server-0.57.43 (2026-02-11) - -## nextcloud-mcp-server-0.57.42 (2026-02-08) - -### Fix - -- strip whitespace from category names when splitting -- handle categories, recurrence_rule, attendees, and reminder_minutes in update_event - -## nextcloud-mcp-server-0.57.41 (2026-02-08) - -### Fix - -- expand recurring events in date-range queries - -## nextcloud-mcp-server-0.57.40 (2026-02-07) - -### Fix - -- use CalDAV time-range filter for calendar date range queries - -## 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.25 (2026-01-31) - -## nextcloud-mcp-server-0.57.24 (2026-01-31) - -## nextcloud-mcp-server-0.57.23 (2026-01-30) - -## nextcloud-mcp-server-0.57.22 (2026-01-30) - -## nextcloud-mcp-server-0.57.21 (2026-01-30) - -## nextcloud-mcp-server-0.57.20 (2026-01-29) - -## nextcloud-mcp-server-0.57.19 (2026-01-28) - -## nextcloud-mcp-server-0.57.18 (2026-01-28) - -## nextcloud-mcp-server-0.57.17 (2026-01-28) - -## nextcloud-mcp-server-0.57.16 (2026-01-28) - -### Feat - -- **astrolabe**: add background token refresh job - -### Fix - -- **astrolabe**: add pagination and psalm fixes for token refresh -- **astrolabe**: add locking to prevent token refresh race condition -- **astrolabe**: add issued_at to on-demand token refresh - -## nextcloud-mcp-server-0.57.15 (2026-01-26) - -### Feat - -- **scripts**: add database query helpers for development - -### Fix - -- **astrolabe**: resolve Psalm type errors in PDF preview code -- **astrolabe**: fix Psalm baseline and ESLint import order -- **astrolabe**: load pdfjs-dist externally to fix PDF viewer -- **astrolabe**: improve error messages for authorization issues -- **astrolabe**: rename OAuthController and fix app password check -- **tests**: improve Astrolabe integration test reliability -- **astrolabe**: update Plotly title attributes for v3 compatibility -- **deps**: update dependency plotly.js-dist-min to v3 - -### Refactor - -- **api**: split management.py into domain-focused modules -- **astrolabe**: replace client-side PDF.js with server-side PyMuPDF rendering - -## nextcloud-mcp-server-0.57.14 (2026-01-26) - -## nextcloud-mcp-server-0.57.13 (2026-01-24) - -## nextcloud-mcp-server-0.57.12 (2026-01-20) - -## nextcloud-mcp-server-0.57.11 (2026-01-20) - -## nextcloud-mcp-server-0.57.10 (2026-01-19) - -## nextcloud-mcp-server-0.57.9 (2026-01-19) - -## nextcloud-mcp-server-0.57.8 (2026-01-18) - -## nextcloud-mcp-server-0.57.7 (2026-01-17) - -### Fix - -- **astrolabe**: improve token refresh error handling and validation -- **astrolabe**: delete stale tokens when refresh fails -- **astrolabe**: resolve CI failures for code quality checks -- **astrolabe**: use internal URL for OAuth token refresh - -### Refactor - -- **astrolabe**: add PHP property types to fix Psalm errors -- **astrolabe**: upgrade to @nextcloud/vue 9.3.3 API - -## nextcloud-mcp-server-0.57.6 (2026-01-16) - -## nextcloud-mcp-server-0.57.5 (2026-01-16) - -## nextcloud-mcp-server-0.57.4 (2026-01-16) - -### Fix - -- **astrolabe**: Address reviewer feedback for hybrid mode -- **astrolabe**: Fix NcSelect options and CSS loading -- **astrolabe**: fix OAuth flow and settings UI for hybrid mode -- **api**: return OIDC config in hybrid mode for Astrolabe OAuth flow - -## nextcloud-mcp-server-0.57.3 (2026-01-15) - -## nextcloud-mcp-server-0.57.2 (2026-01-15) - -### Fix - -- **astrolabe**: address review feedback for Vue 3 bindings -- **astrolabe**: update Vue component bindings for Vue 3 compatibility - -## nextcloud-mcp-server-0.57.1 (2026-01-15) - -### Fix - -- **ci**: bump helm chart version when MCP appVersion changes -- **astrolabe**: define appName and appVersion for @nextcloud/vue - -## nextcloud-mcp-server-0.57.0 (2026-01-15) - -### Feat - -- Add rate limiting and extract helpers for app password endpoints - -### Fix - -- Add missing annotations for deck remove/unassign operations -- **auth**: Store app passwords locally for multi-user BasicAuth background sync -- **deck**: use correct endpoint for reorder_card to fix cross-stack moves -- **deck**: Always preserve fields in update_card for partial updates -- **astrolabe**: Fix CSS loading for Nextcloud apps -- **astrolabe**: Fix revoke access button HTTP method mismatch - -### Refactor - -- Use get_settings() for vector sync enabled check -- Extract storage helper and improve PHP error handling - -## nextcloud-mcp-server-0.56.2 (2025-12-29) - -### Fix - -- **oauth**: Enable browser OAuth routes for Management API in hybrid mode - -## nextcloud-mcp-server-0.56.1 (2025-12-26) - -### Fix - -- **mcp**: Move all imports to the top of modules - -## nextcloud-mcp-server-0.56.0 (2025-12-26) - -### Feat - -- Remove URL rewriting in favor of proper nextcloud config -- **helm**: migrate to new environment variable naming convention -- Migrate to vue 3 -- **astrolabe**: upgrade to Vue 3 and @nextcloud/vue 9 - -### Fix - -- **tests**: Add singleton reset fixture to prevent anyio.WouldBlock errors -- **tests**: Fix integration test failures in qdrant, sampling, and rag tests -- **auth**: Skip issuer validation for management API tokens -- Use settings.enable_offline_access for env var consolidation -- Add required config.py attributes -- **docker**: remove overwritehost to fix container-to-container DCR -- **deps**: update dependency @nextcloud/vue to v9 -- **deps**: update dependency vue to v3 - -### Refactor - -- **auth**: Decouple BasicAuth and OAuth authentication strategies - -## nextcloud-mcp-server-0.55.2 (2025-12-22) - -### Fix - -- **helm**: set OIDC client env vars when using existingSecret - -## nextcloud-mcp-server-0.55.1 (2025-12-22) - -### Fix - -- **helm**: trigger chart release workflow on helm chart tags - -## nextcloud-mcp-server-0.55.0 (2025-12-22) - -### BREAKING CHANGE - -- MCP server now bumps for ANY conventional commit except -those explicitly scoped to helm or astrolabe. - -### Feat - -- **helm**: add support for multi-user BasicAuth mode -- **config**: enable DCR for multi-user BasicAuth with offline access -- **astrolabe**: implement app password provisioning for multi-user background sync -- **config**: consolidate configuration with smart dependency resolution (ADR-021) -- **auth**: add multi-user BasicAuth pass-through mode -- **astrolabe**: add dynamic MCP server configuration for testing -- **ci**: add --increment flag to bump scripts for manual version control - -### Fix - -- **helm**: address PR #447 reviewer feedback -- **helm**: include MCP server version bumps in changelog pattern -- **config**: address reviewer feedback -- **astrolabe**: screenshots in info.xml -- **astrolabe**: screenshots in info.xml -- **astrolabe**: Update screenshots -- **ci**: skip existing Helm chart releases to prevent duplicate release errors -- **astrolabe**: add contents:write permission to appstore workflow -- **astrolabe**: update commitizen pattern to properly update info.xml version -- **astrolabe**: prevent workflow failure when only helm/astrolabe commits exist -- **astrolabe**: info.xml -- **ci**: push all tags explicitly in bump workflow -- **ci**: make MCP server default bump target for all non-scoped commits -- **ci**: restrict docker build to MCP server tags only -- **ci**: correct appstore-push-action version to v1.0.4 - -### Refactor - -- **config**: centralize configuration validation and simplify startup - -## nextcloud-mcp-server-0.54.0 (2025-12-19) - -### Feat - -- **ci**: implement monorepo-aware version bumping workflow -- **astrolabe**: add Nextcloud App Store deployment automation -- configure commitizen monorepo with independent versioning - -### Fix - -- **ci**: improve versioning and error handling -- **ci**: address critical workflow and validation issues -- **astrolabe**: address code review feedback - -## nextcloud-mcp-server-0.53.0 (2025-12-19) - -### Feat - -- add Alembic database migration system -- make chunk modal title clickable link to documents -- add native Plotly hover styling for clickable points -- add click interactivity to Plotly 3D scatter chart -- improve chunk viewer with fixed navigation and markdown rendering -- **astrolabe**: enable multi-select for document types and refactor PDF viewer -- **auth**: implement refresh token rotation for Nextcloud OIDC -- **astrolabe**: enhance unified search and add webhook management -- **astrolabe**: add webhook management UI to admin settings -- **astrolabe**: add OAuth token refresh and webhook presets -- **search**: add file_path metadata and chunk offsets to search results -- **astrolabe**: use proper icons and thumbnails in unified search -- **astrolabe**: add admin search settings and enhanced UI -- **astrolabe**: add unified search provider with clickable file links -- **astrolabe**: add 3D PCA visualization for semantic search -- **astrolabe**: add Nextcloud PHP app for MCP server management -- **vector-sync**: enable background sync in OAuth mode - -### Fix - -- **security**: address critical security issues from PR #401 code review -- **oauth**: enable PKCE for all clients and add token_broker to oauth_context -- **astrolabe**: revert invalid files_pdfviewer URL for file links -- resolve type checking warnings for CI -- move Alembic to package submodule for Docker compatibility -- update unified search results to match chunk viz display -- **astrolabe**: handle OAuth refresh token rotation -- address critical code review issues (4 fixes) -- resolve CI linting issues for Astroglobe - -### Refactor - -- **astrolabe**: extract PDF viewer to dedicated component -- **astrolabe**: reframe UI as semantic search service - -## nextcloud-mcp-server-0.52.1 (2025-12-13) - -## nextcloud-mcp-server-0.52.0 (2025-12-13) - -## nextcloud-mcp-server-0.51.0 (2025-12-13) - -### Feat - -- **vector**: add Deck card vector search with visualization support -- **vector-viz**: add news_item support for links and chunk expansion - -### Perf - -- **deck**: optimize card lookup by storing board_id/stack_id in metadata - -## nextcloud-mcp-server-0.50.2 (2025-12-13) - -### Fix - -- **news**: revert get_item() to use get_items() + filter - -## nextcloud-mcp-server-0.50.1 (2025-12-12) - -### Fix - -- Disable DNS rebinding protection for containerized deployments -- **deps**: update dependency mcp to >=1.23,<1.24 - -## nextcloud-mcp-server-0.50.0 (2025-12-11) - -### Feat - -- add MCP tool annotations for enhanced UX - -### Fix - -- address PR review feedback - -## nextcloud-mcp-server-0.49.2 (2025-12-09) - -### Fix - -- Update lockfile - -## nextcloud-mcp-server-0.49.1 (2025-12-09) - -### Fix - -- Revert mcp version <1.23 - -## nextcloud-mcp-server-0.49.0 (2025-12-08) - -### Fix - -- resolve all type checking errors (8 errors fixed) -- **deps**: update dependency mcp to >=1.23,<1.24 - -### Perf - -- **news**: use direct API endpoint for get_item() - -## nextcloud-mcp-server-0.48.5 (2025-11-28) - -### Feat - -- **news**: add Nextcloud News app integration - -### Fix - -- **deps**: update dependency pillow to v12 - -### Refactor - -- **news**: simplify vector sync to fetch all items - -## nextcloud-mcp-server-0.48.4 (2025-11-23) - -### Fix - -- Add rate limit retry logic to OpenAI provider - -## nextcloud-mcp-server-0.48.3 (2025-11-23) - -### Fix - -- Increase MCP sampling timeout to 5 minutes for slower LLMs - -## nextcloud-mcp-server-0.48.2 (2025-11-23) - -### Fix - -- Share vector sync state with FastMCP session lifespan via module singleton - -## nextcloud-mcp-server-0.48.1 (2025-11-23) - -## nextcloud-mcp-server-0.48.0 (2025-11-23) - -## nextcloud-mcp-server-0.47.0 (2025-11-23) - -### Feat - -- Add tag management methods to WebDAV client -- Add OpenAI provider support for embeddings and generation - -### Fix - -- Share vector sync state with FastMCP session lifespan via module singleton -- Use WebDAV for tag creation and add LLM-as-a-judge for RAG tests - -### Refactor - -- Move background tasks to server lifespan and deprecate SSE transport - -## nextcloud-mcp-server-0.46.2 (2025-11-22) - -### Fix - -- **smithery**: Enable JSON response format for scanner compatibility - -## nextcloud-mcp-server-0.46.1 (2025-11-22) - -### Perf - -- Optimize vector viz search performance - -## nextcloud-mcp-server-0.46.0 (2025-11-22) - -### Feat - -- Add Smithery CLI deployment support -- Implement ADR-016 Smithery stateless deployment mode - -### Fix - -- **smithery**: Add JSON Schema metadata to mcp-config endpoint -- **smithery**: Use container runtime pattern for config discovery -- Add Smithery lifespan and auth mode detection - -## nextcloud-mcp-server-0.45.0 (2025-11-22) - -### Feat - -- Add context expansion to semantic search with chunk overlap removal -- Use Ollama native batch API in embed_batch() -- Implement Qdrant placeholder state management -- Switch files to use numeric IDs with file_path resolution -- Implement per-chunk vector visualization with context expansion - -### Fix - -- Use alpha_composite for proper RGBA highlight blending -- Remove pymupdf.layout.activate() to fix page_chunks behavior -- Centralize PDF processing and generate separate images per chunk -- Set is_placeholder=False in processor to fix search filtering -- Increase placeholder staleness threshold to 5x scan interval -- Add placeholder staleness check to prevent duplicate processing -- Use empty SparseVector instead of None for placeholders -- Return empty array instead of null for query_coords when no results -- Align PDF text extraction between indexing and context expansion -- Update models and viz to use int-only doc_id -- Reconstruct full content for notes to match indexed offsets -- Add async/await, PDF metadata, and type safety fixes - -### Refactor - -- Simplify PDF text extraction with single to_markdown call - -### Perf - -- Optimize PDF processing with parallel extraction and single-render highlights - -## nextcloud-mcp-server-0.44.1 (2025-11-21) - -### Fix - -- **deps**: update dependency mcp to >=1.22,<1.23 - -## nextcloud-mcp-server-0.44.0 (2025-11-19) - -### Feat - -- Improve vector visualization with static assets and fixes -- Redesign UI to match Nextcloud ecosystem aesthetic - -### Fix - -- Improve 3D plot rendering with explicit dimensions and window resize support -- Preserve 3D plot camera and improve documentation -- Preserve 3D plot camera position and fix CSS loading - -## nextcloud-mcp-server-0.43.0 (2025-11-18) - -### Feat - -- Replace custom document chunker with LangChain MarkdownTextSplitter - -## nextcloud-mcp-server-0.42.0 (2025-11-17) - -### Feat - -- **viz**: Add dual-score display and improve UI controls - -## nextcloud-mcp-server-0.41.0 (2025-11-17) - -### Feat - -- add configurable fusion algorithms for BM25 hybrid search -- add chunk position tracking to vector indexing and search -- add vector viz template and chunk context endpoint - -### Fix - -- prevent infinite loop in DocumentChunker with position tracking -- Relax SearchResult validation to support DBSF fusion scores > 1.0 - -## nextcloud-mcp-server-0.40.0 (2025-11-16) - -### Feat - -- add unified provider architecture with Amazon Bedrock support - -### Fix - -- suppress Starlette middleware type warnings in ty checker - -## nextcloud-mcp-server-0.39.0 (2025-11-16) - -## nextcloud-mcp-server-0.38.0 (2025-11-16) - -### Feat - -- add concurrent uploads and --force flag to upload command -- implement RAG evaluation framework with CLI tooling -- Add OpenTelemetry tracing to @instrument_tool decorator -- Implement BM25 hybrid search with native Qdrant RRF fusion - -### Fix - -- download qrels from BEIR ZIP instead of HuggingFace -- Handle named vectors in visualization and semantic search -- Update vizApp to use bm25_hybrid algorithm and remove deprecated weights -- Update viz routes to use BM25 hybrid search after refactor - -### Refactor - -- migrate asyncio to anyio for consistent structured concurrency -- replace httpx client with NextcloudClient in upload command - -### Perf - -- Eliminate double-fetching in semantic search sampling -- fix vector viz search performance and visual encoding -- make note deletion concurrent in upload --force - -## nextcloud-mcp-server-0.36.0 (2025-11-15) - -### BREAKING CHANGE - -- Search algorithms now require Qdrant to be populated. -Vector sync must be enabled and documents indexed for search to work. - -### Feat - -- Normalize hybrid search RRF scores to 0-1 range -- Enhance vector visualization UI and parallelize search verification -- Add Vector Viz tab to app home page -- Add vector visualization pane with multi-select document types -- Implement custom PCA to remove sklearn dependency -- Add multi-document Protocol with cross-app search support -- Update nc_semantic_search tool with algorithm selection -- Implement unified search algorithm module - -### Fix - -- Reorder tabs and fix viz pane session access - -### Refactor - -- Optimize Nextcloud access verification with centralized filtering -- Make all search algorithms query Qdrant payload, not Nextcloud - -### Perf - -- Exclude vector-sync status polling from distributed tracing - -## nextcloud-mcp-server-0.35.0 (2025-11-15) - -### Feat - -- Enable SSE transport for mcp service and update test fixtures - -## nextcloud-mcp-server-0.34.2 (2025-11-13) - -### Fix - -- Use NEXTCLOUD_OIDC_CLIENT_ID/SECRET env vars consistently -- return all notes when search query is empty - -## nextcloud-mcp-server-0.34.0 (2025-11-13) - -### Feat - -- Complete Phase 5 - Instrument all 93 MCP tools -- Add instrumentation decorator and apply to notes tools (Phase 5) -- Add OAuth token and database metrics (Phases 3-4) -- Add metrics instrumentation for queue, health, and database operations - -## nextcloud-mcp-server-0.33.1 (2025-11-13) - -### Fix - -- Move grafana_folder from labels to annotations - -## nextcloud-mcp-server-0.33.0 (2025-11-13) - -### Feat - -- Add Grafana dashboard and vector sync metric instrumentation - -## nextcloud-mcp-server-0.32.1 (2025-11-12) - -### Fix - -- add dynamic dimension detection for Ollama embedding models - -## nextcloud-mcp-server-0.32.0 (2025-11-11) - -### Feat - -- **ollama**: Pull model on startup if not available in ollama -- add dynamic vector sync status updates with htmx polling -- add webhook management UI and BeforeNodeDeletedEvent support -- validate Nextcloud webhook schemas and document findings - -### Fix - -- improve webapp tab UI with CSS Grid and viewport-filling container - -### Refactor - -- move webapp from /user/page to /app -- consolidate database storage for webhooks and OAuth tokens - -## nextcloud-mcp-server-0.31.1 (2025-11-10) - -### Refactor - -- simplify OpenTelemetry tracing configuration - -## nextcloud-mcp-server-0.31.0 (2025-11-10) - -### Feat - -- skip tracing for health and metrics endpoints - -### Fix - -- add retry logic for ETag conflicts in category change test -- optimize Notes API pagination with pruneBefore parameter - -## nextcloud-mcp-server-0.30.0 (2025-11-10) - -### Feat - -- **helm**: Add document chunking configuration -- **vector**: Add configurable chunk size and overlap for document embedding -- **vector**: Support multiple embedding models with auto-generated collection names - -### Fix - -- Support in-memory Qdrant for CI testing - -## nextcloud-mcp-server-0.29.2 (2025-11-09) - -### Fix - -- **helm**: Set default strategy to Recreate - -## nextcloud-mcp-server-0.29.1 (2025-11-09) - -### Fix - -- **observability**: isolate metrics endpoint to dedicated port - -## nextcloud-mcp-server-0.29.0 (2025-11-09) - -### Feat - -- **helm**: Add observability support with ServiceMonitor and Grafana dashboard - -### Fix - -- **readiness**: Only check external Qdrant in network mode - -## nextcloud-mcp-server-0.28.0 (2025-11-09) - -### Feat - -- **observability**: Add comprehensive monitoring with Prometheus and OpenTelemetry - -### Fix - -- **vector**: Handle missing 'modified' field in notes gracefully - -## nextcloud-mcp-server-0.27.3 (2025-11-09) - -### Fix - -- **ci**: Use helm dependency build instead of update to use Chart.lock - -## nextcloud-mcp-server-0.27.2 (2025-11-09) - -### Fix - -- **helm**: update Qdrant dependency condition to match new mode structure - -## nextcloud-mcp-server-0.27.1 (2025-11-09) - -### Feat - -- **helm**: add Qdrant local mode support with three deployment options [skip ci] -- add Qdrant local mode support with in-memory and persistent storage -- implement ADR-009 - refactor semantic search to use generic semantic:read scope -- implement MCP sampling for semantic search RAG (ADR-008) -- add optional vector database and semantic search to helm chart -- add vector sync processing status to /user/page endpoint -- implement semantic search tool and fix vector sync issues (ADR-007 Phase 3) -- implement vector sync scanner and processor (ADR-007 Phase 2) - -### Fix - -- **ci**: add Helm repository setup to chart release workflow -- implement deletion grace period and vector sync status tool -- remove unnecessary urllib3<2.0 constraint -- integrate vector sync tasks with Starlette lifespan for streamable-http - -### Refactor - -- migrate vector sync from asyncio.Queue to anyio memory object streams -- update to Qdrant query_points API and fix Playwright Keycloak login - -## nextcloud-mcp-server-0.26.1 (2025-11-08) - -### Fix - -- **deps**: update dependency mcp to >=1.21,<1.22 - -## nextcloud-mcp-server-0.26.0 (2025-11-08) - -### Feat - -- add real elicitation integration test with python-sdk MCP client -- unify session architecture and enhance login status visibility - -### Fix - -- Consolidate OAuth callbacks and implement PKCE for all flows - -## nextcloud-mcp-server-0.25.0 (2025-11-05) - -### BREAKING CHANGE - -- All OAuth deployments must be reconfigured to specify -resource URIs (NEXTCLOUD_MCP_SERVER_URL and NEXTCLOUD_RESOURCE_URI) and -choose between multi-audience or token exchange mode. - -### Feat - -- Implement ADR-005 unified token verifier to eliminate token passthrough vulnerability - -### Fix - -- Implement proper OAuth resource parameters and PRM-based discovery -- Simplify token verifier to be RFC 7519 compliant -- Use Keycloak client ID for NEXTCLOUD_RESOURCE_URI in token exchange -- Correct OAuth token audience validation for multi-audience mode - -### Refactor - -- Eliminate duplicate validation logic in UnifiedTokenVerifier - -## nextcloud-mcp-server-0.24.1 (2025-11-04) - -### Fix - -- **deps**: update dependency mcp to >=1.20,<1.21 - -## nextcloud-mcp-server-0.24.0 (2025-11-04) - -### Feat - -- add scope protection to OAuth provisioning tools -- enable authorization services for token exchange in Keycloak -- implement scope-based audience mapping and RFC 9728 support -- integrate token exchange into MCP server application -- implement RFC 8693 Standard Token Exchange for Keycloak -- Add userinfo route/page -- add browser-based user info page with separate OAuth flow -- Implement ADR-004 Progressive Consent foundation (partial) -- Complete ADR-004 Progressive Consent OAuth flows implementation -- Implement ADR-004 Progressive Consent foundation components -- Implement ADR-004 Hybrid Flow with comprehensive integration tests - -### Fix - -- add missing await for get_nextcloud_client in capabilities resource -- use valid Fernet encryption keys in token exchange tests -- accept resource URL in token audience for Nextcloud JWT tokens -- remove token-exchange-nextcloud scope and accept tokens without audience -- move audience mapper from scope to nextcloud-mcp-server client -- move token-exchange-nextcloud from default to optional scopes -- restructure routes to prevent SessionAuthBackend from interfering with FastMCP OAuth -- allow OAuth Bearer tokens on /mcp endpoint by excluding from session auth -- correct OAuth token audience validation using RFC 8707 resource parameter -- remove remaining references to deleted oauth_callback and oauth_token -- remove Hybrid Flow, make Progressive Consent default (ADR-004) -- browser OAuth userinfo endpoint and refresh token rotation -- make ENABLE_PROGRESSIVE_CONSENT consistently opt-in (default false) -- make provisioning checks opt-in (default false) -- Disable Progressive Consent for mcp-oauth to enable Hybrid Flow tests - -### Refactor - -- integrate token exchange into unified get_client() pattern - -## nextcloud-mcp-server-0.23.0 (2025-11-03) - -### Feat - -- Auto-configure impersonation role in Keycloak realm import -- Implement dual-tier token exchange (Standard V2 + Legacy V1 impersonation) -- Add Keycloak external IdP integration with custom scopes -- Implement RFC 8693 token exchange for Keycloak (ADR-002 Tier 2) -- Add Keycloak OAuth provider support with refresh token storage - -### Fix - -- Complete Keycloak external IdP integration with all tests passing -- Complete Keycloak external IdP integration with all tests passing -- Update DCR token_type tests for OIDC app changes - -### Refactor - -- Remove NEXTCLOUD_OIDC_CLIENT_STORAGE environment variable -- Remove unnecessary user_oidc patch - CORSMiddleware patch is sufficient -- Unify OAuth configuration to be provider-agnostic - -## nextcloud-mcp-server-0.22.7 (2025-10-29) - -### Fix - -- **helm**: Remove image tag overide - -## nextcloud-mcp-server-0.22.6 (2025-10-29) - -### Fix - -- **helm**: Update helm chart with extraArgs - -## nextcloud-mcp-server-0.22.5 (2025-10-29) - -### Fix - -- Update helm chart variables - -## nextcloud-mcp-server-0.22.4 (2025-10-29) - -### Fix - -- **helm**: Update helm version with release -- **helm**: Update helm version with release -- **helm**: Update helm version with release - -## nextcloud-mcp-server-0.1.1 (2025-10-29) - -### Fix - -- **helm**: Update helm version with release -- Trigger release - -## nextcloud-mcp-server-0.1.0 (2025-10-29) - -### BREAKING CHANGE - -- FASTMCP_-prefixed env vars have been replaced by CLI -arguments. Refer to the README for updated usage. - -### Feat - -- **server**: Add /live & /health endpoints -- Initialize helm chart -- Add text processing background worker for telling client about progress -- **auth**: Add support for client registration deletion -- Split read/write scopes into app:read/write scopes -- Enable token introspection for opaque tokens -- **server**: Add support for custom OIDC scopes and permissions via JWTs -- Initialize JWT-scoped tools -- **caldav**: Add support for tasks -- **webdav**: Add search and list favorite response tools -- **cookbook**: Add full Cookbook app support with 13 tools and 2 resources -- Add Groups API client -- add sharing API client and server tools -- **server**: Experimental support for OAuth2/OIDC authentication -- **users**: Initialize user API client -- **server**: Add support for `streamable-http` transport type -- Add WebDAV resource copy functionality -- Add WebDAV resource move/rename functionality -- **deck**: Add support for stack, cards, labels -- **deck**: Initialize Deck app client/server -- **cli**: Replace `mcp run` with click CLI and runtime options -- **client**: Preserve fields when modifying contacts/calendar resources -- **server**: Add structured output to all tool/resource output -- **contacts**: Initialize Contacts App -- **calendar**: add comprehensive Calendar app support via CalDAV protocol -- Update webdav client create_directory method to handle recursive directories -- **webdav**: add complete file system support -- Add TablesClient and associated tools -- Switch to using async client -- **notes**: Add append to note functionality - -### Fix - -- Add support for RFC 7592 client registration and deletion -- Update webdav models for proper serialization -- **deps**: update dependency mcp to >=1.19,<1.20 -- Add CORS middleware to allow browser-based clients like MCP Inspector -- Use occ-created OAuth clients with allowed_scopes for all tests -- Separate OAuth fixtures for opaque vs JWT tokens -- **caldav**: Fix caldav search() due to missing todos -- **caldav**: Check that calendar exists after creation to avoid race condition -- **caldav**: Properly parse datetimes as vDDDTypes -- Increase HTTP client timeout to 30s -- Handle RequestError in mcp tools -- **deps**: update dependency mcp to >=1.18,<1.19 -- **deps**: update dependency pillow to v12 -- **oauth**: Remove the option to force_register new clients -- Update user/groups API to OCS v2 -- **deps**: update dependency mcp to >=1.17,<1.18 -- **deps**: update dependency mcp to >=1.16,<1.17 -- **deps**: update dependency mcp to >=1.15,<1.16 -- **docker**: Provide --host 0.0.0.0 in default docker image -- **deps**: update dependency mcp to >=1.13,<1.14 -- **server**: Replace ErrorResponses with standard McpErrors -- **notes**: Include ETags in responses to avoid accidently updates -- **notes**: Remove note contents from responses to reduce token usage -- **model**: Serialize timestamps in RFC3339 format -- **client**: Use paging to fetch all notes -- **client**: Strip cookies from responses to avoid falsely raising CSRF errors -- **calendar**: Fix iCalendar date vs datetime format -- **calendar**: Remove try/except in calendar API -- apply ruff formatting to pass CI checks -- **calendar**: address PR feedback from maintainer -- apply ruff formatting to test_webdav_operations.py -- **deps**: update dependency mcp to >=1.10,<1.11 -- update tests -- Commitizen release process -- Do not update dependencies when running in Dockerfile -- Configure logging -- Limit search results to notes with score > 0.5 -- Install deps before checking service -- **deps**: update dependency mcp to >=1.9,<1.10 - -### Refactor - -- Transform document parsing into pluggable processor architecture -- Update JWT client to use DCR, re-enable tool filtering -- Migrate from internal CalendarClient to caldav library -- Unify logging & remove factory deployment -- Add tools for all resources to enable tool-only workflows -- Add `http` to --transport option -- Use _make_request where available -- **calendar**: optimize logging for production readiness -- Modularize NC and Notes app client - -### Perf - -- **notes**: Improve notes search performance using async iterators diff --git a/charts/nextcloud-mcp-server/Chart.lock b/charts/nextcloud-mcp-server/Chart.lock deleted file mode 100644 index b9f46eb4..00000000 --- a/charts/nextcloud-mcp-server/Chart.lock +++ /dev/null @@ -1,9 +0,0 @@ -dependencies: -- name: qdrant - repository: https://qdrant.github.io/qdrant-helm - version: 1.17.1 -- name: ollama - repository: https://otwld.github.io/ollama-helm - version: 1.47.0 -digest: sha256:92b4741d6c8c9ef2303d179074335952e2867b8e2ace8ab74f2ab912e06f5d1c -generated: "2026-03-27T15:36:24.829508269Z" diff --git a/charts/nextcloud-mcp-server/Chart.yaml b/charts/nextcloud-mcp-server/Chart.yaml deleted file mode 100644 index 715289e7..00000000 --- a/charts/nextcloud-mcp-server/Chart.yaml +++ /dev/null @@ -1,45 +0,0 @@ -apiVersion: v2 -name: nextcloud-mcp-server -description: A Helm chart for Nextcloud MCP Server - enables AI assistants to interact with Nextcloud -type: application -version: 0.58.31 -appVersion: "0.68.4" -keywords: - - nextcloud - - mcp - - model-context-protocol - - llm - - ai - - claude - - webdav - - caldav - - carddav -maintainers: - - name: Chris Coutinho - email: chris@coutinho.io -home: https://github.com/cbcoutinho/nextcloud-mcp-server -sources: - - https://github.com/cbcoutinho/nextcloud-mcp-server -icon: https://raw.githubusercontent.com/nextcloud/server/master/core/img/logo/logo.svg -annotations: - # Grafana dashboard support - grafana_dashboard: "true" - grafana_dashboard_folder: "Nextcloud MCP" - artifacthub.io/changes: | - - kind: added - description: Login Flow v2 auth mode for Helm chart (ADR-022) - - kind: added - description: Multi-user BasicAuth guidance in post-install NOTES - - kind: added - description: Version and changelog info in post-install NOTES - - kind: changed - description: Updated appVersion to 0.64.4 -dependencies: - - name: qdrant - version: "1.17.1" - repository: https://qdrant.github.io/qdrant-helm - condition: qdrant.networkMode.deploySubchart - - name: ollama - version: "1.47.0" - repository: https://otwld.github.io/ollama-helm - condition: ollama.enabled diff --git a/charts/nextcloud-mcp-server/README.md b/charts/nextcloud-mcp-server/README.md deleted file mode 100644 index 477ae9c3..00000000 --- a/charts/nextcloud-mcp-server/README.md +++ /dev/null @@ -1,742 +0,0 @@ -# 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 -# Add the Helm repository -helm repo add nextcloud-mcp https://cbcoutinho.github.io/nextcloud-mcp-server -helm repo update - -# Install with basic auth (recommended for most users) -helm install nextcloud-mcp nextcloud-mcp/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 nextcloud-mcp/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 URL for browser-accessible OAuth authorization endpoint (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, defaults to `nextcloud.host`. **Only used for authorization endpoints** that browsers must access. All server-to-server endpoints (token, JWKS, introspection, userinfo) use URLs from OIDC discovery without rewriting - -#### 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` | - -#### 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 - -| 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 with BM25 hybrid search by deploying a vector database (Qdrant) and embedding service (Ollama or OpenAI). - -**Semantic Search Configuration:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `semanticSearch.enabled` | Enable semantic search and background vector synchronization | `false` | -| `semanticSearch.scanInterval` | Scan interval in seconds | `3600` | -| `semanticSearch.processorWorkers` | Number of concurrent processor workers | `3` | -| `semanticSearch.queueMaxSize` | Maximum queue size for pending documents | `10000` | - -**Document Chunking Configuration:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `documentChunking.chunkSize` | Number of words per chunk for embedding | `512` | -| `documentChunking.chunkOverlap` | Number of overlapping words between chunks | `50` | - -**Chunking Strategy:** -- **Small chunks (256-384)**: Better precision for searches, more storage overhead -- **Medium chunks (512-768)**: Balanced approach (recommended for most use cases) -- **Large chunks (1024+)**: Better context preservation, less precise matching -- **Overlap**: Should be 10-20% of chunk size to preserve context across boundaries - -**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) | `""` | - -#### Observability & Monitoring - -The chart includes comprehensive observability features including Prometheus metrics, OpenTelemetry tracing, and Grafana dashboards. - -**Metrics Configuration:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `observability.metrics.enabled` | Enable Prometheus metrics | `true` | -| `observability.metrics.port` | Metrics port | `9090` | -| `observability.metrics.path` | Metrics endpoint path | `/metrics` | - -**Tracing Configuration:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `observability.tracing.enabled` | Enable OpenTelemetry tracing | `false` | -| `observability.tracing.endpoint` | OTLP collector endpoint | `""` | -| `observability.tracing.serviceName` | Service name in traces | `nextcloud-mcp-server` | -| `observability.tracing.samplingRate` | Trace sampling rate (0.0-1.0) | `1.0` | - -**Logging Configuration:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `observability.logging.format` | Log format (json or text) | `json` | -| `observability.logging.level` | Log level | `INFO` | -| `observability.logging.includeTraceContext` | Include trace IDs in logs | `true` | - -**ServiceMonitor (Prometheus Operator):** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `serviceMonitor.enabled` | Create ServiceMonitor resource | `false` | -| `serviceMonitor.interval` | Scrape interval | `30s` | -| `serviceMonitor.scrapeTimeout` | Scrape timeout | `10s` | -| `serviceMonitor.labels` | Additional labels for ServiceMonitor | `{}` | - -**PrometheusRule (Prometheus Operator):** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `prometheusRule.enabled` | Create PrometheusRule with alert rules | `false` | -| `prometheusRule.labels` | Additional labels for PrometheusRule | `{}` | - -**Grafana Dashboards:** - -| Parameter | Description | Default | -|-----------|-------------|---------| -| `dashboards.enabled` | Enable automatic dashboard provisioning | `false` | -| `dashboards.grafanaFolder` | Grafana folder name for dashboards | `Nextcloud MCP` | -| `dashboards.labels` | Additional labels for dashboard ConfigMap | `{}` | -| `dashboards.annotations` | Additional annotations for dashboard ConfigMap | `{}` | - -When `dashboards.enabled` is `true`, a ConfigMap with the Grafana dashboard is created with the `grafana_dashboard: "1"` label. This enables automatic discovery by Grafana sidecar containers (commonly used with kube-prometheus-stack). - -The dashboard provides comprehensive monitoring including: -- HTTP request metrics (RED pattern: Rate, Errors, Duration) -- MCP tool performance and errors -- Nextcloud API performance by app (notes, calendar, contacts, etc.) -- OAuth token operations and cache hit rates -- External dependency health (Nextcloud, Qdrant, Keycloak, Unstructured API) -- Vector sync processing pipeline (when enabled) - -For manual import or more details, see `charts/nextcloud-mcp-server/dashboards/README.md`. - -## 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 (only used for browser-accessible auth endpoint) - -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 (only used for browser-accessible auth endpoint) - -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 semantic search -semanticSearch: - 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 -semanticSearch: - 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 -semanticSearch: - 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 -# Update the repository -helm repo update - -# Upgrade with your custom values -helm upgrade nextcloud-mcp nextcloud-mcp/nextcloud-mcp-server -f custom-values.yaml -``` - -### To upgrade with new values: - -```bash -helm upgrade nextcloud-mcp nextcloud-mcp/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 - - For OAuth mode: Ensure MCP server can reach OIDC discovery endpoints (token, JWKS, introspection, userinfo URLs) - - Check network policies and firewall rules - - Note: Do not use internal Docker hostnames (like `http://app:80`) for `nextcloud.host` - use externally resolvable URLs - -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. diff --git a/charts/nextcloud-mcp-server/dashboards/README.md b/charts/nextcloud-mcp-server/dashboards/README.md deleted file mode 100644 index 314ad526..00000000 --- a/charts/nextcloud-mcp-server/dashboards/README.md +++ /dev/null @@ -1,161 +0,0 @@ -# Grafana Dashboards - -This directory contains example Grafana dashboards for monitoring the Nextcloud MCP Server. - -## Dashboards - -### nextcloud-mcp-server.json - -All-in-one Operations Dashboard with comprehensive monitoring across all system components. - -#### Overview Row -High-level metrics for quick health assessment: -- **Request Rate** (stat): Total requests per second -- **Error Rate** (stat): Percentage of 5xx errors with color thresholds -- **P95 Latency** (stat): 95th percentile request latency -- **Active Requests** (stat): Current in-flight requests - -#### HTTP Metrics (RED Pattern) -Core request/error/duration metrics: -- **Request Rate by Endpoint** (timeseries): RPS breakdown by endpoint -- **Error Rate by Status Code** (timeseries): Error rates for 4xx/5xx codes -- **Latency Percentiles** (timeseries): P50, P95, P99 latency trends -- **Status Code Distribution** (piechart): Percentage breakdown of all status codes - -#### MCP Tools Row -MCP-specific tool performance: -- **Top Tools by Call Volume** (bargauge): Top 10 most-called tools -- **Tool Error Rate** (timeseries): Error rates per tool -- **Tool Execution Duration** (timeseries): P95 latency by tool - -#### Nextcloud API Row -Backend API performance metrics: -- **API Calls by App** (timeseries): Request rate per Nextcloud app (notes, calendar, contacts, etc.) -- **API Latency by App** (timeseries): P95 latency per app -- **API Retries by Reason** (timeseries): Retry patterns (429, timeout, connection errors) -- **API Error Rate** (stat): Overall API error percentage - -#### OAuth & Authentication Row -OAuth token operations and caching: -- **Token Validations** (timeseries): Success/failure rates for token validation -- **Token Exchange Operations** (timeseries): RFC 8693 token exchange operations -- **Token Cache Hit Rate** (stat): Percentage of cache hits (color-coded: red<50%, yellow<80%, green≥80%) -- **Refresh Token Operations** (timeseries): Refresh token storage operations by type - -#### Dependencies & Health Row -External dependency status monitoring: -- **Nextcloud Health** (stat): UP/DOWN status with color coding -- **Qdrant Health** (stat): Vector database health status -- **Keycloak Health** (stat): Identity provider health status -- **Unstructured API Health** (stat): Document processing API status -- **Health Check Duration** (timeseries): Health check latency by dependency -- **Database Operation Latency** (timeseries): P95 latency for DB operations (SQLite, Qdrant) - -#### Vector Sync Row (when enabled) -Document processing pipeline metrics: -- **Documents Processed Rate** (timeseries): Processing throughput by status (success/failure) -- **Processing Queue Depth** (gauge): Current queue size with thresholds (yellow>50, red>100) -- **Qdrant Operations** (timeseries): Vector database operations by type -- **Document Processing Duration** (timeseries): P95 processing latency - -## Importing to Grafana - -### Manual Import - -1. Open Grafana UI -2. Navigate to Dashboards → Import -3. Upload `nextcloud-mcp-server.json` -4. Select your Prometheus data source -5. Click "Import" - -### Automated Import (Helm Chart) - -The Helm chart now supports automatic dashboard provisioning via Grafana sidecar pattern. - -#### Option 1: Using Helm Chart (Recommended) - -Enable dashboard provisioning in your Helm values: - -```yaml -# values.yaml for nextcloud-mcp-server chart -dashboards: - enabled: true - grafanaFolder: "Nextcloud MCP" # Folder name in Grafana - labels: {} # Additional labels if needed -``` - -Then deploy or upgrade: - -```bash -helm upgrade --install nextcloud-mcp nextcloud-mcp-server \ - --set dashboards.enabled=true -``` - -The dashboard will be automatically imported by Grafana if the sidecar is configured -to watch for ConfigMaps with label `grafana_dashboard: "1"`. - -#### Option 2: Using kube-prometheus-stack - -If using kube-prometheus-stack with Grafana sidecar enabled, the dashboard will be -automatically discovered and imported. Ensure your Grafana deployment has: - -```yaml -# kube-prometheus-stack values -grafana: - sidecar: - dashboards: - enabled: true - label: grafana_dashboard - folder: /tmp/dashboards - provider: - foldersFromFilesStructure: true -``` - -#### Option 3: Manual ConfigMap Creation - -For other Grafana setups, create a ConfigMap manually: - -```bash -kubectl create configmap nextcloud-mcp-dashboard \ - --from-file=nextcloud-mcp-server.json \ - -n monitoring - -# Add sidecar discovery label -kubectl label configmap nextcloud-mcp-dashboard \ - grafana_dashboard=1 \ - -n monitoring - -# Add folder annotation (annotations support spaces, unlike labels) -kubectl annotate configmap nextcloud-mcp-dashboard \ - grafana_folder="Nextcloud MCP" \ - -n monitoring -``` - -## Dashboard Variables - -The dashboard includes four template variables for dynamic filtering: - -- **datasource**: Select your Prometheus data source -- **namespace**: Filter metrics by Kubernetes namespace (supports "All") -- **pod**: Filter by specific pod(s) - multi-select enabled (supports "All") -- **interval**: Query interval for rate calculations (1m, 5m, 10m, 30m, 1h - default: 5m) - -## Customization - -You can customize the dashboard by: - -1. Adjusting refresh rate (default: 30s) -2. Modifying time range (default: last 6 hours) -3. Adding new panels for specific metrics -4. Adjusting thresholds in existing panels - -## Metrics Reference - -All metrics are documented in `/docs/observability.md`. Key metric prefixes: - -- `mcp_http_*` - HTTP server metrics -- `mcp_tool_*` - MCP tool invocation metrics -- `mcp_nextcloud_api_*` - Nextcloud API call metrics -- `mcp_oauth_*` - OAuth token validation metrics -- `mcp_vector_sync_*` - Vector database sync metrics -- `mcp_db_*` - Database operation metrics diff --git a/charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json b/charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json deleted file mode 100644 index 90a31a6b..00000000 --- a/charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json +++ /dev/null @@ -1,1714 +0,0 @@ -{ - "editable": true, - "graphTooltip": 1, - "id": null, - "panels": [ - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 0 - }, - "id": 1, - "panels": [], - "title": "Overview", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 10 - }, - { - "color": "red", - "value": 50 - } - ] - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 1 - }, - "id": 2, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "sum(rate(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval]))", - "legendFormat": "requests/s", - "refId": "A" - } - ], - "title": "Request Rate", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 1 - }, - { - "color": "red", - "value": 5 - } - ] - }, - "unit": "percent" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 1 - }, - "id": 3, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "100 * sum(rate(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\", status_code=~\"5..\"}[$interval])) / sum(rate(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval]))", - "legendFormat": "error %", - "refId": "A" - } - ], - "title": "Error Rate", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 3, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 0.5 - }, - { - "color": "red", - "value": 1 - } - ] - }, - "unit": "s" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 1 - }, - "id": 4, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_http_request_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (le))", - "legendFormat": "p95", - "refId": "A" - } - ], - "title": "P95 Latency", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 10 - }, - { - "color": "red", - "value": 50 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 1 - }, - "id": 5, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "sum(mcp_http_requests_in_progress{namespace=\"$namespace\", pod=~\"$pod\"})", - "legendFormat": "in-flight", - "refId": "A" - } - ], - "title": "Active Requests", - "type": "stat" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 5 - }, - "id": 10, - "panels": [], - "title": "HTTP Metrics (RED Pattern)", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 6 - }, - "id": 11, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (endpoint)", - "legendFormat": "{{endpoint}}", - "refId": "A" - } - ], - "title": "Request Rate by Endpoint", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 6 - }, - "id": 12, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\", status_code=~\"4..|5..\"}[$interval])) by (status_code)", - "legendFormat": "{{status_code}}", - "refId": "A" - } - ], - "title": "Error Rate by Status Code", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 14 - }, - "id": 13, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "histogram_quantile(0.50, sum(rate(mcp_http_request_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (le))", - "legendFormat": "p50", - "refId": "A" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_http_request_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (le))", - "legendFormat": "p95", - "refId": "B" - }, - { - "expr": "histogram_quantile(0.99, sum(rate(mcp_http_request_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (le))", - "legendFormat": "p99", - "refId": "C" - } - ], - "title": "Latency Percentiles", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "unit": "short" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 14 - }, - "id": 14, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "percent" - ], - "displayMode": "table", - "placement": "right" - }, - "pieType": "donut" - }, - "targets": [ - { - "expr": "sum(increase(mcp_http_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$__range])) by (status_code)", - "legendFormat": "{{status_code}}", - "refId": "A" - } - ], - "title": "Status Code Distribution", - "type": "piechart" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 22 - }, - "id": 20, - "panels": [], - "title": "MCP Tools", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "continuous-GrYlRd" - }, - "unit": "short" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 23 - }, - "id": 21, - "options": { - "displayMode": "gradient", - "orientation": "horizontal", - "showUnfilled": true - }, - "targets": [ - { - "expr": "topk(10, sum(increase(mcp_tool_calls_total{namespace=\"$namespace\", pod=~\"$pod\"}[$__range])) by (tool_name))", - "legendFormat": "{{tool_name}}", - "refId": "A" - } - ], - "title": "Top Tools by Call Volume", - "type": "bargauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 23 - }, - "id": 22, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_tool_calls_total{namespace=\"$namespace\", pod=~\"$pod\", status=\"error\"}[$interval])) by (tool_name)", - "legendFormat": "{{tool_name}}", - "refId": "A" - } - ], - "title": "Tool Error Rate", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 24, - "x": 0, - "y": 31 - }, - "id": 23, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_tool_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (tool_name, le))", - "legendFormat": "{{tool_name}}", - "refId": "A" - } - ], - "title": "Tool Execution Duration (P95)", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 39 - }, - "id": 30, - "panels": [], - "title": "Nextcloud API", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 40 - }, - "id": 31, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_nextcloud_api_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (app)", - "legendFormat": "{{app}}", - "refId": "A" - } - ], - "title": "API Calls by App", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 40 - }, - "id": 32, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_nextcloud_api_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (app, le))", - "legendFormat": "{{app}}", - "refId": "A" - } - ], - "title": "API Latency by App (P95)", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 48 - }, - "id": 33, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_nextcloud_api_retries_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (reason)", - "legendFormat": "{{reason}}", - "refId": "A" - } - ], - "title": "API Retries by Reason", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 1 - }, - { - "color": "red", - "value": 5 - } - ] - }, - "unit": "percent" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 48 - }, - "id": 34, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "100 * sum(rate(mcp_nextcloud_api_requests_total{namespace=\"$namespace\", pod=~\"$pod\", status_code=~\"5..\"}[$interval])) / sum(rate(mcp_nextcloud_api_requests_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval]))", - "legendFormat": "error %", - "refId": "A" - } - ], - "title": "API Error Rate", - "type": "stat" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 56 - }, - "id": 40, - "panels": [], - "title": "OAuth & Authentication", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 57 - }, - "id": 41, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_oauth_token_validations_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (status)", - "legendFormat": "{{status}}", - "refId": "A" - } - ], - "title": "Token Validations", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 57 - }, - "id": 42, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_oauth_token_exchange_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (status)", - "legendFormat": "{{status}}", - "refId": "A" - } - ], - "title": "Token Exchange Operations", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 2, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "yellow", - "value": 50 - }, - { - "color": "green", - "value": 80 - } - ] - }, - "unit": "percent" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 65 - }, - "id": 43, - "options": { - "colorMode": "value", - "graphMode": "area", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "100 * sum(rate(mcp_oauth_token_cache_hits_total{namespace=\"$namespace\", pod=~\"$pod\", result=\"hit\"}[$interval])) / sum(rate(mcp_oauth_token_cache_hits_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval]))", - "legendFormat": "hit %", - "refId": "A" - } - ], - "title": "Token Cache Hit Rate", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "reqps" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 65 - }, - "id": 44, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_oauth_refresh_token_operations_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (operation)", - "legendFormat": "{{operation}}", - "refId": "A" - } - ], - "title": "Refresh Token Operations", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 73 - }, - "id": 50, - "panels": [], - "title": "Dependencies & Health", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [ - { - "options": { - "0": { - "color": "red", - "text": "DOWN" - } - }, - "type": "value" - }, - { - "options": { - "1": { - "color": "green", - "text": "UP" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 0, - "y": 74 - }, - "id": 51, - "options": { - "colorMode": "value", - "graphMode": "none", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "mcp_dependency_health{namespace=\"$namespace\", pod=~\"$pod\", dependency=\"nextcloud\"}", - "legendFormat": "status", - "refId": "A" - } - ], - "title": "Nextcloud Health", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [ - { - "options": { - "0": { - "color": "red", - "text": "DOWN" - } - }, - "type": "value" - }, - { - "options": { - "1": { - "color": "green", - "text": "UP" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 6, - "y": 74 - }, - "id": 52, - "options": { - "colorMode": "value", - "graphMode": "none", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "mcp_dependency_health{namespace=\"$namespace\", pod=~\"$pod\", dependency=\"qdrant\"}", - "legendFormat": "status", - "refId": "A" - } - ], - "title": "Qdrant Health", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [ - { - "options": { - "0": { - "color": "red", - "text": "DOWN" - } - }, - "type": "value" - }, - { - "options": { - "1": { - "color": "green", - "text": "UP" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 12, - "y": 74 - }, - "id": 53, - "options": { - "colorMode": "value", - "graphMode": "none", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "mcp_dependency_health{namespace=\"$namespace\", pod=~\"$pod\", dependency=\"keycloak\"}", - "legendFormat": "status", - "refId": "A" - } - ], - "title": "Keycloak Health", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "decimals": 0, - "mappings": [ - { - "options": { - "0": { - "color": "red", - "text": "DOWN" - } - }, - "type": "value" - }, - { - "options": { - "1": { - "color": "green", - "text": "UP" - } - }, - "type": "value" - } - ], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "red", - "value": null - }, - { - "color": "green", - "value": 1 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 4, - "w": 6, - "x": 18, - "y": 74 - }, - "id": 54, - "options": { - "colorMode": "value", - "graphMode": "none", - "orientation": "auto", - "reduceOptions": { - "calcs": [ - "lastNotNull" - ], - "values": false - }, - "textMode": "value_and_name" - }, - "targets": [ - { - "expr": "mcp_dependency_health{namespace=\"$namespace\", pod=~\"$pod\", dependency=\"unstructured\"}", - "legendFormat": "status", - "refId": "A" - } - ], - "title": "Unstructured API Health", - "type": "stat" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 78 - }, - "id": 55, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "mcp_dependency_check_duration_seconds{namespace=\"$namespace\", pod=~\"$pod\"}", - "legendFormat": "{{dependency}}", - "refId": "A" - } - ], - "title": "Health Check Duration", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 78 - }, - "id": 56, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_db_operation_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (db, operation, le))", - "legendFormat": "{{db}}/{{operation}}", - "refId": "A" - } - ], - "title": "Database Operation Latency", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { - "h": 1, - "w": 24, - "x": 0, - "y": 86 - }, - "id": 60, - "panels": [], - "title": "Vector Sync (when enabled)", - "type": "row" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "ops" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 87 - }, - "id": 61, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_vector_sync_documents_processed_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (status)", - "legendFormat": "{{status}}", - "refId": "A" - } - ], - "title": "Documents Processed Rate", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "thresholds" - }, - "max": 200, - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "yellow", - "value": 50 - }, - { - "color": "red", - "value": 100 - } - ] - }, - "unit": "short" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 87 - }, - "id": 62, - "options": { - "showThresholdLabels": true, - "showThresholdMarkers": true - }, - "targets": [ - { - "expr": "mcp_vector_sync_queue_size{namespace=\"$namespace\", pod=~\"$pod\"}", - "legendFormat": "queue", - "refId": "A" - } - ], - "title": "Processing Queue Depth", - "type": "gauge" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 10, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "ops" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 0, - "y": 95 - }, - "id": 63, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "sum(rate(mcp_qdrant_operations_total{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (operation)", - "legendFormat": "{{operation}}", - "refId": "A" - } - ], - "title": "Qdrant Operations", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "fieldConfig": { - "defaults": { - "custom": { - "drawStyle": "line", - "fillOpacity": 0, - "lineInterpolation": "smooth", - "showPoints": "never" - }, - "unit": "s" - } - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 95 - }, - "id": 64, - "options": { - "legend": { - "calcs": [ - "lastNotNull", - "mean", - "max" - ], - "displayMode": "table", - "placement": "bottom" - } - }, - "targets": [ - { - "expr": "histogram_quantile(0.95, sum(rate(mcp_vector_sync_processing_duration_seconds_bucket{namespace=\"$namespace\", pod=~\"$pod\"}[$interval])) by (le))", - "legendFormat": "p95", - "refId": "A" - } - ], - "title": "Document Processing Duration (P95)", - "type": "timeseries" - } - ], - "refresh": "30s", - "tags": [ - "nextcloud-mcp-server", - "operations", - "kubernetes", - "mcp" - ], - "templating": { - "list": [ - { - "current": { - "text": "Prometheus", - "value": "prometheus" - }, - "hide": 0, - "includeAll": false, - "multi": false, - "name": "datasource", - "options": [], - "query": "prometheus", - "refresh": 1, - "regex": "", - "skipUrlSync": false, - "type": "datasource" - }, - { - "current": {}, - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "hide": 0, - "includeAll": true, - "multi": false, - "name": "namespace", - "options": [], - "query": "label_values(mcp_http_requests_total, namespace)", - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "type": "query" - }, - { - "current": {}, - "datasource": { - "type": "prometheus", - "uid": "$datasource" - }, - "hide": 0, - "includeAll": true, - "multi": true, - "name": "pod", - "options": [], - "query": "label_values(mcp_http_requests_total{namespace=\"$namespace\"}, pod)", - "refresh": 2, - "regex": "", - "skipUrlSync": false, - "sort": 1, - "type": "query" - }, - { - "current": { - "text": "5m", - "value": "5m" - }, - "hide": 0, - "name": "interval", - "options": [ - { - "selected": false, - "text": "1m", - "value": "1m" - }, - { - "selected": true, - "text": "5m", - "value": "5m" - }, - { - "selected": false, - "text": "10m", - "value": "10m" - }, - { - "selected": false, - "text": "30m", - "value": "30m" - }, - { - "selected": false, - "text": "1h", - "value": "1h" - } - ], - "query": "1m,5m,10m,30m,1h", - "refresh": 0, - "skipUrlSync": false, - "type": "interval" - } - ] - }, - "time": { - "from": "now-6h", - "to": "now" - }, - "timezone": "browser", - "title": "Nextcloud MCP Server - Operations", - "uid": "nextcloud-mcp-server", - "version": 1 -} diff --git a/charts/nextcloud-mcp-server/templates/NOTES.txt b/charts/nextcloud-mcp-server/templates/NOTES.txt deleted file mode 100644 index 7877506a..00000000 --- a/charts/nextcloud-mcp-server/templates/NOTES.txt +++ /dev/null @@ -1,208 +0,0 @@ -Thank you for installing {{ .Chart.Name }}! - -Your Nextcloud MCP Server has been deployed in {{ .Values.auth.mode }} authentication mode. - -1. Get the application URL by running these commands: -{{- if .Values.ingress.enabled }} -{{- range $host := .Values.ingress.hosts }} - {{- range .paths }} - http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} - {{- end }} -{{- end }} -{{- else if contains "NodePort" .Values.service.type }} - export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "nextcloud-mcp-server.fullname" . }}) - export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") - echo http://$NODE_IP:$NODE_PORT -{{- else if contains "LoadBalancer" .Values.service.type }} - NOTE: It may take a few minutes for the LoadBalancer IP to be available. - You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "nextcloud-mcp-server.fullname" . }}' - export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "nextcloud-mcp-server.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") - echo http://$SERVICE_IP:{{ .Values.service.port }} -{{- else if contains "ClusterIP" .Values.service.type }} - export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "nextcloud-mcp-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") - export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") - echo "Visit http://127.0.0.1:8080 to use your MCP server" - kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT -{{- end }} - -2. Check the deployment status: - kubectl --namespace {{ .Release.Namespace }} get pods -l "app.kubernetes.io/name={{ include "nextcloud-mcp-server.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" - -{{- 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: {{ 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 }} - - IMPORTANT: OAuth mode is experimental and requires patches to the user_oidc app. - See: https://github.com/cbcoutinho/nextcloud-mcp-server#authentication -{{- else if eq .Values.auth.mode "multi-user-basic" }} - -3. Multi-User BasicAuth Mode (Pass-Through): - - Users provide credentials via Authorization header - - Connected to: {{ .Values.nextcloud.host }} - {{- if .Values.auth.multiUserBasic.enableOfflineAccess }} - - Offline access: Enabled (background operations with app passwords) - - Token storage: {{ .Values.auth.multiUserBasic.tokenStorageDb }} - {{- else }} - - Offline access: Disabled (stateless pass-through) - {{- end }} -{{- else if eq .Values.auth.mode "login-flow" }} - -3. Login Flow v2 Mode (Experimental, ADR-022): - - Server URL: {{ include "nextcloud-mcp-server.mcpServerUrl" . }} - - Connected to: {{ .Values.nextcloud.host }} - - Token storage: {{ .Values.auth.loginFlow.tokenStorageDb }} - - Users authenticate via Nextcloud's native Login Flow v2 — no OAuth patches required. - Each user gets a per-device app password managed by the MCP server. - - IMPORTANT: Login Flow v2 is experimental. See ADR-022 for details. -{{- end }} - -{{- if .Values.documentProcessing.enabled }} - -4. Document Processing: - - Enabled: {{ .Values.documentProcessing.enabled }} - - Default processor: {{ .Values.documentProcessing.defaultProcessor }} - {{- if .Values.documentProcessing.unstructured.enabled }} - - Unstructured API: {{ .Values.documentProcessing.unstructured.apiUrl }} - {{- end }} -{{- end }} - -{{- if .Values.semanticSearch.enabled }} - -5. Semantic Search & Vector Capabilities: - - Semantic Search: Enabled - - Scan Interval: {{ .Values.semanticSearch.scanInterval }}s - - Processor Workers: {{ .Values.semanticSearch.processorWorkers }} - {{- if .Values.qdrant.enabled }} - - Qdrant: Deployed as subchart ({{ .Release.Name }}-qdrant:6333) - {{- else }} - - Qdrant: Not deployed (configure external instance) - {{- end }} - {{- if .Values.ollama.enabled }} - - Ollama: Deployed as subchart ({{ .Release.Name }}-ollama:11434) - - Embedding Model: {{ .Values.ollama.embeddingModel }} - {{- else if .Values.ollama.url }} - - Ollama: Using external instance at {{ .Values.ollama.url }} - - Embedding Model: {{ .Values.ollama.embeddingModel }} - {{- else if .Values.openai.enabled }} - - OpenAI: Enabled for embeddings - {{- else }} - - WARNING: No embedding provider configured (Ollama or OpenAI required) - {{- end }} - - Check vector sync status: - kubectl --namespace {{ .Release.Namespace }} exec -it deploy/{{ include "nextcloud-mcp-server.fullname" . }} -- curl -s http://localhost:{{ include "nextcloud-mcp-server.port" . }}/user/page | grep "Vector Sync" -{{- end }} - -{{- if .Values.dashboards.enabled }} - -6. Grafana Dashboards: - - Dashboard provisioning: Enabled - - ConfigMap: {{ include "nextcloud-mcp-server.fullname" . }}-dashboard - - Grafana Folder: {{ .Values.dashboards.grafanaFolder }} - - The dashboard will be automatically imported by Grafana if the sidecar is configured - to watch for ConfigMaps with label "grafana_dashboard: 1". - - To manually import the dashboard: - kubectl --namespace {{ .Release.Namespace }} get configmap {{ include "nextcloud-mcp-server.fullname" . }}-dashboard -o jsonpath='{.data.nextcloud-mcp-server\.json}' | jq . > dashboard.json - - Then import dashboard.json via Grafana UI (Dashboards → Import). -{{- else }} - -6. Grafana Dashboards: - - Dashboard provisioning: Disabled - - To enable automatic dashboard provisioning, set: dashboards.enabled=true - - Manual import option: - The dashboard JSON is available in the chart at charts/nextcloud-mcp-server/dashboards/nextcloud-mcp-server.json -{{- 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 }} - -Deployed version: - - Chart: {{ .Chart.Version }} - - App: {{ .Chart.AppVersion }} - -Full changelog: https://github.com/cbcoutinho/nextcloud-mcp-server/blob/master/charts/nextcloud-mcp-server/CHANGELOG.md - -For more information and documentation: -- GitHub: https://github.com/cbcoutinho/nextcloud-mcp-server -- Documentation: https://github.com/cbcoutinho/nextcloud-mcp-server#readme - -To upgrade this deployment: - helm upgrade {{ .Release.Name }} nextcloud-mcp-server - -To uninstall: - helm uninstall {{ .Release.Name }} diff --git a/charts/nextcloud-mcp-server/templates/_helpers.tpl b/charts/nextcloud-mcp-server/templates/_helpers.tpl deleted file mode 100644 index 04980571..00000000 --- a/charts/nextcloud-mcp-server/templates/_helpers.tpl +++ /dev/null @@ -1,237 +0,0 @@ -{{/* -Expand the name of the chart. -*/}} -{{- define "nextcloud-mcp-server.name" -}} -{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Create a default fully qualified app name. -We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). -If release name contains chart name it will be used as a full name. -*/}} -{{- define "nextcloud-mcp-server.fullname" -}} -{{- if .Values.fullnameOverride }} -{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- $name := default .Chart.Name .Values.nameOverride }} -{{- if contains $name .Release.Name }} -{{- .Release.Name | trunc 63 | trimSuffix "-" }} -{{- else }} -{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} -{{- end }} -{{- end }} -{{- end }} - -{{/* -Create chart name and version as used by the chart label. -*/}} -{{- define "nextcloud-mcp-server.chart" -}} -{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} -{{- end }} - -{{/* -Common labels -*/}} -{{- define "nextcloud-mcp-server.labels" -}} -helm.sh/chart: {{ include "nextcloud-mcp-server.chart" . }} -{{ include "nextcloud-mcp-server.selectorLabels" . }} -{{- if .Chart.AppVersion }} -app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} -{{- end }} -app.kubernetes.io/managed-by: {{ .Release.Service }} -{{- end }} - -{{/* -Selector labels -*/}} -{{- define "nextcloud-mcp-server.selectorLabels" -}} -app.kubernetes.io/name: {{ include "nextcloud-mcp-server.name" . }} -app.kubernetes.io/instance: {{ .Release.Name }} -{{- end }} - -{{/* -Create the name of the service account to use -*/}} -{{- define "nextcloud-mcp-server.serviceAccountName" -}} -{{- if .Values.serviceAccount.create }} -{{- default (include "nextcloud-mcp-server.fullname" .) .Values.serviceAccount.name }} -{{- else }} -{{- default "default" .Values.serviceAccount.name }} -{{- end }} -{{- end }} - -{{/* -Create the name of the secret to use for basic auth -*/}} -{{- define "nextcloud-mcp-server.basicAuthSecretName" -}} -{{- if .Values.auth.basic.existingSecret }} -{{- .Values.auth.basic.existingSecret }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-basic-auth -{{- end }} -{{- end }} - -{{/* -Create the name of the secret to use for multi-user basic auth -*/}} -{{- define "nextcloud-mcp-server.multiUserBasicSecretName" -}} -{{- if .Values.auth.multiUserBasic.existingSecret }} -{{- .Values.auth.multiUserBasic.existingSecret }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-multi-user-basic -{{- end }} -{{- end }} - -{{/* -Create the name of the PVC to use for multi-user basic token storage -*/}} -{{- define "nextcloud-mcp-server.multiUserBasicPvcName" -}} -{{- if .Values.auth.multiUserBasic.persistence.existingClaim }} -{{- .Values.auth.multiUserBasic.persistence.existingClaim }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-token-storage -{{- end }} -{{- end }} - -{{/* -Create the name of the secret to use for OAuth -*/}} -{{- define "nextcloud-mcp-server.oauthSecretName" -}} -{{- if .Values.auth.oauth.existingSecret }} -{{- .Values.auth.oauth.existingSecret }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-oauth -{{- end }} -{{- end }} - -{{/* -Create the name of the secret to use for Login Flow v2 -*/}} -{{- define "nextcloud-mcp-server.loginFlowSecretName" -}} -{{- if .Values.auth.loginFlow.existingSecret }} -{{- .Values.auth.loginFlow.existingSecret }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-login-flow -{{- end }} -{{- end }} - -{{/* -Create the name of the PVC to use for OAuth storage -*/}} -{{- define "nextcloud-mcp-server.oauthPvcName" -}} -{{- if .Values.auth.oauth.persistence.existingClaim }} -{{- .Values.auth.oauth.persistence.existingClaim }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-oauth-storage -{{- end }} -{{- end }} - -{{/* -Create the name of the PVC to use for Qdrant local persistent storage -*/}} -{{- define "nextcloud-mcp-server.qdrantPvcName" -}} -{{- if .Values.qdrant.localPersistence.existingClaim }} -{{- .Values.qdrant.localPersistence.existingClaim }} -{{- else }} -{{- include "nextcloud-mcp-server.fullname" . }}-qdrant-data -{{- 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 eq .Values.auth.mode "login-flow" -}} -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 -*/}} -{{- define "nextcloud-mcp-server.port" -}} -{{- .Values.mcp.port }} -{{- end }} - -{{/* -Return the image tag (always uses chart appVersion) -*/}} -{{- define "nextcloud-mcp-server.imageTag" -}} -{{- .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/charts/nextcloud-mcp-server/templates/dashboard-configmap.yaml b/charts/nextcloud-mcp-server/templates/dashboard-configmap.yaml deleted file mode 100644 index 5f77657a..00000000 --- a/charts/nextcloud-mcp-server/templates/dashboard-configmap.yaml +++ /dev/null @@ -1,25 +0,0 @@ -{{- if .Values.dashboards.enabled }} -apiVersion: v1 -kind: ConfigMap -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-dashboard - namespace: {{ .Release.Namespace }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.dashboards.labels }} - {{- toYaml . | nindent 4 }} - {{- end }} - # Grafana sidecar discovery label - grafana_dashboard: "1" - annotations: - {{- with .Values.dashboards.annotations }} - {{- toYaml . | nindent 4 }} - {{- end }} - # Grafana folder name (annotations support spaces, unlike labels) - {{- if .Values.dashboards.grafanaFolder }} - grafana_folder: {{ .Values.dashboards.grafanaFolder | quote }} - {{- end }} -data: - nextcloud-mcp-server.json: |- -{{ .Files.Get "dashboards/nextcloud-mcp-server.json" | indent 4 }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/deployment.yaml b/charts/nextcloud-mcp-server/templates/deployment.yaml deleted file mode 100644 index 749fe2bb..00000000 --- a/charts/nextcloud-mcp-server/templates/deployment.yaml +++ /dev/null @@ -1,340 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - strategy: - type: Recreate - {{- if not .Values.autoscaling.enabled }} - replicas: {{ .Values.replicaCount }} - {{- end }} - selector: - matchLabels: - {{- include "nextcloud-mcp-server.selectorLabels" . | nindent 6 }} - template: - metadata: - annotations: - checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} - {{- with .Values.podAnnotations }} - {{- toYaml . | nindent 8 }} - {{- end }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 8 }} - {{- with .Values.podLabels }} - {{- toYaml . | nindent 8 }} - {{- end }} - spec: - {{- with .Values.imagePullSecrets }} - imagePullSecrets: - {{- toYaml . | nindent 8 }} - {{- end }} - serviceAccountName: {{ include "nextcloud-mcp-server.serviceAccountName" . }} - securityContext: - {{- toYaml .Values.podSecurityContext | nindent 8 }} - {{- with .Values.initContainers }} - initContainers: - {{- toYaml . | nindent 8 }} - {{- end }} - containers: - - name: {{ .Chart.Name }} - securityContext: - {{- toYaml .Values.securityContext | nindent 12 }} - image: "{{ .Values.image.repository }}:{{ include "nextcloud-mcp-server.imageTag" . }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - args: - - "--transport" - - "{{ .Values.mcp.transport }}" - {{- if or (eq .Values.auth.mode "oauth") (eq .Values.auth.mode "login-flow") }} - - "--oauth" - {{- end }} - {{- if eq .Values.auth.mode "oauth" }} - - "--oauth-token-type" - - "{{ .Values.auth.oauth.tokenType }}" - {{- end }} - {{- with .Values.mcp.extraArgs }} - {{- toYaml . | nindent 12 }} - {{- end }} - ports: - - name: http - containerPort: {{ include "nextcloud-mcp-server.port" . }} - protocol: TCP - {{- if .Values.observability.metrics.enabled }} - - name: metrics - containerPort: {{ .Values.observability.metrics.port }} - protocol: TCP - {{- end }} - env: - # Nextcloud connection - - name: NEXTCLOUD_HOST - value: {{ .Values.nextcloud.host | quote }} - {{- if eq .Values.auth.mode "basic" }} - # Basic auth mode (single-user) - - name: NEXTCLOUD_USERNAME - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.basicAuthSecretName" . }} - key: {{ .Values.auth.basic.usernameKey }} - - name: NEXTCLOUD_PASSWORD - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.basicAuthSecretName" . }} - key: {{ .Values.auth.basic.passwordKey }} - {{- else if eq .Values.auth.mode "multi-user-basic" }} - # Multi-user BasicAuth mode (pass-through) - - name: ENABLE_MULTI_USER_BASIC_AUTH - value: "true" - - name: NEXTCLOUD_MCP_SERVER_URL - value: {{ include "nextcloud-mcp-server.mcpServerUrl" . | quote }} - - name: NEXTCLOUD_PUBLIC_ISSUER_URL - value: {{ include "nextcloud-mcp-server.publicIssuerUrl" . | quote }} - {{- if .Values.auth.multiUserBasic.enableOfflineAccess }} - # Background operations with app passwords (replaces deprecated ENABLE_OFFLINE_ACCESS) - - name: ENABLE_BACKGROUND_OPERATIONS - value: "true" - - name: TOKEN_STORAGE_DB - value: {{ .Values.auth.multiUserBasic.tokenStorageDb | quote }} - - name: TOKEN_ENCRYPTION_KEY - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.multiUserBasicSecretName" . }} - key: {{ .Values.auth.multiUserBasic.tokenEncryptionKeyKey }} - - name: NEXTCLOUD_OIDC_SCOPES - value: {{ .Values.auth.multiUserBasic.scopes | quote }} - {{- if or .Values.auth.multiUserBasic.clientId .Values.auth.multiUserBasic.existingSecret }} - # Static OAuth credentials (optional - uses DCR if not provided) - - name: NEXTCLOUD_OIDC_CLIENT_ID - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.multiUserBasicSecretName" . }} - key: {{ .Values.auth.multiUserBasic.clientIdKey }} - - name: NEXTCLOUD_OIDC_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.multiUserBasicSecretName" . }} - key: {{ .Values.auth.multiUserBasic.clientSecretKey }} - {{- end }} - {{- end }} - {{- else if eq .Values.auth.mode "oauth" }} - # OAuth mode - - name: NEXTCLOUD_MCP_SERVER_URL - value: {{ include "nextcloud-mcp-server.mcpServerUrl" . | quote }} - - name: NEXTCLOUD_PUBLIC_ISSUER_URL - value: {{ include "nextcloud-mcp-server.publicIssuerUrl" . | quote }} - - name: NEXTCLOUD_OIDC_SCOPES - value: {{ .Values.auth.oauth.scopes | quote }} - {{- if or .Values.auth.oauth.clientId .Values.auth.oauth.existingSecret }} - - name: NEXTCLOUD_OIDC_CLIENT_ID - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.oauthSecretName" . }} - key: {{ .Values.auth.oauth.clientIdKey }} - - name: NEXTCLOUD_OIDC_CLIENT_SECRET - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.oauthSecretName" . }} - key: {{ .Values.auth.oauth.clientSecretKey }} - {{- end }} - {{- else if eq .Values.auth.mode "login-flow" }} - # Login Flow v2 mode (ADR-022) - - name: ENABLE_LOGIN_FLOW - value: "true" - - name: NEXTCLOUD_MCP_SERVER_URL - value: {{ include "nextcloud-mcp-server.mcpServerUrl" . | quote }} - - name: NEXTCLOUD_PUBLIC_ISSUER_URL - value: {{ include "nextcloud-mcp-server.publicIssuerUrl" . | quote }} - - name: TOKEN_STORAGE_DB - value: {{ .Values.auth.loginFlow.tokenStorageDb | quote }} - - name: TOKEN_ENCRYPTION_KEY - valueFrom: - secretKeyRef: - name: {{ include "nextcloud-mcp-server.loginFlowSecretName" . }} - key: {{ .Values.auth.loginFlow.tokenEncryptionKeyKey }} - {{- end }} - {{- if .Values.documentProcessing.enabled }} - # Document processing - - name: ENABLE_DOCUMENT_PROCESSING - value: {{ .Values.documentProcessing.enabled | quote }} - - name: DOCUMENT_PROCESSOR - value: {{ .Values.documentProcessing.defaultProcessor | quote }} - - name: PROGRESS_INTERVAL - value: {{ .Values.documentProcessing.progressInterval | quote }} - {{- if .Values.documentProcessing.unstructured.enabled }} - - name: ENABLE_UNSTRUCTURED - value: "true" - - name: UNSTRUCTURED_API_URL - value: {{ .Values.documentProcessing.unstructured.apiUrl | quote }} - - name: UNSTRUCTURED_TIMEOUT - value: {{ .Values.documentProcessing.unstructured.timeout | quote }} - - name: UNSTRUCTURED_STRATEGY - value: {{ .Values.documentProcessing.unstructured.strategy | quote }} - - name: UNSTRUCTURED_LANGUAGES - value: {{ .Values.documentProcessing.unstructured.languages | quote }} - {{- end }} - {{- if .Values.documentProcessing.tesseract.enabled }} - - name: ENABLE_TESSERACT - value: "true" - {{- if .Values.documentProcessing.tesseract.cmd }} - - name: TESSERACT_CMD - value: {{ .Values.documentProcessing.tesseract.cmd | quote }} - {{- end }} - - name: TESSERACT_LANG - value: {{ .Values.documentProcessing.tesseract.lang | quote }} - {{- end }} - {{- if .Values.documentProcessing.custom.enabled }} - - name: ENABLE_CUSTOM_PROCESSOR - value: "true" - - name: CUSTOM_PROCESSOR_NAME - value: {{ .Values.documentProcessing.custom.name | quote }} - - name: CUSTOM_PROCESSOR_URL - value: {{ .Values.documentProcessing.custom.url | quote }} - {{- if .Values.documentProcessing.custom.apiKey }} - - name: CUSTOM_PROCESSOR_API_KEY - value: {{ .Values.documentProcessing.custom.apiKey | quote }} - {{- end }} - - name: CUSTOM_PROCESSOR_TIMEOUT - value: {{ .Values.documentProcessing.custom.timeout | quote }} - - name: CUSTOM_PROCESSOR_TYPES - value: {{ .Values.documentProcessing.custom.types | quote }} - {{- end }} - {{- end }} - # Semantic Search (replaces deprecated VECTOR_SYNC_ENABLED) - - name: ENABLE_SEMANTIC_SEARCH - value: {{ .Values.semanticSearch.enabled | quote }} - {{- if .Values.semanticSearch.enabled }} - - name: VECTOR_SYNC_SCAN_INTERVAL - value: {{ .Values.semanticSearch.scanInterval | quote }} - - name: VECTOR_SYNC_PROCESSOR_WORKERS - value: {{ .Values.semanticSearch.processorWorkers | quote }} - - name: VECTOR_SYNC_QUEUE_MAX_SIZE - value: {{ .Values.semanticSearch.queueMaxSize | quote }} - {{- end }} - # Document Chunking (always set, used by vector sync processor) - - name: DOCUMENT_CHUNK_SIZE - value: {{ .Values.documentChunking.chunkSize | quote }} - - name: DOCUMENT_CHUNK_OVERLAP - value: {{ .Values.documentChunking.chunkOverlap | quote }} - # Qdrant Vector Database - {{- if eq .Values.qdrant.mode "network" }} - # Network mode: Use dedicated Qdrant service - {{- if .Values.qdrant.networkMode.deploySubchart }} - - name: QDRANT_URL - value: "http://{{ .Release.Name }}-qdrant:6333" - {{- else if .Values.qdrant.networkMode.externalUrl }} - - name: QDRANT_URL - value: {{ .Values.qdrant.networkMode.externalUrl | quote }} - {{- end }} - {{- if or .Values.qdrant.networkMode.apiKey .Values.qdrant.networkMode.existingSecret }} - - name: QDRANT_API_KEY - valueFrom: - secretKeyRef: - name: {{ .Values.qdrant.networkMode.existingSecret | default (printf "%s-qdrant" .Release.Name) }} - key: {{ .Values.qdrant.networkMode.secretKey }} - {{- end }} - {{- else if eq .Values.qdrant.mode "persistent" }} - # Persistent local mode: File-based storage - - name: QDRANT_LOCATION - value: {{ .Values.qdrant.localPersistence.dataPath | quote }} - {{- else }} - # In-memory mode (default): Ephemeral storage - - name: QDRANT_LOCATION - value: ":memory:" - {{- end }} - - name: QDRANT_COLLECTION - value: {{ .Values.qdrant.collection | quote }} - # Ollama Embedding Service - {{- if or .Values.ollama.enabled .Values.ollama.url }} - - name: OLLAMA_BASE_URL - value: {{ .Values.ollama.url | default (printf "http://%s-ollama:11434" .Release.Name) | quote }} - - name: OLLAMA_EMBEDDING_MODEL - value: {{ .Values.ollama.embeddingModel | quote }} - - name: OLLAMA_VERIFY_SSL - value: {{ .Values.ollama.verifySsl | quote }} - {{- end }} - # OpenAI Embedding Provider (alternative to Ollama) - {{- if .Values.openai.enabled }} - - name: OPENAI_API_KEY - valueFrom: - secretKeyRef: - name: {{ .Values.openai.existingSecret | default (printf "%s-openai" (include "nextcloud-mcp-server.fullname" .)) }} - key: {{ .Values.openai.secretKey }} - {{- if .Values.openai.baseUrl }} - - name: OPENAI_BASE_URL - value: {{ .Values.openai.baseUrl | quote }} - {{- end }} - {{- end }} - # Observability - - name: METRICS_ENABLED - value: {{ .Values.observability.metrics.enabled | quote }} - - name: METRICS_PORT - value: {{ .Values.observability.metrics.port | quote }} - {{- if .Values.observability.tracing.enabled }} - - name: OTEL_EXPORTER_OTLP_ENDPOINT - value: {{ .Values.observability.tracing.endpoint | quote }} - - name: OTEL_SERVICE_NAME - value: {{ .Values.observability.tracing.serviceName | quote }} - - name: OTEL_TRACES_SAMPLER_ARG - value: {{ .Values.observability.tracing.samplingRate | quote }} - {{- end }} - - name: LOG_FORMAT - value: {{ .Values.observability.logging.format | quote }} - - name: LOG_LEVEL - value: {{ .Values.observability.logging.level | quote }} - - name: LOG_INCLUDE_TRACE_CONTEXT - value: {{ .Values.observability.logging.includeTraceContext | quote }} - {{- with .Values.extraEnv }} - {{- toYaml . | nindent 12 }} - {{- end }} - {{- with .Values.extraEnvFrom }} - envFrom: - {{- toYaml . | nindent 12 }} - {{- end }} - livenessProbe: - {{- toYaml .Values.livenessProbe | nindent 12 }} - readinessProbe: - {{- toYaml .Values.readinessProbe | nindent 12 }} - resources: - {{- toYaml .Values.resources | nindent 12 }} - volumeMounts: - - name: tmp - mountPath: /tmp - {{- if or (and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled) (eq .Values.auth.mode "login-flow") }} - - name: oauth-storage - mountPath: /app/.oauth - {{- end }} - - name: data-storage - mountPath: /app/data - {{- with .Values.volumeMounts }} - {{- toYaml . | nindent 12 }} - {{- end }} - volumes: - - name: tmp - emptyDir: {} - {{- if or (and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled) (eq .Values.auth.mode "login-flow") }} - - name: oauth-storage - persistentVolumeClaim: - claimName: {{ include "nextcloud-mcp-server.oauthPvcName" . }} - {{- end }} - - name: data-storage - {{- if eq (include "nextcloud-mcp-server.dataStorageEnabled" .) "true" }} - persistentVolumeClaim: - claimName: {{ include "nextcloud-mcp-server.dataStoragePvcName" . }} - {{- else }} - emptyDir: {} - {{- end }} - {{- with .Values.volumes }} - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} diff --git a/charts/nextcloud-mcp-server/templates/hpa.yaml b/charts/nextcloud-mcp-server/templates/hpa.yaml deleted file mode 100644 index 260eae68..00000000 --- a/charts/nextcloud-mcp-server/templates/hpa.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if .Values.autoscaling.enabled }} -apiVersion: autoscaling/v2 -kind: HorizontalPodAutoscaler -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - scaleTargetRef: - apiVersion: apps/v1 - kind: Deployment - name: {{ include "nextcloud-mcp-server.fullname" . }} - minReplicas: {{ .Values.autoscaling.minReplicas }} - maxReplicas: {{ .Values.autoscaling.maxReplicas }} - metrics: - {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} - - type: Resource - resource: - name: cpu - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} - {{- end }} - {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} - - type: Resource - resource: - name: memory - target: - type: Utilization - averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} - {{- end }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/ingress.yaml b/charts/nextcloud-mcp-server/templates/ingress.yaml deleted file mode 100644 index fe38b947..00000000 --- a/charts/nextcloud-mcp-server/templates/ingress.yaml +++ /dev/null @@ -1,61 +0,0 @@ -{{- if .Values.ingress.enabled -}} -{{- $fullName := include "nextcloud-mcp-server.fullname" . -}} -{{- $svcPort := .Values.service.port -}} -{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} - {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} - {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} - {{- end }} -{{- end }} -{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1 -{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} -apiVersion: networking.k8s.io/v1beta1 -{{- else -}} -apiVersion: extensions/v1beta1 -{{- end }} -kind: Ingress -metadata: - name: {{ $fullName }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.ingress.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} - ingressClassName: {{ .Values.ingress.className }} - {{- end }} - {{- if .Values.ingress.tls }} - tls: - {{- range .Values.ingress.tls }} - - hosts: - {{- range .hosts }} - - {{ . | quote }} - {{- end }} - secretName: {{ .secretName }} - {{- end }} - {{- end }} - rules: - {{- range .Values.ingress.hosts }} - - host: {{ .host | quote }} - http: - paths: - {{- range .paths }} - - path: {{ .path }} - {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} - pathType: {{ .pathType }} - {{- end }} - backend: - {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} - service: - name: {{ $fullName }} - port: - number: {{ $svcPort }} - {{- else }} - serviceName: {{ $fullName }} - servicePort: {{ $svcPort }} - {{- end }} - {{- end }} - {{- end }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/openai-secret.yaml b/charts/nextcloud-mcp-server/templates/openai-secret.yaml deleted file mode 100644 index d8514a37..00000000 --- a/charts/nextcloud-mcp-server/templates/openai-secret.yaml +++ /dev/null @@ -1,11 +0,0 @@ -{{- if and .Values.openai.enabled (not .Values.openai.existingSecret) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-openai - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -type: Opaque -data: - {{ .Values.openai.secretKey }}: {{ .Values.openai.apiKey | b64enc | quote }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/prometheusrule.yaml b/charts/nextcloud-mcp-server/templates/prometheusrule.yaml deleted file mode 100644 index 204d127d..00000000 --- a/charts/nextcloud-mcp-server/templates/prometheusrule.yaml +++ /dev/null @@ -1,92 +0,0 @@ -{{- if and .Values.observability.metrics.enabled .Values.prometheusRule.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: PrometheusRule -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.prometheusRule.labels }} - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - groups: - - name: nextcloud-mcp-server.critical - interval: 30s - rules: - - alert: NextcloudMCPServerDown - expr: up{job="{{ include "nextcloud-mcp-server.fullname" . }}"} == 0 - for: 5m - labels: - severity: critical - annotations: - summary: "Nextcloud MCP Server is down" - description: "{{ `{{` }} $labels.pod {{ `}}` }} has been down for more than 5 minutes." - - - alert: NextcloudMCPHighErrorRate - expr: | - sum(rate(mcp_http_requests_total{status_code=~"5..", job="{{ include "nextcloud-mcp-server.fullname" . }}"}[5m])) - / sum(rate(mcp_http_requests_total{job="{{ include "nextcloud-mcp-server.fullname" . }}"}[5m])) > 0.05 - for: 5m - labels: - severity: critical - annotations: - summary: "High error rate on Nextcloud MCP Server" - description: "Error rate is {{ `{{` }} printf \"%.2f%%\" (mul $value 100) {{ `}}` }} (threshold: 5%)" - - - alert: NextcloudMCPHighLatency - expr: | - histogram_quantile(0.95, - sum(rate(mcp_http_request_duration_seconds_bucket{job="{{ include "nextcloud-mcp-server.fullname" . }}"}[5m])) by (le, endpoint) - ) > 1 - for: 5m - labels: - severity: critical - annotations: - summary: "High latency on Nextcloud MCP Server" - description: "P95 latency is {{ `{{` }} printf \"%.2fs\" $value {{ `}}` }} on {{ `{{` }} $labels.endpoint {{ `}}` }} (threshold: 1s)" - - - alert: NextcloudMCPDependencyDown - expr: mcp_dependency_health{job="{{ include "nextcloud-mcp-server.fullname" . }}"} == 0 - for: 2m - labels: - severity: critical - annotations: - summary: "Nextcloud MCP dependency is down" - description: "Dependency {{ `{{` }} $labels.dependency {{ `}}` }} has been down for more than 2 minutes." - - - name: nextcloud-mcp-server.warning - interval: 30s - rules: - - alert: NextcloudMCPTokenValidationErrors - expr: | - sum(rate(mcp_oauth_token_validations_total{result="error", job="{{ include "nextcloud-mcp-server.fullname" . }}"}[10m])) - / sum(rate(mcp_oauth_token_validations_total{job="{{ include "nextcloud-mcp-server.fullname" . }}"}[10m])) > 0.01 - for: 10m - labels: - severity: warning - annotations: - summary: "High token validation error rate" - description: "Token validation error rate is {{ `{{` }} printf \"%.2f%%\" (mul $value 100) {{ `}}` }} (threshold: 1%)" - - - alert: NextcloudMCPVectorSyncQueueHigh - expr: mcp_vector_sync_queue_size{job="{{ include "nextcloud-mcp-server.fullname" . }}"} > 100 - for: 15m - labels: - severity: warning - annotations: - summary: "Vector sync queue is high" - description: "Vector sync queue size is {{ `{{` }} $value {{ `}}` }} (threshold: 100)" - - - alert: NextcloudMCPQdrantSlowQueries - expr: | - histogram_quantile(0.95, - sum(rate(mcp_db_operation_duration_seconds_bucket{db="qdrant", job="{{ include "nextcloud-mcp-server.fullname" . }}"}[10m])) by (le) - ) > 0.5 - for: 10m - labels: - severity: warning - annotations: - summary: "Qdrant queries are slow" - description: "P95 Qdrant query latency is {{ `{{` }} printf \"%.2fs\" $value {{ `}}` }} (threshold: 0.5s)" -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/pvc.yaml b/charts/nextcloud-mcp-server/templates/pvc.yaml deleted file mode 100644 index 268b812e..00000000 --- a/charts/nextcloud-mcp-server/templates/pvc.yaml +++ /dev/null @@ -1,64 +0,0 @@ -{{- if and (eq .Values.auth.mode "oauth") .Values.auth.oauth.persistence.enabled (not .Values.auth.oauth.persistence.existingClaim) }} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-oauth-storage - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - accessModes: - - {{ .Values.auth.oauth.persistence.accessMode }} - {{- if .Values.auth.oauth.persistence.storageClass }} - storageClassName: {{ .Values.auth.oauth.persistence.storageClass }} - {{- end }} - resources: - requests: - storage: {{ .Values.auth.oauth.persistence.size }} -{{- end }} ---- -{{- if eq .Values.auth.mode "login-flow" }} -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-oauth-storage - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 100Mi -{{- end }} ---- -{{- 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 -kind: PersistentVolumeClaim -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-data-storage - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -spec: - accessModes: - - {{ $accessMode }} - {{- if $storageClass }} - storageClassName: {{ $storageClass }} - {{- end }} - resources: - requests: - storage: {{ $size }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/secret.yaml b/charts/nextcloud-mcp-server/templates/secret.yaml deleted file mode 100644 index aeb138b5..00000000 --- a/charts/nextcloud-mcp-server/templates/secret.yaml +++ /dev/null @@ -1,61 +0,0 @@ -{{- if eq .Values.auth.mode "basic" }} -{{- if not .Values.auth.basic.existingSecret }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-basic-auth - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -type: Opaque -data: - {{ .Values.auth.basic.usernameKey }}: {{ .Values.auth.basic.username | b64enc | quote }} - {{ .Values.auth.basic.passwordKey }}: {{ .Values.auth.basic.password | b64enc | quote }} -{{- end }} -{{- end }} ---- -{{- if eq .Values.auth.mode "multi-user-basic" }} -{{- if and .Values.auth.multiUserBasic.enableOfflineAccess (not .Values.auth.multiUserBasic.existingSecret) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-multi-user-basic - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -type: Opaque -data: - {{ .Values.auth.multiUserBasic.tokenEncryptionKeyKey }}: {{ .Values.auth.multiUserBasic.tokenEncryptionKey | b64enc | quote }} - {{- if .Values.auth.multiUserBasic.clientId }} - {{ .Values.auth.multiUserBasic.clientIdKey }}: {{ .Values.auth.multiUserBasic.clientId | b64enc | quote }} - {{ .Values.auth.multiUserBasic.clientSecretKey }}: {{ .Values.auth.multiUserBasic.clientSecret | b64enc | quote }} - {{- end }} -{{- end }} -{{- end }} ---- -{{- if eq .Values.auth.mode "oauth" }} -{{- if and .Values.auth.oauth.clientId (not .Values.auth.oauth.existingSecret) }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-oauth - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -type: Opaque -data: - {{ .Values.auth.oauth.clientIdKey }}: {{ .Values.auth.oauth.clientId | b64enc | quote }} - {{ .Values.auth.oauth.clientSecretKey }}: {{ .Values.auth.oauth.clientSecret | b64enc | quote }} -{{- end }} -{{- end }} ---- -{{- if eq .Values.auth.mode "login-flow" }} -{{- if not .Values.auth.loginFlow.existingSecret }} -apiVersion: v1 -kind: Secret -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }}-login-flow - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} -type: Opaque -data: - {{ .Values.auth.loginFlow.tokenEncryptionKeyKey }}: {{ .Values.auth.loginFlow.tokenEncryptionKey | b64enc | quote }} -{{- end }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/service.yaml b/charts/nextcloud-mcp-server/templates/service.yaml deleted file mode 100644 index af245e07..00000000 --- a/charts/nextcloud-mcp-server/templates/service.yaml +++ /dev/null @@ -1,25 +0,0 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.service.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - type: {{ .Values.service.type }} - ports: - - port: {{ .Values.service.port }} - targetPort: http - protocol: TCP - name: http - {{- if .Values.observability.metrics.enabled }} - - port: {{ .Values.observability.metrics.port }} - targetPort: metrics - protocol: TCP - name: metrics - {{- end }} - selector: - {{- include "nextcloud-mcp-server.selectorLabels" . | nindent 4 }} diff --git a/charts/nextcloud-mcp-server/templates/serviceaccount.yaml b/charts/nextcloud-mcp-server/templates/serviceaccount.yaml deleted file mode 100644 index e7c9701c..00000000 --- a/charts/nextcloud-mcp-server/templates/serviceaccount.yaml +++ /dev/null @@ -1,13 +0,0 @@ -{{- if .Values.serviceAccount.create -}} -apiVersion: v1 -kind: ServiceAccount -metadata: - name: {{ include "nextcloud-mcp-server.serviceAccountName" . }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.serviceAccount.annotations }} - annotations: - {{- toYaml . | nindent 4 }} - {{- end }} -automountServiceAccountToken: {{ .Values.serviceAccount.automount }} -{{- end }} diff --git a/charts/nextcloud-mcp-server/templates/servicemonitor.yaml b/charts/nextcloud-mcp-server/templates/servicemonitor.yaml deleted file mode 100644 index 13bd34cd..00000000 --- a/charts/nextcloud-mcp-server/templates/servicemonitor.yaml +++ /dev/null @@ -1,32 +0,0 @@ -{{- if and .Values.observability.metrics.enabled .Values.serviceMonitor.enabled }} -apiVersion: monitoring.coreos.com/v1 -kind: ServiceMonitor -metadata: - name: {{ include "nextcloud-mcp-server.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "nextcloud-mcp-server.labels" . | nindent 4 }} - {{- with .Values.serviceMonitor.labels }} - {{- toYaml . | nindent 4 }} - {{- end }} -spec: - selector: - matchLabels: - {{- include "nextcloud-mcp-server.selectorLabels" . | nindent 6 }} - endpoints: - - port: metrics - path: {{ .Values.observability.metrics.path }} - interval: {{ .Values.serviceMonitor.interval }} - scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }} - scheme: http - relabelings: - # Add namespace label - - sourceLabels: [__meta_kubernetes_namespace] - targetLabel: namespace - # Add pod label - - sourceLabels: [__meta_kubernetes_pod_name] - targetLabel: pod - # Add service label - - sourceLabels: [__meta_kubernetes_service_name] - targetLabel: service -{{- end }} diff --git a/charts/nextcloud-mcp-server/values.yaml b/charts/nextcloud-mcp-server/values.yaml deleted file mode 100644 index 03222e46..00000000 --- a/charts/nextcloud-mcp-server/values.yaml +++ /dev/null @@ -1,553 +0,0 @@ -# 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: "" diff --git a/docs/observability.md b/docs/observability.md index 5975781e..03b18453 100644 --- a/docs/observability.md +++ b/docs/observability.md @@ -27,15 +27,7 @@ Access metrics at: `http://localhost:9090/metrics` ### Kubernetes Deployment -Metrics are automatically scraped if you have Prometheus Operator installed: - -```bash -helm install nextcloud-mcp charts/nextcloud-mcp-server \ - --set observability.metrics.enabled=true \ - --set observability.tracing.enabled=true \ - --set observability.tracing.endpoint=http://opentelemetry-collector:4317 \ - --set serviceMonitor.enabled=true -``` +For Kubernetes deployments with Helm, see the [Helm chart repository](https://github.com/cbcoutinho/helm-charts) which includes ServiceMonitor and PrometheusRule support. ## Configuration @@ -55,28 +47,7 @@ helm install nextcloud-mcp charts/nextcloud-mcp-server \ ### Helm Chart Configuration -```yaml -observability: - metrics: - enabled: true - port: 9090 - path: /metrics - - tracing: - enabled: true - endpoint: "http://opentelemetry-collector:4317" - samplingRate: 1.0 - - logging: - format: json - level: INFO - includeTraceContext: true - -serviceMonitor: - enabled: true - interval: 30s - scrapeTimeout: 10s -``` +The Helm chart has moved to a [separate repository](https://github.com/cbcoutinho/helm-charts). See its `values.yaml` for observability configuration options including metrics, tracing, logging, and ServiceMonitor settings. ## Metrics @@ -206,7 +177,7 @@ sum(rate(mcp_nextcloud_api_requests_total{status_code!~"2.."}[5m])) by (app) - Vector sync queue >100 for >15min - Qdrant slow (p95 >500ms) for >10min -See `charts/nextcloud-mcp-server/templates/prometheusrule.yaml` for complete definitions. +See the [Helm chart repository](https://github.com/cbcoutinho/helm-charts) for PrometheusRule definitions. ## Troubleshooting diff --git a/docs/running.md b/docs/running.md index 0ddc47ad..b8a1bf9e 100644 --- a/docs/running.md +++ b/docs/running.md @@ -385,7 +385,7 @@ services: ### Scaling with Multiple Replicas -For higher load, use Docker Swarm or Kubernetes. See the [Helm Chart](../helm/) for Kubernetes deployments. +For higher load, use Docker Swarm or Kubernetes. See the [Helm chart](https://github.com/cbcoutinho/helm-charts) for Kubernetes deployments. --- diff --git a/pyproject.toml b/pyproject.toml index 2e5740ad..5ea8abef 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -93,21 +93,6 @@ version_provider = "uv" update_changelog_on_bump = true major_version_zero = true -# MCP server version files + Helm appVersion -version_files = [ - "charts/nextcloud-mcp-server/Chart.yaml:^appVersion:", -] - -# Ignore tags from other components -ignored_tag_formats = [ - "nextcloud-mcp-server-*", # Helm chart tags -] - -# Filter commits by scope (all scopes except helm) -[tool.commitizen.customize] -changelog_pattern = "^(feat|fix|docs|refactor|perf|test|build|ci|chore)(?!\\((?:helm)\\))(\\([^)]+\\))?(!)?:" -schema_pattern = "^(feat|fix|docs|refactor|perf|test|build|ci|chore)(?!\\((?:helm)\\))(\\([^)]+\\))?(!)?:\\s.+" - [tool.ruff.lint] extend-select = ["I", "PLC0415"] diff --git a/scripts/bump-helm.sh b/scripts/bump-helm.sh deleted file mode 100755 index f8086a9b..00000000 --- a/scripts/bump-helm.sh +++ /dev/null @@ -1,86 +0,0 @@ -#!/bin/bash -# Bump Helm chart version -set -euo pipefail - -# Parse optional --increment flag -INCREMENT="" -while [[ $# -gt 0 ]]; do - case $1 in - --increment) - INCREMENT="$2" - shift 2 - ;; - *) - echo "❌ Error: Unknown option: $1" >&2 - echo "Usage: $0 [--increment PATCH|MINOR|MAJOR]" >&2 - exit 1 - ;; - esac -done - -# Validate dependencies -command -v uv >/dev/null 2>&1 || { - echo "❌ Error: uv not found" >&2 - echo " Install from https://docs.astral.sh/uv/" >&2 - exit 1 -} - -# Validate Helm chart directory exists -if [ ! -d "charts/nextcloud-mcp-server" ]; then - echo "❌ Error: Must run from repository root (charts/ not found)" >&2 - exit 1 -fi - -cd charts/nextcloud-mcp-server - -# Validate Chart.yaml exists -if [ ! -f "Chart.yaml" ]; then - echo "❌ Error: Chart.yaml not found" >&2 - exit 1 -fi - -echo "Bumping Helm chart version..." -if [ -n "$INCREMENT" ]; then - echo " Forcing $INCREMENT bump" -fi - -# Build commitizen command -CZ_CMD="uv run cz --config .cz.toml bump --yes" -if [ -n "$INCREMENT" ]; then - CZ_CMD="$CZ_CMD --increment $INCREMENT" -fi - -# Run commitizen bump and capture output -if ! output=$($CZ_CMD 2>&1); then - cd ../.. - - # Check if this is the expected "no commits to bump" case - if echo "$output" | grep -q "\[NO_COMMITS_TO_BUMP\]"; then - echo "ℹ️ No commits eligible for version bump" >&2 - echo "$output" >&2 - exit 0 - fi - - # Otherwise, this is an actual error - echo "❌ Error: Version bump failed" >&2 - echo "$output" >&2 - echo "" >&2 - echo "Common causes:" >&2 - echo " - No commits with scope 'helm' since last version" >&2 - echo " - No conventional commits found (use feat(helm):, fix(helm):, etc.)" >&2 - echo " - Git working directory not clean" >&2 - exit 1 -fi - -echo "$output" -echo "" -echo "✓ Helm chart version bumped successfully" -echo " Updated: Chart.yaml:version" -echo " Tag format: nextcloud-mcp-server-\${version}" -echo " Note: appVersion stays at MCP server version" -echo "" -echo "Next steps:" -echo " cd ../.." -echo " git push --follow-tags" - -cd ../.. diff --git a/scripts/bump-mcp.sh b/scripts/bump-mcp.sh index 37d56eb8..f316f61d 100755 --- a/scripts/bump-mcp.sh +++ b/scripts/bump-mcp.sh @@ -65,7 +65,7 @@ fi echo "$output" echo "" echo "✓ MCP server version bumped successfully" -echo " Updated: pyproject.toml, Chart.yaml:appVersion" +echo " Updated: pyproject.toml" echo " Tag format: v\${version}" echo "" echo "Next steps:" diff --git a/scripts/test-commitizen-scopes.sh b/scripts/test-commitizen-scopes.sh index 6eb3b87d..1bbf6bee 100755 --- a/scripts/test-commitizen-scopes.sh +++ b/scripts/test-commitizen-scopes.sh @@ -6,8 +6,7 @@ echo "Testing commitizen scope filtering patterns..." echo # Regex patterns from configs -MCP_PATTERN='^(feat|fix|docs|refactor|perf|test|build|ci|chore)(?!\((?:helm|astrolabe)\))(\([^)]+\))?(!)?:' -HELM_PATTERN='^(feat|fix|docs|refactor|perf|test|build|ci|chore)\(helm\)(!)?:' +MCP_PATTERN='^(feat|fix|docs|refactor|perf|test|build|ci|chore)(?!\((?:astrolabe)\))(\([^)]+\))?(!)?:' ASTROLABE_PATTERN='^(feat|fix|docs|refactor|perf|test|build|ci|chore)\(astrolabe\)(!)?:' test_pattern() { @@ -31,9 +30,6 @@ run_test() { if test_pattern "$message" "$MCP_PATTERN"; then matched_components+=("mcp") fi - if test_pattern "$message" "$HELM_PATTERN"; then - matched_components+=("helm") - fi if test_pattern "$message" "$ASTROLABE_PATTERN"; then matched_components+=("astrolabe") fi @@ -62,7 +58,7 @@ run_test() { failed=0 passed=0 -# MCP server commits (any scope except helm/astrolabe) +# MCP server commits (any scope except astrolabe) run_test "feat: add new feature" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) run_test "feat(mcp): add API endpoint" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) run_test "fix(mcp): resolve authentication bug" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) @@ -71,11 +67,6 @@ run_test "fix(ci): update workflow" "mcp" && passed=$((passed+1)) || failed=$((f run_test "feat(api): add endpoint" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) run_test "ci: configure GitHub Actions" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) -# Helm chart commits -run_test "feat(helm): add resource limits" "helm" && passed=$((passed+1)) || failed=$((failed+1)) -run_test "fix(helm): correct values schema" "helm" && passed=$((passed+1)) || failed=$((failed+1)) -run_test "docs(helm): update deployment guide" "helm" && passed=$((passed+1)) || failed=$((failed+1)) - # Astrolabe commits run_test "feat(astrolabe): add dark mode" "astrolabe" && passed=$((passed+1)) || failed=$((failed+1)) run_test "fix(astrolabe): resolve UI bug" "astrolabe" && passed=$((passed+1)) || failed=$((failed+1)) @@ -83,11 +74,10 @@ run_test "perf(astrolabe): optimize rendering" "astrolabe" && passed=$((passed+1 # Breaking changes run_test "feat(mcp)!: breaking API change" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) -run_test "feat(helm)!: rename values" "helm" && passed=$((passed+1)) || failed=$((failed+1)) run_test "feat(astrolabe)!: remove deprecated feature" "astrolabe" && passed=$((passed+1)) || failed=$((failed+1)) # Edge cases -run_test "feat(invalid): test" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) # Any scope except helm/astrolabe → MCP +run_test "feat(invalid): test" "mcp" && passed=$((passed+1)) || failed=$((failed+1)) # Any scope except astrolabe → MCP run_test "random commit message" "none" && passed=$((passed+1)) || failed=$((failed+1)) # Not conventional commit run_test "feat (mcp): space before scope" "none" && passed=$((passed+1)) || failed=$((failed+1)) # Invalid format