feat: implement ADR-009 - refactor semantic search to use generic semantic:read scope

This implements ADR-009, which documents the decision to use a generic
`semantic:read` OAuth scope instead of requiring all app-specific scopes
for semantic search functionality.

Changes:
- Created new `nextcloud_mcp_server/models/semantic.py` with semantic search models
  - SemanticSearchResult (with new doc_type field for multi-app support)
  - SemanticSearchResponse
  - SamplingSearchResponse
  - VectorSyncStatusResponse

- Created new `nextcloud_mcp_server/server/semantic.py` with semantic search tools
  - nc_semantic_search (renamed from nc_notes_semantic_search)
  - nc_semantic_search_answer (renamed from nc_notes_semantic_search_answer)
  - nc_get_vector_sync_status (renamed from nc_notes_get_vector_sync_status)
  - All tools now use @require_scopes("semantic:read") instead of "notes:read"

- Updated `nextcloud_mcp_server/server/notes.py`
  - Removed semantic search tools (moved to semantic.py)
  - Removed semantic search model imports
  - Removed unused MCP imports (ModelHint, ModelPreferences, etc.)

- Updated `nextcloud_mcp_server/models/notes.py`
  - Removed semantic search models (moved to semantic.py)

- Updated `nextcloud_mcp_server/app.py`
  - Import configure_semantic_tools
  - Register semantic tools when VECTOR_SYNC_ENABLED=true

- Updated `nextcloud_mcp_server/server/__init__.py`
  - Export configure_semantic_tools

- Updated tests
  - tests/integration/test_sampling.py: Use new tool names
  - tests/unit/test_response_models.py: Import from semantic.py, add doc_type field

Architecture:
- Semantic search is now a cross-app feature, not tied to Notes
- Uses dual-phase authorization: semantic:read scope + per-document verification
- Supports future multi-app indexing (notes, calendar, deck, files, contacts)

Test results:
- All 69 unit tests passing
- All 5 smoke tests passing

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Chris Coutinho
2025-11-09 05:53:53 +01:00
parent 31799ffd9a
commit 4b026e9aa0
8 changed files with 576 additions and 512 deletions
+6 -1
View File
@@ -6,8 +6,10 @@ from nextcloud_mcp_server.models.notes import (
CreateNoteResponse,
Note,
NoteSearchResult,
SamplingSearchResponse,
SearchNotesResponse,
)
from nextcloud_mcp_server.models.semantic import (
SamplingSearchResponse,
SemanticSearchResult,
)
@@ -131,6 +133,7 @@ def test_sampling_search_response_with_answer():
sources = [
SemanticSearchResult(
id=1,
doc_type="note",
title="Python Guide",
category="Development",
excerpt="Use async/await for asynchronous programming",
@@ -140,6 +143,7 @@ def test_sampling_search_response_with_answer():
),
SemanticSearchResult(
id=2,
doc_type="note",
title="Best Practices",
category="Development",
excerpt="Always use context managers with async operations",
@@ -189,6 +193,7 @@ def test_sampling_search_response_fallback():
sources = [
SemanticSearchResult(
id=1,
doc_type="note",
title="Note 1",
category="Work",
excerpt="Some content",