Commit Graph
14 Commits
Author SHA1 Message Date
Chris CoutinhoandClaude Opus 4.8 d33832aba9 test: add Pact consumer contract for astrolabe credentials status (ADR-029)
Introduce consumer-driven contract testing between nextcloud-mcp-server and the
astrolabe Nextcloud app, published to the homelab Pact Broker and verified in CI.

- pact-python dev dep + `contract` pytest marker
- tests/contract/test_astrolabe_credentials_consumer.py: consumer pact for the
  background-sync *status* call (provisioned -> has_background_access:true,
  sync_type:"app_password", integer provisioned_at; unprovisioned -> false/null)
- tests/contract/test_mcp_provider_verification.py: env-gated Verifier harness
  for this server's /api/v1/* provider role (provider-state handlers stubbed
  pending astrolabe's published pacts)
- .github/workflows/pact.yml: join tailnet -> publish pacts -> provider verify
  -> can-i-deploy; broker steps skip when PACT_BROKER is unset (forks)
- docs/ADR-029-pact-contract-testing.md

Fix astrolabe_client.get_background_sync_status: it previously read a
non-existent `app_password` field (always reporting no-access). Rewrite it to
read the real status contract (has_background_access / sync_type /
provisioned_at) and drop the unsatisfiable get_user_app_password.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 20:22:07 +02:00
Chris CoutinhoandClaude Opus 4.8 2bbf4ed967 refactor(usage): address round-2 review on PR #871
- remove accidentally-committed .claude/scheduled_tasks.lock (Claude Code
  runtime artifact swept in by `git add -A`) and gitignore it; the rest
  of .claude/ stays tracked.
- store: cache UsageEventStore.shared() as a process-wide instance so the
  hot search path doesn't allocate a fresh wrapper per metered query (the
  wrapper is stateless beyond its storage handle).
- hooks: pass enabled=True directly (the outer guard already confirmed
  the flag) instead of re-reading settings.usage_metering_enabled.
- migration: document the no-TTL retention design (control-plane rollup
  owns the lifecycle; the data plane only appends).
- tests: assert the best-effort error path logs at WARNING (observability
  contract).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 15:28:24 +02:00
Chris CoutinhoandClaude Opus 4.6 146b622ebf fix: enable uvx/PyPI deployments without Docker assumptions
Two bugs made `uvx --from . nextcloud-mcp-server run` (and any pip install)
unusable outside Docker:

1. Dynaconf was configured with ignore_unknown_envvars=True and relied on
   settings.toml to declare the key schema. With no settings.toml in a wheel
   install, every env var (NEXTCLOUD_HOST, MCP_DEPLOYMENT_MODE, ...) was
   silently dropped. Moved the schema into a Python _DEFAULTS dict passed
   directly to Dynaconf, kept settings.toml as an optional external override
   (renamed to settings.toml.example, gitignored), and pointed docker-compose
   at the example file.

2. Token SQLite DB defaulted to /app/data/tokens.db in multiple places
   (auth/storage.py, migrations.py, alembic/env.py, cli.py db subcommands),
   which blew up at uvicorn startup with FileNotFoundError on non-Docker
   hosts. Replaced with a new config.get_token_db_path() helper that
   resolves TOKEN_STORAGE_DB if explicitly set, otherwise allocates a
   per-process tempfile cleaned up at interpreter exit via atexit — mirroring
   the "ephemeral by default" pattern used for QDRANT_LOCATION=:memory:.

Containers are unaffected: docker-compose services now explicitly set
TOKEN_STORAGE_DB=/app/data/tokens.db (the fourth service that was missing
this pin has been brought in line with the other three).

Verified end-to-end in an isolated /tmp venv: env-var-only startup, Alembic
migrations run against the tempfile, Application startup complete, /health/live
returns 200, tempfile deleted on SIGTERM. Unit tests (464) + ruff + ty pass.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 20:11:23 +02:00
Chris CoutinhoandClaude Opus 4.6 c8e4cbe825 feat: implement dynaconf configuration management (ADR-024 phases 1-3)
Replace ~80 manual os.getenv() calls in config.py with dynaconf-backed
configuration, enabling TOML file-based config alongside existing env
var support. Zero breaking changes — Settings dataclass interface and
all consumers unchanged.

Phase 1: Create settings.toml with all config keys and defaults,
.secrets.toml.example template, update .gitignore, initialize Dynaconf
instance with envvar_prefix=False and environment section switching.

Phase 2: Wire adapter — replace os.getenv() with _dynaconf.get() in
get_settings(), get_document_processor_config(), and deprecation/
dependency resolution helpers. Automatic type coercion eliminates ~30
manual int()/float()/.lower()=="true" patterns.

Phase 3: Add 12 declarative validators for port ranges, positive
integers, enum constraints, and float ranges. Remove redundant negative
overlap check from Settings.__post_init__.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-07 09:22:19 +02:00
Chris CoutinhoandClaude c272ddd82d feat: implement RAG evaluation framework with CLI tooling
- Add ADR-013 documenting RAG evaluation architecture
- Implement two-part evaluation: Context Recall (retrieval) + Answer Correctness (generation)
- Create Click CLI for ground truth generation and corpus upload
- Add pytest fixtures and tests for retrieval/generation quality
- Use BeIR/nfcorpus dataset with 5 selected test queries
- Support Ollama and Anthropic LLM providers
- Generate synthetic ground truth answers offline
- Add comprehensive documentation in tests/rag_evaluation/README.md

The framework separates one-time setup (generate/upload) from test execution,
making tests much faster (~6-12 min vs ~15-25 min per run).

Tests are manual only (not in CI) and require external LLM access.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-15 23:11:21 +01:00
Chris Coutinho 619ba5684d build: Add ./worktrees to .gitignore 2025-11-12 08:27:33 +01:00
Chris CoutinhoandClaude adde0e5623 fix: improve webapp tab UI with CSS Grid and viewport-filling container
Fixes layout issues on the webhooks admin tab:
- Add min-height to container to fill viewport consistently
- Use CSS Grid to overlay tab panes without jumpiness
- Add smooth htmx fade transitions for content swaps
- Adjust vector sync polling interval from 3s to 10s
- Add .playwright-mcp/ to gitignore for test screenshots

The CSS Grid approach allows tabs to overlay without absolute positioning,
preventing content cutoff while maintaining smooth transitions without
container resizing jumps.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-11 23:07:44 +01:00
Chris CoutinhoandClaude a6e5f3d8ff refactor: simplify OpenTelemetry tracing configuration
Simplifies the OpenTelemetry tracing setup by removing the redundant
OTEL_ENABLED flag and using the presence of OTEL_EXPORTER_OTLP_ENDPOINT
to determine if tracing should be enabled. This follows the standard
OpenTelemetry environment variable conventions more closely.

Changes:
- Remove OTEL_ENABLED/tracing_enabled flag in favor of checking if
  OTEL_EXPORTER_OTLP_ENDPOINT is set
- Add OTEL_EXPORTER_VERIFY_SSL configuration option for OTLP endpoints
  with self-signed certificates (defaults to false for development)
- Move HTTPXClientInstrumentor initialization to module level to ensure
  httpx calls are traced across all Nextcloud API requests
- Add tracing spans to vector sync operations (scan_user_documents)
- Fix authorization header logging to only warn about missing headers
  in OAuth mode (BasicAuth mode doesn't use Authorization headers)
- Update observability documentation to reflect simplified configuration
- Refactor Dockerfile to use --no-editable flag for uv sync

Breaking changes:
- OTEL_ENABLED environment variable is removed
- Tracing is now automatically enabled when OTEL_EXPORTER_OTLP_ENDPOINT
  is set

Migration guide:
- Remove OTEL_ENABLED=true from environment configuration
- Tracing will be enabled automatically if OTEL_EXPORTER_OTLP_ENDPOINT
  is configured

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-10 22:48:37 +01:00
Chris Coutinho 83917b3786 perf(notes): Improve notes search performance using async iterators 2025-10-18 22:02:19 +02:00
Chris Coutinho 7004104873 test: Fix multi-user tests 2025-10-15 02:11:17 +02:00
Chris Coutinho 33b962a7fc test: Setup interactive browser test 2025-10-14 01:23:30 +02:00
Neovasky 9e96999f02 feat(webdav): add complete file system support
- Add nc_webdav_list_directory tool for browsing any NextCloud directory
  - Add nc_webdav_read_file tool with automatic text/binary content handling
  - Add nc_webdav_write_file tool supporting text and base64 binary content
  - Add nc_webdav_create_directory tool for creating directories
  - Add nc_webdav_delete_resource tool for deleting files and directories
  - Extend WebDAV client beyond Notes attachments to general file operations
  - Add XML parsing for WebDAV PROPFIND responses with metadata extraction
  - Improve type annotations throughout codebase for better IDE support
  - Add comprehensive documentation with usage examples

  This transforms the NextCloud MCP server from a limited Notes/Tables tool
  into a full-featured file system interface, enabling complete NextCloud
  file management through LLM interactions.
2025-07-25 03:15:52 -04:00
Chris Coutinho b0012d6e4a wip Move testing to container 2025-05-10 12:47:10 +02:00
Chris Coutinho 0d8666a2d7 Initial commit 2025-05-04 23:24:55 +02:00