feat(config): consolidate configuration with smart dependency resolution (ADR-021)
Simplifies configuration by consolidating overlapping settings and adding automatic dependency resolution. This makes semantic search configuration significantly easier for users while maintaining 100% backward compatibility. ## Key Changes ### Variable Renaming (Backward Compatible) - `VECTOR_SYNC_ENABLED` → `ENABLE_SEMANTIC_SEARCH` (old name still works) - `ENABLE_OFFLINE_ACCESS` → `ENABLE_BACKGROUND_OPERATIONS` (old name still works) - Deprecation warnings logged when old names used - Old names will be removed in v1.0.0 ### Smart Dependency Resolution - `ENABLE_SEMANTIC_SEARCH` automatically enables background operations in multi-user modes - No need to set both `ENABLE_OFFLINE_ACCESS` and `VECTOR_SYNC_ENABLED` anymore - Single-user mode doesn't auto-enable background ops (not needed) ### Explicit Mode Selection (Optional) - New `MCP_DEPLOYMENT_MODE` environment variable - Valid values: single_user_basic, multi_user_basic, oauth_single_audience, oauth_token_exchange, smithery - Removes ambiguity about which deployment mode is active - Falls back to auto-detection if not set (existing behavior) ### Configuration Templates - Reorganized `env.sample` by deployment mode with clear sections - Added mode-specific quick-start templates: - `env.sample.single-user` - Simplest configuration - `env.sample.oauth-multi-user` - Recommended multi-user - `env.sample.oauth-advanced` - Token exchange mode ## Implementation Details ### Files Modified - `nextcloud_mcp_server/config.py` - Smart dependency resolution helpers - `nextcloud_mcp_server/config_validators.py` - Simplified validation, explicit mode - `tests/unit/test_config_validators.py` - 19 new tests (60 total, all passing) - `env.sample` - Reorganized by deployment mode - `docs/configuration.md` - Complete rewrite with consolidated approach - `docs/troubleshooting.md` - New consolidation troubleshooting section - `README.md` - Updated variable references ### New Files - `docs/ADR-021-configuration-consolidation.md` - Architecture decision record - `docs/configuration-migration-v2.md` - Comprehensive migration guide - `env.sample.single-user` - Single-user quick-start template - `env.sample.oauth-multi-user` - OAuth multi-user quick-start template - `env.sample.oauth-advanced` - Token exchange quick-start template ## User Impact ### Before (Confusing) ```bash ENABLE_OFFLINE_ACCESS=true # Why both? VECTOR_SYNC_ENABLED=true # What's the relationship? ``` ### After (Simplified) ```bash MCP_DEPLOYMENT_MODE=oauth_single_audience # Explicit (optional) ENABLE_SEMANTIC_SEARCH=true # Auto-enables background ops! ``` ### Benefits - 📉 2 fewer variables to understand for semantic search - 📋 Clear intent ("I want semantic search") - 🎯 Explicit mode declaration available - 🔄 100% backward compatible - ✅ All 265 unit tests passing ## Testing - All 60 config validation tests passing - 10 new tests for configuration consolidation - 9 new tests for explicit mode selection - Full unit test suite: 265 tests passing - Backward compatibility verified ## Migration Users can migrate at their own pace. Old variable names continue working with deprecation warnings. See docs/configuration-migration-v2.md for detailed migration instructions. Related: ADR-021 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -127,7 +127,7 @@ This enables natural language queries and helps discover related content across
|
|||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
> **Semantic Search is experimental and opt-in:**
|
> **Semantic Search is experimental and opt-in:**
|
||||||
> - Disabled by default (`VECTOR_SYNC_ENABLED=false`)
|
> - Disabled by default (`ENABLE_SEMANTIC_SEARCH=false`)
|
||||||
> - Currently supports Notes app only (multi-app support planned)
|
> - Currently supports Notes app only (multi-app support planned)
|
||||||
> - Requires additional infrastructure: vector database + embedding service
|
> - Requires additional infrastructure: vector database + embedding service
|
||||||
> - Answer generation (`nc_semantic_search_answer`) requires MCP client sampling support
|
> - Answer generation (`nc_semantic_search_answer`) requires MCP client sampling support
|
||||||
|
|||||||
@@ -0,0 +1,391 @@
|
|||||||
|
# ADR-021: Configuration Consolidation and Simplification
|
||||||
|
|
||||||
|
**Status:** Accepted
|
||||||
|
**Date:** 2025-12-21
|
||||||
|
**Deciders:** Development Team
|
||||||
|
**Related:** ADR-020 (Deployment Modes), ADR-002 (Vector Sync), ADR-004 (Progressive Consent)
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
The configuration system has grown complex with overlapping concerns that make it difficult for users to switch between deployment modes and understand configuration dependencies.
|
||||||
|
|
||||||
|
### Problems Identified
|
||||||
|
|
||||||
|
1. **Confusing variable names don't reflect purpose**:
|
||||||
|
- `ENABLE_OFFLINE_ACCESS` - Actually controls refresh token storage for background operations, not general "offline" capabilities
|
||||||
|
- `VECTOR_SYNC_ENABLED` - Controls semantic search background indexing (implementation detail, not user-facing feature name)
|
||||||
|
- Users struggle to understand what these variables actually control
|
||||||
|
|
||||||
|
2. **Redundant configuration requirements**:
|
||||||
|
- Multi-user semantic search requires setting BOTH `ENABLE_OFFLINE_ACCESS=true` AND `VECTOR_SYNC_ENABLED=true`
|
||||||
|
- The dependency is one-way (semantic search needs background ops, but background ops don't need semantic search)
|
||||||
|
- Users must understand internal implementation details to configure a user-facing feature
|
||||||
|
|
||||||
|
3. **Implicit mode detection creates ambiguity**:
|
||||||
|
- Five deployment modes detected via priority-based logic
|
||||||
|
- Users can't easily predict which mode will activate
|
||||||
|
- Configuration errors don't clearly indicate which mode triggered the requirement
|
||||||
|
|
||||||
|
4. **OIDC_CLIENT_ID vs NEXTCLOUD_OIDC_CLIENT_ID confusion**:
|
||||||
|
- Investigation revealed these are NOT actually overlapping (`OIDC_CLIENT_ID` is test-only)
|
||||||
|
- However, their similar names create confusion
|
||||||
|
|
||||||
|
### Current Configuration Complexity
|
||||||
|
|
||||||
|
**Example: Multi-user OAuth with semantic search**:
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_OFFLINE_ACCESS=true # Why is this needed?
|
||||||
|
VECTOR_SYNC_ENABLED=true # And this separately?
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
```
|
||||||
|
|
||||||
|
Users must understand:
|
||||||
|
- Semantic search requires background token storage (ENABLE_OFFLINE_ACCESS)
|
||||||
|
- Background token storage requires encryption keys
|
||||||
|
- The relationship between ENABLE_OFFLINE_ACCESS and VECTOR_SYNC_ENABLED
|
||||||
|
- Which deployment mode these settings will activate
|
||||||
|
|
||||||
|
## Decision
|
||||||
|
|
||||||
|
We consolidate overlapping functionality and add explicit mode selection while maintaining 100% backward compatibility.
|
||||||
|
|
||||||
|
### 1. Automatic Dependency Resolution
|
||||||
|
|
||||||
|
**Make ENABLE_SEMANTIC_SEARCH the primary control** that automatically enables required dependencies:
|
||||||
|
|
||||||
|
**New behavior**:
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def enable_background_operations(self) -> bool:
|
||||||
|
"""Background operations - auto-enabled by semantic search in multi-user modes."""
|
||||||
|
# Check new names first
|
||||||
|
explicit = os.getenv("ENABLE_BACKGROUND_OPERATIONS", "").lower() == "true"
|
||||||
|
# Fall back to old name with deprecation warning
|
||||||
|
legacy = os.getenv("ENABLE_OFFLINE_ACCESS", "").lower() == "true"
|
||||||
|
# Auto-enable if semantic search needs it
|
||||||
|
auto_enabled = self.enable_semantic_search and self.is_multi_user_mode()
|
||||||
|
|
||||||
|
return explicit or legacy or auto_enabled
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enable_semantic_search(self) -> bool:
|
||||||
|
"""Semantic search - renamed from VECTOR_SYNC_ENABLED."""
|
||||||
|
new_value = os.getenv("ENABLE_SEMANTIC_SEARCH", "").lower() == "true"
|
||||||
|
old_value = os.getenv("VECTOR_SYNC_ENABLED", "").lower() == "true"
|
||||||
|
return new_value or old_value
|
||||||
|
```
|
||||||
|
|
||||||
|
**Result**: Users set `ENABLE_SEMANTIC_SEARCH=true` and the system automatically enables background token storage when needed.
|
||||||
|
|
||||||
|
### 2. Explicit Mode Selection (Optional)
|
||||||
|
|
||||||
|
Add `MCP_DEPLOYMENT_MODE` environment variable to remove detection ambiguity:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Optional: Explicitly declare deployment mode
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# Valid values: single_user_basic, multi_user_basic,
|
||||||
|
# oauth_single_audience, oauth_token_exchange, smithery
|
||||||
|
```
|
||||||
|
|
||||||
|
**Detection logic**:
|
||||||
|
1. If `MCP_DEPLOYMENT_MODE` is set → validate and use it
|
||||||
|
2. Otherwise → use priority-based auto-detection (existing behavior)
|
||||||
|
3. Validate explicit mode doesn't conflict with detected mode
|
||||||
|
|
||||||
|
### 3. Simplified User Experience
|
||||||
|
|
||||||
|
**Before**:
|
||||||
|
```bash
|
||||||
|
# Multi-user OAuth with semantic search
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_OFFLINE_ACCESS=true # Confusing
|
||||||
|
VECTOR_SYNC_ENABLED=true # Why both?
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
```
|
||||||
|
|
||||||
|
**After**:
|
||||||
|
```bash
|
||||||
|
# Multi-user OAuth with semantic search
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience # Explicit (optional)
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Auto-enables background ops
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefits**:
|
||||||
|
- 2 fewer variables to understand/set
|
||||||
|
- Clear intent ("I want semantic search")
|
||||||
|
- Explicit mode declaration (optional)
|
||||||
|
- All existing configs continue working
|
||||||
|
|
||||||
|
### 4. Variable Naming Strategy
|
||||||
|
|
||||||
|
**Deprecated (but still functional)**:
|
||||||
|
- `ENABLE_OFFLINE_ACCESS` → Renamed to `ENABLE_BACKGROUND_OPERATIONS`
|
||||||
|
- `VECTOR_SYNC_ENABLED` → Renamed to `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
|
||||||
|
**No change needed**:
|
||||||
|
- `VECTOR_SYNC_SCAN_INTERVAL` - Implementation tuning parameter (keep as-is)
|
||||||
|
- `VECTOR_SYNC_PROCESSOR_WORKERS` - Implementation tuning parameter (keep as-is)
|
||||||
|
- `VECTOR_SYNC_QUEUE_MAX_SIZE` - Implementation tuning parameter (keep as-is)
|
||||||
|
|
||||||
|
**Rationale**: Only rename user-facing feature flags, not internal tuning parameters.
|
||||||
|
|
||||||
|
### 5. Backward Compatibility
|
||||||
|
|
||||||
|
**Support both old and new names for minimum 2 major versions**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
@property
|
||||||
|
def enable_semantic_search(self) -> bool:
|
||||||
|
new_value = os.getenv("ENABLE_SEMANTIC_SEARCH", "").lower() == "true"
|
||||||
|
old_value = os.getenv("VECTOR_SYNC_ENABLED", "").lower() == "true"
|
||||||
|
|
||||||
|
if new_value and old_value:
|
||||||
|
logger.warning(
|
||||||
|
"Both ENABLE_SEMANTIC_SEARCH and VECTOR_SYNC_ENABLED are set. "
|
||||||
|
"Using ENABLE_SEMANTIC_SEARCH. VECTOR_SYNC_ENABLED is deprecated."
|
||||||
|
)
|
||||||
|
|
||||||
|
if old_value and not new_value:
|
||||||
|
logger.warning(
|
||||||
|
"VECTOR_SYNC_ENABLED is deprecated. Please use ENABLE_SEMANTIC_SEARCH instead."
|
||||||
|
)
|
||||||
|
|
||||||
|
return new_value or old_value
|
||||||
|
```
|
||||||
|
|
||||||
|
**Deprecation timeline**:
|
||||||
|
- v0.6.0: Add new variables, deprecate old ones (both work with warnings)
|
||||||
|
- v1.0.0: Remove old variables (breaking change, well-announced)
|
||||||
|
- Minimum 2 major versions of support (12+ months)
|
||||||
|
|
||||||
|
## Consequences
|
||||||
|
|
||||||
|
### Positive
|
||||||
|
|
||||||
|
1. **Reduced cognitive load**: Users set `ENABLE_SEMANTIC_SEARCH=true` instead of understanding internal dependencies
|
||||||
|
2. **Clearer intent**: Variable names reflect user-facing features, not implementation details
|
||||||
|
3. **Explicit mode control**: `MCP_DEPLOYMENT_MODE` removes detection ambiguity
|
||||||
|
4. **Better onboarding**: New users see simpler configuration in env.sample
|
||||||
|
5. **Improved error messages**: Validation can suggest "set MCP_DEPLOYMENT_MODE=X" instead of relying on implicit detection
|
||||||
|
6. **No breaking changes**: All existing configurations continue working
|
||||||
|
|
||||||
|
### Negative
|
||||||
|
|
||||||
|
1. **Transition period complexity**: Both old and new names supported for 2+ versions
|
||||||
|
2. **Documentation burden**: All docs must be updated to show new approach
|
||||||
|
3. **Test coverage expansion**: Must test both old and new variable names in all modes
|
||||||
|
4. **Migration effort**: Existing deployments should eventually migrate (optional but recommended)
|
||||||
|
|
||||||
|
### Neutral
|
||||||
|
|
||||||
|
1. **Same functionality**: No new features, just better organization
|
||||||
|
2. **Same validation**: Underlying requirements unchanged (e.g., semantic search still needs Qdrant)
|
||||||
|
3. **Same performance**: No runtime performance impact
|
||||||
|
|
||||||
|
## Implementation
|
||||||
|
|
||||||
|
### Phase 1: Configuration Consolidation (v0.6.0)
|
||||||
|
|
||||||
|
**Files to modify**:
|
||||||
|
- `nextcloud_mcp_server/config.py` - Add property-based deprecation with auto-enablement
|
||||||
|
- `nextcloud_mcp_server/config_validators.py` - Simplify validation (semantic search no longer requires explicit background operations setting)
|
||||||
|
- `nextcloud_mcp_server/app.py` - Add informative logging for auto-enablement
|
||||||
|
- `tests/unit/test_config_validators.py` - Add auto-enablement tests
|
||||||
|
- `docs/configuration-migration-v2.md` - Create migration guide
|
||||||
|
|
||||||
|
**Key changes**:
|
||||||
|
1. `enable_background_operations` property auto-enables when `enable_semantic_search=true` in multi-user modes
|
||||||
|
2. `enable_semantic_search` property accepts both `ENABLE_SEMANTIC_SEARCH` and `VECTOR_SYNC_ENABLED`
|
||||||
|
3. Smart logging when auto-enablement occurs or deprecated variables used
|
||||||
|
4. Validation simplified to remove redundant requirements
|
||||||
|
|
||||||
|
### Phase 2: Explicit Mode Selection (v0.6.0)
|
||||||
|
|
||||||
|
**Files to modify**:
|
||||||
|
- `nextcloud_mcp_server/config.py` - Add `deployment_mode` field
|
||||||
|
- `nextcloud_mcp_server/config_validators.py` - Check explicit mode first, fall back to auto-detection
|
||||||
|
- `tests/unit/test_config_validators.py` - Test mode override and conflict detection
|
||||||
|
- `docs/configuration.md` - Document mode selection
|
||||||
|
|
||||||
|
**Key changes**:
|
||||||
|
1. Add `MCP_DEPLOYMENT_MODE` environment variable (optional)
|
||||||
|
2. Mode detection checks explicit mode first, then auto-detects
|
||||||
|
3. Validate explicit mode doesn't conflict with detected mode
|
||||||
|
4. Better error messages referencing explicit mode setting
|
||||||
|
|
||||||
|
### Phase 3: env.sample Reorganization (v0.6.0)
|
||||||
|
|
||||||
|
**Files to create/modify**:
|
||||||
|
- `env.sample` - Reorganize by deployment mode
|
||||||
|
- `env.sample.single-user` - Simplest config template
|
||||||
|
- `env.sample.oauth-multi-user` - Multi-user template showing consolidation
|
||||||
|
- `env.sample.oauth-advanced` - Token exchange mode template
|
||||||
|
- `README.md` - Update Quick Start to reference templates
|
||||||
|
|
||||||
|
**Key changes**:
|
||||||
|
1. Group related settings by deployment mode
|
||||||
|
2. Show simplified configuration (only essential variables)
|
||||||
|
3. Document automatic dependencies inline
|
||||||
|
4. Provide mode-specific quick-start templates
|
||||||
|
|
||||||
|
### Phase 4: Documentation Updates (v0.7.0)
|
||||||
|
|
||||||
|
**Files to modify**:
|
||||||
|
- `docs/configuration.md` - Lead with consolidated approach
|
||||||
|
- `docs/authentication.md` - Update mode guidance with `MCP_DEPLOYMENT_MODE`
|
||||||
|
- `docs/troubleshooting.md` - Add consolidation troubleshooting section
|
||||||
|
- `docs/configuration-migration-v2.md` - Expand with comprehensive examples
|
||||||
|
- `docs/ADR-020-deployment-modes-and-configuration-validation.md` - Update configuration matrix
|
||||||
|
- All other ADRs - Update variable references
|
||||||
|
|
||||||
|
**Key changes**:
|
||||||
|
1. Update all examples to use new variable names
|
||||||
|
2. Add before/after migration examples
|
||||||
|
3. Document automatic dependency resolution
|
||||||
|
4. Add mode selection decision tree diagram
|
||||||
|
|
||||||
|
## Validation Strategy
|
||||||
|
|
||||||
|
### Test Coverage Requirements
|
||||||
|
|
||||||
|
**Backward compatibility tests**:
|
||||||
|
- Old variable names still work (ENABLE_OFFLINE_ACCESS, VECTOR_SYNC_ENABLED)
|
||||||
|
- New variable names work (ENABLE_BACKGROUND_OPERATIONS, ENABLE_SEMANTIC_SEARCH)
|
||||||
|
- Setting both old and new triggers deprecation warning but works correctly
|
||||||
|
- All 41 existing config validation tests pass
|
||||||
|
|
||||||
|
**Auto-enablement tests**:
|
||||||
|
- `ENABLE_SEMANTIC_SEARCH=true` in OAuth mode → `enable_background_operations=true`
|
||||||
|
- `ENABLE_SEMANTIC_SEARCH=true` in single-user mode → `enable_background_operations=false` (not needed)
|
||||||
|
- `ENABLE_SEMANTIC_SEARCH=false` → `enable_background_operations=false` (unless explicitly set)
|
||||||
|
|
||||||
|
**Mode selection tests**:
|
||||||
|
- `MCP_DEPLOYMENT_MODE=oauth_single_audience` → mode correctly detected
|
||||||
|
- `MCP_DEPLOYMENT_MODE` conflicts with detected mode → validation error
|
||||||
|
- No `MCP_DEPLOYMENT_MODE` → auto-detection works as before
|
||||||
|
|
||||||
|
## Success Metrics
|
||||||
|
|
||||||
|
**Immediate** (v0.6.0 release):
|
||||||
|
- Zero breaking changes in existing deployments
|
||||||
|
- All 41 config validation tests pass
|
||||||
|
- New users report clearer configuration process
|
||||||
|
|
||||||
|
**Medium-term** (6 months after v0.6.0):
|
||||||
|
- 80% of new deployments use new variable names
|
||||||
|
- Mode selection errors decrease by 50%
|
||||||
|
- Support requests about configuration decrease
|
||||||
|
|
||||||
|
**Long-term** (12+ months):
|
||||||
|
- 90% of deployments migrated to new names
|
||||||
|
- Old variable names can be safely removed in v1.0.0
|
||||||
|
- Configuration-related issues in issue tracker decrease
|
||||||
|
|
||||||
|
## Alternatives Considered
|
||||||
|
|
||||||
|
### Alternative 1: Just Rename Variables
|
||||||
|
|
||||||
|
**Rejected**: User feedback: "There's no reason to just rename variables without consolidating functionality"
|
||||||
|
|
||||||
|
This would make names clearer but wouldn't reduce the number of variables users need to set. The real problem is requiring users to set both ENABLE_OFFLINE_ACCESS and VECTOR_SYNC_ENABLED when they just want semantic search.
|
||||||
|
|
||||||
|
### Alternative 2: Remove ENABLE_OFFLINE_ACCESS Entirely
|
||||||
|
|
||||||
|
**Rejected**: Advanced users need background operations without semantic search
|
||||||
|
|
||||||
|
Some deployments might want background token storage for future features (background Deck sync, background Calendar sync, etc.) without enabling semantic search. Keeping ENABLE_BACKGROUND_OPERATIONS (renamed) allows this.
|
||||||
|
|
||||||
|
### Alternative 3: Always Auto-Enable Background Operations
|
||||||
|
|
||||||
|
**Rejected**: Single-user mode doesn't need background token storage
|
||||||
|
|
||||||
|
Auto-enablement is only needed in multi-user modes. Single-user mode uses a shared client with BasicAuth, so background token storage is unnecessary. Always enabling it would waste resources and create confusing log messages.
|
||||||
|
|
||||||
|
### Alternative 4: Require All New Names Immediately
|
||||||
|
|
||||||
|
**Rejected**: Breaking change would affect all existing deployments
|
||||||
|
|
||||||
|
Forcing migration to new variable names in v0.6.0 would break every existing deployment. Supporting both old and new names with deprecation warnings provides a smooth migration path.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [ADR-020: Deployment Modes and Configuration Validation](ADR-020-deployment-modes-and-configuration-validation.md)
|
||||||
|
- [ADR-002: Vector Sync Authentication](ADR-002-vector-sync-authentication.md)
|
||||||
|
- [ADR-004: Progressive Consent](ADR-004-mcp-application-oauth.md)
|
||||||
|
- [Issue: Configuration complexity for multi-user semantic search](https://github.com/cbcoutinho/nextcloud-mcp-server/issues/XXX)
|
||||||
|
|
||||||
|
## Migration Examples
|
||||||
|
|
||||||
|
### Example 1: Single-User BasicAuth with Semantic Search
|
||||||
|
|
||||||
|
**Before**:
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
QDRANT_LOCATION=:memory:
|
||||||
|
```
|
||||||
|
|
||||||
|
**After** (optional migration):
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Renamed
|
||||||
|
QDRANT_LOCATION=:memory:
|
||||||
|
# Note: Background operations NOT auto-enabled (not needed in single-user mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 2: Multi-User OAuth with Semantic Search
|
||||||
|
|
||||||
|
**Before**:
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
```
|
||||||
|
|
||||||
|
**After** (simplified):
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience # Explicit (optional)
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Auto-enables background operations
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
# Note: ENABLE_OFFLINE_ACCESS no longer needed (auto-enabled)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Example 3: Multi-User OAuth WITHOUT Semantic Search
|
||||||
|
|
||||||
|
**Before**:
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_OFFLINE_ACCESS=true # For future background features
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
```
|
||||||
|
|
||||||
|
**After** (optional migration):
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
ENABLE_BACKGROUND_OPERATIONS=true # Renamed for clarity
|
||||||
|
TOKEN_ENCRYPTION_KEY=<key>
|
||||||
|
TOKEN_STORAGE_DB=/path/to/tokens.db
|
||||||
|
```
|
||||||
@@ -0,0 +1,564 @@
|
|||||||
|
# Configuration Migration Guide v2
|
||||||
|
|
||||||
|
**Version:** v0.58.0
|
||||||
|
**Status:** Active
|
||||||
|
**Related ADR:** [ADR-021: Configuration Consolidation and Simplification](ADR-021-configuration-consolidation.md)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
This guide helps you migrate from the old configuration variables to the new consolidated approach introduced in v0.58.0.
|
||||||
|
|
||||||
|
**Key Changes:**
|
||||||
|
- `VECTOR_SYNC_ENABLED` → `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
- `ENABLE_OFFLINE_ACCESS` → `ENABLE_BACKGROUND_OPERATIONS`
|
||||||
|
- New: `MCP_DEPLOYMENT_MODE` for explicit mode selection
|
||||||
|
- Automatic dependency resolution: semantic search auto-enables background operations
|
||||||
|
|
||||||
|
**Backward Compatibility:**
|
||||||
|
- Old variable names still work in v0.58.0+
|
||||||
|
- Deprecation warnings logged when old names used
|
||||||
|
- Old names will be removed in v1.0.0
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Reference: Variable Name Changes
|
||||||
|
|
||||||
|
| Old Name | New Name | Status |
|
||||||
|
|----------|----------|--------|
|
||||||
|
| `VECTOR_SYNC_ENABLED` | `ENABLE_SEMANTIC_SEARCH` | Deprecated |
|
||||||
|
| `ENABLE_OFFLINE_ACCESS` | `ENABLE_BACKGROUND_OPERATIONS` | Deprecated |
|
||||||
|
| N/A (auto-detected) | `MCP_DEPLOYMENT_MODE` | New (optional) |
|
||||||
|
|
||||||
|
**Tuning parameters unchanged:**
|
||||||
|
- `VECTOR_SYNC_SCAN_INTERVAL` - Keep as-is
|
||||||
|
- `VECTOR_SYNC_PROCESSOR_WORKERS` - Keep as-is
|
||||||
|
- `VECTOR_SYNC_QUEUE_MAX_SIZE` - Keep as-is
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration Scenarios
|
||||||
|
|
||||||
|
### Scenario 1: Single-User BasicAuth with Semantic Search
|
||||||
|
|
||||||
|
**Before (v0.57.x):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
QDRANT_LOCATION=:memory:
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v0.58.0+):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration (recommended)
|
||||||
|
MCP_DEPLOYMENT_MODE=single_user_basic
|
||||||
|
|
||||||
|
# Updated variable name
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Previously VECTOR_SYNC_ENABLED
|
||||||
|
|
||||||
|
QDRANT_LOCATION=:memory:
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Changed:**
|
||||||
|
- ✅ Renamed `VECTOR_SYNC_ENABLED` to `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
- ✅ Added optional `MCP_DEPLOYMENT_MODE` for clarity
|
||||||
|
- ✅ Background operations NOT auto-enabled (not needed in single-user mode)
|
||||||
|
|
||||||
|
**Migration Steps:**
|
||||||
|
1. Replace `VECTOR_SYNC_ENABLED=true` with `ENABLE_SEMANTIC_SEARCH=true`
|
||||||
|
2. Optionally add `MCP_DEPLOYMENT_MODE=single_user_basic`
|
||||||
|
3. Restart server
|
||||||
|
4. Verify deprecation warnings are gone
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Scenario 2: Multi-User OAuth with Semantic Search
|
||||||
|
|
||||||
|
**Before (v0.57.x):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# Both variables required - confusing!
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v0.58.0+ - Simplified):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# One variable does it all!
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Automatically enables background operations
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
|
||||||
|
# Note: ENABLE_OFFLINE_ACCESS no longer needed!
|
||||||
|
# Background operations are auto-enabled by ENABLE_SEMANTIC_SEARCH
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Changed:**
|
||||||
|
- ✅ Removed need for explicit `ENABLE_OFFLINE_ACCESS`
|
||||||
|
- ✅ `ENABLE_SEMANTIC_SEARCH` automatically enables background operations in multi-user modes
|
||||||
|
- ✅ Renamed `VECTOR_SYNC_ENABLED` to `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
- ✅ Added optional explicit mode declaration
|
||||||
|
|
||||||
|
**Migration Steps:**
|
||||||
|
1. Replace `VECTOR_SYNC_ENABLED=true` with `ENABLE_SEMANTIC_SEARCH=true`
|
||||||
|
2. Remove `ENABLE_OFFLINE_ACCESS=true` (auto-enabled)
|
||||||
|
3. Optionally add `MCP_DEPLOYMENT_MODE=oauth_single_audience`
|
||||||
|
4. Restart server
|
||||||
|
5. Check logs for confirmation: "Automatically enabled background operations for semantic search"
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Scenario 3: Multi-User OAuth WITHOUT Semantic Search
|
||||||
|
|
||||||
|
**Before (v0.57.x):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# Enable background operations for future features
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v0.58.0+):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# Renamed for clarity
|
||||||
|
ENABLE_BACKGROUND_OPERATIONS=true # Previously ENABLE_OFFLINE_ACCESS
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Changed:**
|
||||||
|
- ✅ Renamed `ENABLE_OFFLINE_ACCESS` to `ENABLE_BACKGROUND_OPERATIONS`
|
||||||
|
- ✅ Added optional explicit mode declaration
|
||||||
|
|
||||||
|
**Migration Steps:**
|
||||||
|
1. Replace `ENABLE_OFFLINE_ACCESS=true` with `ENABLE_BACKGROUND_OPERATIONS=true`
|
||||||
|
2. Optionally add `MCP_DEPLOYMENT_MODE=oauth_single_audience`
|
||||||
|
3. Restart server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Scenario 4: Multi-User BasicAuth with Semantic Search
|
||||||
|
|
||||||
|
**Before (v0.57.x):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_MULTI_USER_BASIC_AUTH=true
|
||||||
|
|
||||||
|
# Both required - redundant
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v0.58.0+ - Simplified):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_MULTI_USER_BASIC_AUTH=true
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration
|
||||||
|
MCP_DEPLOYMENT_MODE=multi_user_basic
|
||||||
|
|
||||||
|
# One variable handles both!
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Auto-enables background operations
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=mcp-server
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=secret
|
||||||
|
|
||||||
|
# Note: ENABLE_OFFLINE_ACCESS no longer needed!
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Changed:**
|
||||||
|
- ✅ Semantic search auto-enables background operations
|
||||||
|
- ✅ Removed need for explicit `ENABLE_OFFLINE_ACCESS`
|
||||||
|
- ✅ Clearer variable naming
|
||||||
|
|
||||||
|
**Migration Steps:**
|
||||||
|
1. Replace `VECTOR_SYNC_ENABLED=true` with `ENABLE_SEMANTIC_SEARCH=true`
|
||||||
|
2. Remove `ENABLE_OFFLINE_ACCESS=true` (auto-enabled)
|
||||||
|
3. Optionally add `MCP_DEPLOYMENT_MODE=multi_user_basic`
|
||||||
|
4. Restart server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Scenario 5: Token Exchange Mode with Semantic Search
|
||||||
|
|
||||||
|
**Before (v0.57.x):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_TOKEN_EXCHANGE=true
|
||||||
|
|
||||||
|
# Both required
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
TOKEN_EXCHANGE_CACHE_TTL=300
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
**After (v0.58.0+ - Simplified):**
|
||||||
|
```bash
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
ENABLE_TOKEN_EXCHANGE=true
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_token_exchange
|
||||||
|
|
||||||
|
# One variable!
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # Auto-enables background operations
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
TOKEN_EXCHANGE_CACHE_TTL=300
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
**What Changed:**
|
||||||
|
- ✅ Semantic search auto-enables background operations
|
||||||
|
- ✅ Explicit mode declaration available
|
||||||
|
|
||||||
|
**Migration Steps:**
|
||||||
|
1. Replace `VECTOR_SYNC_ENABLED=true` with `ENABLE_SEMANTIC_SEARCH=true`
|
||||||
|
2. Remove `ENABLE_OFFLINE_ACCESS=true` (auto-enabled)
|
||||||
|
3. Optionally add `MCP_DEPLOYMENT_MODE=oauth_token_exchange`
|
||||||
|
4. Restart server
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Understanding Automatic Dependency Resolution
|
||||||
|
|
||||||
|
### How It Works
|
||||||
|
|
||||||
|
In v0.58.0+, the server uses smart dependency resolution:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# In multi-user modes (OAuth, Multi-User BasicAuth):
|
||||||
|
if ENABLE_SEMANTIC_SEARCH == true:
|
||||||
|
background_operations = automatically enabled
|
||||||
|
refresh_tokens = automatically requested
|
||||||
|
token_storage = required (TOKEN_ENCRYPTION_KEY, TOKEN_STORAGE_DB)
|
||||||
|
oauth_credentials = required (for app password retrieval)
|
||||||
|
```
|
||||||
|
|
||||||
|
**What this means:**
|
||||||
|
- ✅ Set `ENABLE_SEMANTIC_SEARCH=true`
|
||||||
|
- ✅ Provide required infrastructure (Qdrant, Ollama, encryption key)
|
||||||
|
- ✅ System automatically enables background operations
|
||||||
|
- ❌ No need to set `ENABLE_BACKGROUND_OPERATIONS` separately
|
||||||
|
|
||||||
|
### When Automatic Enablement Happens
|
||||||
|
|
||||||
|
| Deployment Mode | Semantic Search Enabled | Background Operations Auto-Enabled? |
|
||||||
|
|----------------|------------------------|-----------------------------------|
|
||||||
|
| Single-User BasicAuth | ✅ | ❌ No (not needed) |
|
||||||
|
| Multi-User BasicAuth | ✅ | ✅ Yes |
|
||||||
|
| OAuth Single-Audience | ✅ | ✅ Yes |
|
||||||
|
| OAuth Token Exchange | ✅ | ✅ Yes |
|
||||||
|
| Smithery Stateless | N/A (not supported) | N/A |
|
||||||
|
|
||||||
|
### When to Explicitly Set ENABLE_BACKGROUND_OPERATIONS
|
||||||
|
|
||||||
|
Only needed when you want background operations **without** semantic search:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Example: OAuth mode with background operations but NO semantic search
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# Explicitly enable background operations for future features
|
||||||
|
ENABLE_BACKGROUND_OPERATIONS=true
|
||||||
|
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
|
||||||
|
# Semantic search disabled
|
||||||
|
ENABLE_SEMANTIC_SEARCH=false
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Explicit Mode Selection
|
||||||
|
|
||||||
|
### Why Use MCP_DEPLOYMENT_MODE?
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Removes ambiguity about which mode is active
|
||||||
|
- ✅ Validation errors reference specific mode requirements
|
||||||
|
- ✅ Catches configuration mistakes early
|
||||||
|
- ✅ Self-documenting configuration
|
||||||
|
|
||||||
|
**Example:**
|
||||||
|
```bash
|
||||||
|
# Without explicit mode:
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
# Is this OAuth or Multi-User BasicAuth? Not immediately clear.
|
||||||
|
|
||||||
|
# With explicit mode:
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
# Clear: This is OAuth mode
|
||||||
|
```
|
||||||
|
|
||||||
|
### Valid Mode Values
|
||||||
|
|
||||||
|
| Mode Value | Description |
|
||||||
|
|-----------|-------------|
|
||||||
|
| `single_user_basic` | Single-user with username/password |
|
||||||
|
| `multi_user_basic` | Multi-user with BasicAuth pass-through |
|
||||||
|
| `oauth_single_audience` | Multi-user OAuth (recommended) |
|
||||||
|
| `oauth_token_exchange` | Multi-user OAuth with token exchange |
|
||||||
|
| `smithery` | Smithery platform deployment |
|
||||||
|
|
||||||
|
### Mode Detection Priority
|
||||||
|
|
||||||
|
When `MCP_DEPLOYMENT_MODE` is set:
|
||||||
|
1. ✅ Explicit mode is used
|
||||||
|
2. ✅ Server validates configuration matches explicit mode
|
||||||
|
3. ❌ Auto-detection is skipped
|
||||||
|
|
||||||
|
When `MCP_DEPLOYMENT_MODE` is NOT set:
|
||||||
|
1. ✅ Auto-detection runs (existing behavior)
|
||||||
|
2. ✅ Priority: Smithery → Token Exchange → Multi-User BasicAuth → Single-User BasicAuth → OAuth Single-Audience
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Validation and Error Messages
|
||||||
|
|
||||||
|
### Old Validation (v0.57.x)
|
||||||
|
|
||||||
|
```
|
||||||
|
Error: [multi_user_basic] ENABLE_OFFLINE_ACCESS is required when VECTOR_SYNC_ENABLED is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
**Problem:** User must understand internal dependency relationship
|
||||||
|
|
||||||
|
### New Validation (v0.58.0+)
|
||||||
|
|
||||||
|
```
|
||||||
|
Error: [multi_user_basic] TOKEN_ENCRYPTION_KEY is required when ENABLE_SEMANTIC_SEARCH is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
**Benefit:** Clear what's needed, no mention of internal ENABLE_BACKGROUND_OPERATIONS flag
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting Migration
|
||||||
|
|
||||||
|
### Issue: Deprecation Warning After Migration
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
WARNING: VECTOR_SYNC_ENABLED is deprecated. Please use ENABLE_SEMANTIC_SEARCH instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Check for `VECTOR_SYNC_ENABLED` in `.env` file
|
||||||
|
2. Replace with `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
3. Search for any scripts/CI configs using old name
|
||||||
|
4. Restart server
|
||||||
|
|
||||||
|
### Issue: Both Old and New Names Set
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
WARNING: Both ENABLE_SEMANTIC_SEARCH and VECTOR_SYNC_ENABLED are set. Using ENABLE_SEMANTIC_SEARCH.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
1. Remove `VECTOR_SYNC_ENABLED` from `.env`
|
||||||
|
2. Keep `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
3. Restart server
|
||||||
|
|
||||||
|
### Issue: Missing Required Dependencies
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
Error: [oauth_single_audience] TOKEN_ENCRYPTION_KEY is required when ENABLE_SEMANTIC_SEARCH is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
When semantic search is enabled in multi-user modes, you need:
|
||||||
|
- `TOKEN_ENCRYPTION_KEY` - Generate with: `python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"`
|
||||||
|
- `TOKEN_STORAGE_DB` - Path to SQLite database (e.g., `/app/data/tokens.db`)
|
||||||
|
- `NEXTCLOUD_OIDC_CLIENT_ID` and `NEXTCLOUD_OIDC_CLIENT_SECRET` - For app password retrieval
|
||||||
|
|
||||||
|
### Issue: Unexpected Mode Detected
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
Server activates `oauth_single_audience` mode when you expected `multi_user_basic`
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Add explicit mode declaration:
|
||||||
|
```bash
|
||||||
|
MCP_DEPLOYMENT_MODE=multi_user_basic
|
||||||
|
ENABLE_MULTI_USER_BASIC_AUTH=true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing Your Migration
|
||||||
|
|
||||||
|
### Step 1: Verify Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Set new variable names in .env
|
||||||
|
cat .env | grep -E "(ENABLE_SEMANTIC_SEARCH|ENABLE_BACKGROUND_OPERATIONS|MCP_DEPLOYMENT_MODE)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Check for Old Variable Names
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Should return nothing after migration
|
||||||
|
cat .env | grep -E "(VECTOR_SYNC_ENABLED|ENABLE_OFFLINE_ACCESS)"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Start Server and Check Logs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Start server
|
||||||
|
docker-compose up mcp
|
||||||
|
|
||||||
|
# Look for:
|
||||||
|
# 1. No deprecation warnings
|
||||||
|
# 2. Correct mode detected
|
||||||
|
# 3. Auto-enablement messages (if using semantic search in multi-user mode)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Expected Log Output (Multi-User OAuth + Semantic Search):**
|
||||||
|
```
|
||||||
|
INFO: Using explicit deployment mode: oauth_single_audience
|
||||||
|
INFO: Automatically enabled background operations for semantic search in multi-user mode.
|
||||||
|
INFO: Vector sync enabled. Starting background scanner...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 4: Verify Functionality
|
||||||
|
|
||||||
|
Test that existing features still work:
|
||||||
|
- [ ] Semantic search returns results
|
||||||
|
- [ ] Background indexing runs
|
||||||
|
- [ ] OAuth flow completes successfully
|
||||||
|
- [ ] Refresh tokens are stored/retrieved
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Quick Start Templates
|
||||||
|
|
||||||
|
We provide mode-specific templates for new deployments:
|
||||||
|
|
||||||
|
| Template | Use Case |
|
||||||
|
|----------|----------|
|
||||||
|
| `env.sample.single-user` | Simplest setup |
|
||||||
|
| `env.sample.oauth-multi-user` | Recommended multi-user |
|
||||||
|
| `env.sample.oauth-advanced` | Token exchange mode |
|
||||||
|
|
||||||
|
**Usage:**
|
||||||
|
```bash
|
||||||
|
cp env.sample.oauth-multi-user .env
|
||||||
|
# Edit .env with your values
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Timeline and Support
|
||||||
|
|
||||||
|
| Version | Status | Old Variable Support |
|
||||||
|
|---------|--------|---------------------|
|
||||||
|
| v0.57.x | Stable | Old names only |
|
||||||
|
| v0.58.0 | Current | Both old and new (with warnings) |
|
||||||
|
| v1.0.0 | Breaking | New names only |
|
||||||
|
|
||||||
|
**Recommendation:** Migrate before v1.0.0 (12+ months minimum)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
If you encounter issues during migration:
|
||||||
|
|
||||||
|
1. **Check the logs** - Look for deprecation warnings and error messages
|
||||||
|
2. **Review ADR-021** - See [docs/ADR-021-configuration-consolidation.md](ADR-021-configuration-consolidation.md)
|
||||||
|
3. **Use mode-specific templates** - See `env.sample.*` files
|
||||||
|
4. **File an issue** - Include your `.env` (redacted), logs, and mode
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
**What You Need to Do:**
|
||||||
|
1. ✅ Rename `VECTOR_SYNC_ENABLED` → `ENABLE_SEMANTIC_SEARCH`
|
||||||
|
2. ✅ (Optional) Rename `ENABLE_OFFLINE_ACCESS` → `ENABLE_BACKGROUND_OPERATIONS`
|
||||||
|
3. ✅ (Recommended) Add `MCP_DEPLOYMENT_MODE` for clarity
|
||||||
|
4. ✅ Remove redundant settings (semantic search auto-enables background ops in multi-user modes)
|
||||||
|
5. ✅ Test your configuration
|
||||||
|
|
||||||
|
**What the Server Does Automatically:**
|
||||||
|
- ✅ Supports both old and new variable names
|
||||||
|
- ✅ Logs deprecation warnings for old names
|
||||||
|
- ✅ Auto-enables background operations when semantic search is enabled in multi-user modes
|
||||||
|
- ✅ Validates configuration and provides clear error messages
|
||||||
|
|
||||||
|
**Migration Timeline:**
|
||||||
|
- Now → v1.0.0: Both old and new names work
|
||||||
|
- v1.0.0+: Only new names supported
|
||||||
|
|
||||||
|
**Questions?** See [docs/configuration.md](configuration.md) or file an issue.
|
||||||
+129
-15
@@ -2,25 +2,82 @@
|
|||||||
|
|
||||||
The Nextcloud MCP server requires configuration to connect to your Nextcloud instance. Configuration is provided through environment variables, typically stored in a `.env` file.
|
The Nextcloud MCP server requires configuration to connect to your Nextcloud instance. Configuration is provided through environment variables, typically stored in a `.env` file.
|
||||||
|
|
||||||
|
> **Note:** Configuration was significantly simplified in v0.58.0. If you're upgrading from v0.57.x, see the [Configuration Migration Guide](configuration-migration-v2.md).
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
Create a `.env` file based on `env.sample`:
|
We provide mode-specific configuration templates for quick setup:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
# Choose a template based on your deployment mode:
|
||||||
|
cp env.sample.single-user .env # Simplest - one user, local dev
|
||||||
|
cp env.sample.oauth-multi-user .env # Recommended - multi-user OAuth
|
||||||
|
cp env.sample.oauth-advanced .env # Advanced - token exchange mode
|
||||||
|
|
||||||
|
# Or start from the full example:
|
||||||
cp env.sample .env
|
cp env.sample .env
|
||||||
|
|
||||||
# Edit .env with your Nextcloud details
|
# Edit .env with your Nextcloud details
|
||||||
```
|
```
|
||||||
|
|
||||||
Then choose your authentication mode:
|
Then choose your deployment mode:
|
||||||
|
|
||||||
- [OAuth2/OIDC Configuration](#oauth2oidc-configuration) (Recommended)
|
- [Single-User BasicAuth](#single-user-basicauth-mode) - Simplest for personal instances
|
||||||
- [Basic Authentication Configuration](#basic-authentication-legacy)
|
- [Multi-User OAuth](#multi-user-oauth-modes) - Recommended for production
|
||||||
|
- [Deployment Mode Selection](#deployment-mode-selection) - Explicit mode declaration
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## OAuth2/OIDC Configuration
|
## Deployment Mode Selection
|
||||||
|
|
||||||
OAuth2/OIDC is the recommended authentication mode for production deployments.
|
**New in v0.58.0:** You can explicitly declare your deployment mode to remove ambiguity and catch configuration errors early.
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
# Optional but recommended
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
```
|
||||||
|
|
||||||
|
**Valid values:**
|
||||||
|
- `single_user_basic` - Single-user with username/password
|
||||||
|
- `multi_user_basic` - Multi-user with BasicAuth pass-through
|
||||||
|
- `oauth_single_audience` - Multi-user OAuth (recommended)
|
||||||
|
- `oauth_token_exchange` - Multi-user OAuth with token exchange
|
||||||
|
- `smithery` - Smithery platform deployment
|
||||||
|
|
||||||
|
**Benefits:**
|
||||||
|
- ✅ Clear which mode is active
|
||||||
|
- ✅ Better validation error messages
|
||||||
|
- ✅ Self-documenting configuration
|
||||||
|
- ✅ Catches configuration mistakes early
|
||||||
|
|
||||||
|
**Auto-detection:** If `MCP_DEPLOYMENT_MODE` is not set, the server auto-detects the mode based on other settings (existing behavior).
|
||||||
|
|
||||||
|
See [Authentication Modes](authentication.md) for detailed comparison of deployment modes.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Single-User BasicAuth Mode
|
||||||
|
|
||||||
|
BasicAuth with a single user is the simplest deployment mode. Use for personal instances, local development, and testing.
|
||||||
|
|
||||||
|
```dotenv
|
||||||
|
# Minimal single-user configuration
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration
|
||||||
|
MCP_DEPLOYMENT_MODE=single_user_basic
|
||||||
|
```
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> **Security Notice:** BasicAuth stores credentials in environment variables and is less secure than OAuth. Use OAuth for production multi-user deployments.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Multi-User OAuth Modes
|
||||||
|
|
||||||
|
OAuth2/OIDC is the recommended authentication mode for production multi-user deployments.
|
||||||
|
|
||||||
### Minimal Configuration (Auto-registration)
|
### Minimal Configuration (Auto-registration)
|
||||||
|
|
||||||
@@ -28,6 +85,9 @@ OAuth2/OIDC is the recommended authentication mode for production deployments.
|
|||||||
# .env file for OAuth with auto-registration
|
# .env file for OAuth with auto-registration
|
||||||
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
|
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration (recommended)
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
# Leave these EMPTY for OAuth mode
|
# Leave these EMPTY for OAuth mode
|
||||||
NEXTCLOUD_USERNAME=
|
NEXTCLOUD_USERNAME=
|
||||||
NEXTCLOUD_PASSWORD=
|
NEXTCLOUD_PASSWORD=
|
||||||
@@ -41,6 +101,9 @@ This minimal configuration uses dynamic client registration to automatically reg
|
|||||||
# .env file for OAuth with pre-configured client
|
# .env file for OAuth with pre-configured client
|
||||||
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
|
NEXTCLOUD_HOST=https://your.nextcloud.instance.com
|
||||||
|
|
||||||
|
# Optional: Explicit mode declaration (recommended)
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
# OAuth Client Credentials (optional - auto-registers if not provided)
|
# OAuth Client Credentials (optional - auto-registers if not provided)
|
||||||
NEXTCLOUD_OIDC_CLIENT_ID=your-client-id
|
NEXTCLOUD_OIDC_CLIENT_ID=your-client-id
|
||||||
NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
|
NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
|
||||||
@@ -110,8 +173,50 @@ NEXTCLOUD_PASSWORD=your_app_password_or_password
|
|||||||
|
|
||||||
## Semantic Search Configuration (Optional)
|
## Semantic Search Configuration (Optional)
|
||||||
|
|
||||||
|
**New in v0.58.0:** Simplified semantic search configuration with automatic dependency resolution.
|
||||||
|
|
||||||
The MCP server includes semantic search capabilities powered by vector embeddings. This feature requires a vector database (Qdrant) and an embedding service.
|
The MCP server includes semantic search capabilities powered by vector embeddings. This feature requires a vector database (Qdrant) and an embedding service.
|
||||||
|
|
||||||
|
### Quick Start
|
||||||
|
|
||||||
|
**Single-User Mode:**
|
||||||
|
```dotenv
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
|
||||||
|
# Enable semantic search
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
|
||||||
|
# Vector database
|
||||||
|
QDRANT_LOCATION=:memory:
|
||||||
|
|
||||||
|
# Embedding provider
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multi-User OAuth Mode:**
|
||||||
|
```dotenv
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# Enable semantic search
|
||||||
|
# In multi-user modes, this AUTOMATICALLY enables background operations!
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
|
||||||
|
# Required for background operations (auto-enabled by semantic search)
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
|
||||||
|
# Vector database
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
|
||||||
|
# Embedding provider
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** In multi-user modes (OAuth, Multi-User BasicAuth), enabling `ENABLE_SEMANTIC_SEARCH` automatically enables background operations and refresh token storage. You don't need to set `ENABLE_BACKGROUND_OPERATIONS` separately!
|
||||||
|
|
||||||
### Qdrant Vector Database Modes
|
### Qdrant Vector Database Modes
|
||||||
|
|
||||||
The server supports three Qdrant deployment modes:
|
The server supports three Qdrant deployment modes:
|
||||||
@@ -126,7 +231,7 @@ No configuration needed! If neither `QDRANT_URL` nor `QDRANT_LOCATION` is set, t
|
|||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
# No Qdrant configuration needed - defaults to :memory:
|
# No Qdrant configuration needed - defaults to :memory:
|
||||||
VECTOR_SYNC_ENABLED=true
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
@@ -145,7 +250,7 @@ For single-instance deployments that need persistence without a separate Qdrant
|
|||||||
```dotenv
|
```dotenv
|
||||||
# Local persistent storage
|
# Local persistent storage
|
||||||
QDRANT_LOCATION=/app/data/qdrant # Or any writable path
|
QDRANT_LOCATION=/app/data/qdrant # Or any writable path
|
||||||
VECTOR_SYNC_ENABLED=true
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
@@ -166,7 +271,7 @@ For production deployments with a dedicated Qdrant service:
|
|||||||
QDRANT_URL=http://qdrant:6333
|
QDRANT_URL=http://qdrant:6333
|
||||||
QDRANT_API_KEY=your-secret-api-key # Optional
|
QDRANT_API_KEY=your-secret-api-key # Optional
|
||||||
QDRANT_COLLECTION=nextcloud_content # Optional
|
QDRANT_COLLECTION=nextcloud_content # Optional
|
||||||
VECTOR_SYNC_ENABLED=true
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
```
|
```
|
||||||
|
|
||||||
**Pros:**
|
**Pros:**
|
||||||
@@ -283,13 +388,15 @@ Solutions:
|
|||||||
- Data corruption in Qdrant
|
- Data corruption in Qdrant
|
||||||
- Confusing error messages during indexing
|
- Confusing error messages during indexing
|
||||||
|
|
||||||
### Vector Sync Configuration
|
### Background Indexing Configuration
|
||||||
|
|
||||||
Control background indexing behavior:
|
Control background indexing behavior:
|
||||||
|
|
||||||
```dotenv
|
```dotenv
|
||||||
# Vector sync settings (ADR-007)
|
# Semantic search (ADR-007, ADR-021)
|
||||||
VECTOR_SYNC_ENABLED=true # Enable background indexing
|
ENABLE_SEMANTIC_SEARCH=true # Enable background indexing
|
||||||
|
|
||||||
|
# Tuning parameters (advanced - only modify if needed)
|
||||||
VECTOR_SYNC_SCAN_INTERVAL=300 # Scan interval in seconds (default: 5 minutes)
|
VECTOR_SYNC_SCAN_INTERVAL=300 # Scan interval in seconds (default: 5 minutes)
|
||||||
VECTOR_SYNC_PROCESSOR_WORKERS=3 # Concurrent indexing workers (default: 3)
|
VECTOR_SYNC_PROCESSOR_WORKERS=3 # Concurrent indexing workers (default: 3)
|
||||||
VECTOR_SYNC_QUEUE_MAX_SIZE=10000 # Max queued documents (default: 10000)
|
VECTOR_SYNC_QUEUE_MAX_SIZE=10000 # Max queued documents (default: 10000)
|
||||||
@@ -299,6 +406,8 @@ DOCUMENT_CHUNK_SIZE=512 # Words per chunk (default: 512)
|
|||||||
DOCUMENT_CHUNK_OVERLAP=50 # Overlapping words between chunks (default: 50)
|
DOCUMENT_CHUNK_OVERLAP=50 # Overlapping words between chunks (default: 50)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
> **Note:** The `VECTOR_SYNC_*` tuning parameters keep their names as they're implementation details. Only the user-facing feature flag was renamed to `ENABLE_SEMANTIC_SEARCH`.
|
||||||
|
|
||||||
### Embedding Service Configuration
|
### Embedding Service Configuration
|
||||||
|
|
||||||
The server uses an embedding service to generate vector representations. Two options are available:
|
The server uses an embedding service to generate vector representations. Two options are available:
|
||||||
@@ -369,11 +478,11 @@ DOCUMENT_CHUNK_OVERLAP=100
|
|||||||
|
|
||||||
| Variable | Required | Default | Description |
|
| Variable | Required | Default | Description |
|
||||||
|----------|----------|---------|-------------|
|
|----------|----------|---------|-------------|
|
||||||
|
| `ENABLE_SEMANTIC_SEARCH` | ⚠️ Optional | `false` | Enable semantic search with background indexing (replaces `VECTOR_SYNC_ENABLED`) |
|
||||||
| `QDRANT_URL` | ⚠️ Optional | - | Qdrant service URL (network mode) - mutually exclusive with `QDRANT_LOCATION` |
|
| `QDRANT_URL` | ⚠️ Optional | - | Qdrant service URL (network mode) - mutually exclusive with `QDRANT_LOCATION` |
|
||||||
| `QDRANT_LOCATION` | ⚠️ Optional | `:memory:` | Local Qdrant path (`:memory:` or `/path/to/data`) - mutually exclusive with `QDRANT_URL` |
|
| `QDRANT_LOCATION` | ⚠️ Optional | `:memory:` | Local Qdrant path (`:memory:` or `/path/to/data`) - mutually exclusive with `QDRANT_URL` |
|
||||||
| `QDRANT_API_KEY` | ⚠️ Optional | - | Qdrant API key (network mode only) |
|
| `QDRANT_API_KEY` | ⚠️ Optional | - | Qdrant API key (network mode only) |
|
||||||
| `QDRANT_COLLECTION` | ⚠️ Optional | `nextcloud_content` | Qdrant collection name |
|
| `QDRANT_COLLECTION` | ⚠️ Optional | Auto-generated | Qdrant collection name |
|
||||||
| `VECTOR_SYNC_ENABLED` | ⚠️ Optional | `false` | Enable background vector indexing |
|
|
||||||
| `VECTOR_SYNC_SCAN_INTERVAL` | ⚠️ Optional | `300` | Document scan interval (seconds) |
|
| `VECTOR_SYNC_SCAN_INTERVAL` | ⚠️ Optional | `300` | Document scan interval (seconds) |
|
||||||
| `VECTOR_SYNC_PROCESSOR_WORKERS` | ⚠️ Optional | `3` | Concurrent indexing workers |
|
| `VECTOR_SYNC_PROCESSOR_WORKERS` | ⚠️ Optional | `3` | Concurrent indexing workers |
|
||||||
| `VECTOR_SYNC_QUEUE_MAX_SIZE` | ⚠️ Optional | `10000` | Max queued documents |
|
| `VECTOR_SYNC_QUEUE_MAX_SIZE` | ⚠️ Optional | `10000` | Max queued documents |
|
||||||
@@ -383,6 +492,9 @@ DOCUMENT_CHUNK_OVERLAP=100
|
|||||||
| `DOCUMENT_CHUNK_SIZE` | ⚠️ Optional | `512` | Words per chunk for document embedding |
|
| `DOCUMENT_CHUNK_SIZE` | ⚠️ Optional | `512` | Words per chunk for document embedding |
|
||||||
| `DOCUMENT_CHUNK_OVERLAP` | ⚠️ Optional | `50` | Overlapping words between chunks (must be < chunk size) |
|
| `DOCUMENT_CHUNK_OVERLAP` | ⚠️ Optional | `50` | Overlapping words between chunks (must be < chunk size) |
|
||||||
|
|
||||||
|
**Deprecated variables (still functional):**
|
||||||
|
- `VECTOR_SYNC_ENABLED` - Use `ENABLE_SEMANTIC_SEARCH` instead (will be removed in v1.0.0)
|
||||||
|
|
||||||
### Docker Compose Example
|
### Docker Compose Example
|
||||||
|
|
||||||
Enable network mode Qdrant with docker-compose:
|
Enable network mode Qdrant with docker-compose:
|
||||||
@@ -392,7 +504,7 @@ services:
|
|||||||
mcp:
|
mcp:
|
||||||
environment:
|
environment:
|
||||||
- QDRANT_URL=http://qdrant:6333
|
- QDRANT_URL=http://qdrant:6333
|
||||||
- VECTOR_SYNC_ENABLED=true
|
- ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
|
||||||
qdrant:
|
qdrant:
|
||||||
image: qdrant/qdrant:latest
|
image: qdrant/qdrant:latest
|
||||||
@@ -545,6 +657,7 @@ uv run nextcloud-mcp-server --no-oauth \
|
|||||||
|
|
||||||
## See Also
|
## See Also
|
||||||
|
|
||||||
|
- [Configuration Migration Guide v2](configuration-migration-v2.md) - **New in v0.58.0:** Migrate from old variable names
|
||||||
- [OAuth Quick Start](quickstart-oauth.md) - 5-minute OAuth setup for development
|
- [OAuth Quick Start](quickstart-oauth.md) - 5-minute OAuth setup for development
|
||||||
- [OAuth Setup Guide](oauth-setup.md) - Detailed OAuth configuration for production
|
- [OAuth Setup Guide](oauth-setup.md) - Detailed OAuth configuration for production
|
||||||
- [OAuth Architecture](oauth-architecture.md) - How OAuth works in the MCP server
|
- [OAuth Architecture](oauth-architecture.md) - How OAuth works in the MCP server
|
||||||
@@ -553,3 +666,4 @@ uv run nextcloud-mcp-server --no-oauth \
|
|||||||
- [Running the Server](running.md) - Starting the server with different configurations
|
- [Running the Server](running.md) - Starting the server with different configurations
|
||||||
- [Troubleshooting](troubleshooting.md) - Common configuration issues
|
- [Troubleshooting](troubleshooting.md) - Common configuration issues
|
||||||
- [OAuth Troubleshooting](oauth-troubleshooting.md) - OAuth-specific troubleshooting
|
- [OAuth Troubleshooting](oauth-troubleshooting.md) - OAuth-specific troubleshooting
|
||||||
|
- [ADR-021](ADR-021-configuration-consolidation.md) - Configuration consolidation architecture decision
|
||||||
|
|||||||
@@ -4,6 +4,146 @@ This guide covers common issues and solutions for the Nextcloud MCP server.
|
|||||||
|
|
||||||
> **OAuth-specific issues?** See the dedicated [OAuth Troubleshooting Guide](oauth-troubleshooting.md) for OAuth authentication problems, OIDC discovery issues, token validation failures, and more.
|
> **OAuth-specific issues?** See the dedicated [OAuth Troubleshooting Guide](oauth-troubleshooting.md) for OAuth authentication problems, OIDC discovery issues, token validation failures, and more.
|
||||||
|
|
||||||
|
> **Upgrading from v0.57.x?** See the [Configuration Migration Guide](configuration-migration-v2.md) for help with new variable names.
|
||||||
|
|
||||||
|
## Configuration Issues (v0.58.0+)
|
||||||
|
|
||||||
|
### Issue: Deprecation warning for VECTOR_SYNC_ENABLED
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
WARNING: VECTOR_SYNC_ENABLED is deprecated. Please use ENABLE_SEMANTIC_SEARCH instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** You're using the old variable name from v0.57.x.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
```bash
|
||||||
|
# In your .env file, replace:
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
# With:
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
```
|
||||||
|
|
||||||
|
See [Configuration Migration Guide](configuration-migration-v2.md) for complete migration instructions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Issue: Deprecation warning for ENABLE_OFFLINE_ACCESS
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
WARNING: ENABLE_OFFLINE_ACCESS is deprecated. Please use ENABLE_BACKGROUND_OPERATIONS instead.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** You're using the old variable name from v0.57.x.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
|
||||||
|
**If you have semantic search enabled:**
|
||||||
|
```bash
|
||||||
|
# In multi-user modes, you can remove ENABLE_OFFLINE_ACCESS entirely!
|
||||||
|
# ENABLE_SEMANTIC_SEARCH automatically enables background operations
|
||||||
|
|
||||||
|
# Before (v0.57.x):
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
# After (v0.58.0+):
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true # This is all you need!
|
||||||
|
```
|
||||||
|
|
||||||
|
**If you only want background operations (no semantic search):**
|
||||||
|
```bash
|
||||||
|
# Replace:
|
||||||
|
ENABLE_OFFLINE_ACCESS=true
|
||||||
|
|
||||||
|
# With:
|
||||||
|
ENABLE_BACKGROUND_OPERATIONS=true
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Issue: "Invalid MCP_DEPLOYMENT_MODE"
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
ValueError: Invalid MCP_DEPLOYMENT_MODE: 'oauth'. Valid values: single_user_basic, multi_user_basic, oauth_single_audience, oauth_token_exchange, smithery
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** Invalid value for `MCP_DEPLOYMENT_MODE`.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Use one of the valid mode values:
|
||||||
|
```bash
|
||||||
|
# Correct values:
|
||||||
|
MCP_DEPLOYMENT_MODE=single_user_basic # Single-user with username/password
|
||||||
|
MCP_DEPLOYMENT_MODE=multi_user_basic # Multi-user BasicAuth
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience # OAuth (recommended)
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_token_exchange # OAuth with token exchange
|
||||||
|
MCP_DEPLOYMENT_MODE=smithery # Smithery deployment
|
||||||
|
```
|
||||||
|
|
||||||
|
Or remove `MCP_DEPLOYMENT_MODE` to use automatic detection.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Issue: Missing TOKEN_ENCRYPTION_KEY when semantic search enabled
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
Error: [oauth_single_audience] TOKEN_ENCRYPTION_KEY is required when ENABLE_SEMANTIC_SEARCH is enabled
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** In multi-user modes, semantic search automatically enables background operations, which require encrypted token storage.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Generate an encryption key and add required token storage configuration:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Generate encryption key
|
||||||
|
python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||||||
|
|
||||||
|
# Add to .env:
|
||||||
|
TOKEN_ENCRYPTION_KEY=<generated-key>
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_ID=your-client-id # Required for app password retrieval
|
||||||
|
NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why this happens:**
|
||||||
|
- v0.58.0+ automatically enables background operations when `ENABLE_SEMANTIC_SEARCH=true` in multi-user modes
|
||||||
|
- Background operations need encrypted refresh token storage
|
||||||
|
- This simplifies configuration but requires the encryption infrastructure
|
||||||
|
|
||||||
|
See [Configuration Guide - Semantic Search](configuration.md#semantic-search-configuration-optional) for details.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Issue: Both old and new variable names set
|
||||||
|
|
||||||
|
**Symptom:**
|
||||||
|
```
|
||||||
|
WARNING: Both ENABLE_SEMANTIC_SEARCH and VECTOR_SYNC_ENABLED are set. Using ENABLE_SEMANTIC_SEARCH.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Cause:** You have both the old and new variable names in your configuration.
|
||||||
|
|
||||||
|
**Solution:**
|
||||||
|
Remove the old variable name:
|
||||||
|
```bash
|
||||||
|
# Remove this line:
|
||||||
|
VECTOR_SYNC_ENABLED=true
|
||||||
|
|
||||||
|
# Keep this line:
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
```
|
||||||
|
|
||||||
|
The server will use the new name and ignore the old one, but it's cleaner to remove the old variable entirely.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## OAuth Issues (Quick Reference)
|
## OAuth Issues (Quick Reference)
|
||||||
|
|
||||||
### Issue: "OAuth mode requires NEXTCLOUD_HOST environment variable"
|
### Issue: "OAuth mode requires NEXTCLOUD_HOST environment variable"
|
||||||
|
|||||||
+225
-192
@@ -1,203 +1,236 @@
|
|||||||
# Nextcloud Instance
|
# ============================================
|
||||||
|
# DEPLOYMENT MODE SELECTION
|
||||||
|
# ============================================
|
||||||
|
# Optional: Explicitly declare deployment mode (ADR-021)
|
||||||
|
# If not set, mode is auto-detected from other settings
|
||||||
|
# Valid values: single_user_basic, multi_user_basic, oauth_single_audience,
|
||||||
|
# oauth_token_exchange, smithery
|
||||||
|
#
|
||||||
|
# Recommendation: Set this for clarity and to catch configuration errors early
|
||||||
|
#MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# COMMON SETTINGS (Required for all modes)
|
||||||
|
# ============================================
|
||||||
|
# Your Nextcloud instance URL (without trailing slash)
|
||||||
NEXTCLOUD_HOST=
|
NEXTCLOUD_HOST=
|
||||||
|
|
||||||
# ===== AUTHENTICATION MODE =====
|
# ============================================
|
||||||
# Choose ONE of the following:
|
# SINGLE-USER BASICAUTH MODE
|
||||||
|
# ============================================
|
||||||
# Option 1: OAuth2/OIDC (RECOMMENDED - More Secure)
|
# Simplest deployment - one user, credentials in environment
|
||||||
# - Requires Nextcloud OIDC app installed and configured
|
# Use for: Personal instances, local development, testing
|
||||||
# - Admin must enable "Dynamic Client Registration" in OIDC app settings
|
#
|
||||||
# - Leave NEXTCLOUD_USERNAME and NEXTCLOUD_PASSWORD empty to use OAuth mode
|
# Required:
|
||||||
# - OAuth client credentials are stored encrypted in SQLite (TOKEN_STORAGE_DB)
|
|
||||||
# - Optional: Pre-register client and provide credentials (otherwise auto-registers)
|
|
||||||
NEXTCLOUD_OIDC_CLIENT_ID=
|
|
||||||
NEXTCLOUD_OIDC_CLIENT_SECRET=
|
|
||||||
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
|
||||||
|
|
||||||
# OAuth Storage Configuration (SQLite storage for OAuth clients and refresh tokens)
|
|
||||||
# TOKEN_ENCRYPTION_KEY: Required for encrypting OAuth client secrets and refresh tokens
|
|
||||||
# Generate with: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
|
||||||
#TOKEN_ENCRYPTION_KEY=
|
|
||||||
# TOKEN_STORAGE_DB: Path to SQLite database (default: /app/data/tokens.db)
|
|
||||||
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
|
||||||
|
|
||||||
# ===== ADR-004 PROGRESSIVE CONSENT CONFIGURATION =====
|
|
||||||
# Enable Progressive Consent mode (dual OAuth flows)
|
|
||||||
# When enabled: Flow 1 for client auth, Flow 2 for Nextcloud resource access
|
|
||||||
# When disabled: Uses existing hybrid flow (backward compatible)
|
|
||||||
|
|
||||||
# MCP Server OAuth Client Configuration
|
|
||||||
# The MCP server's own OAuth client credentials for Flow 2
|
|
||||||
# If not set, will use dynamic client registration
|
|
||||||
#MCP_SERVER_CLIENT_ID=
|
|
||||||
#MCP_SERVER_CLIENT_SECRET=
|
|
||||||
|
|
||||||
# Allowed MCP Client IDs (comma-separated list)
|
|
||||||
# Client IDs that are allowed to authenticate in Flow 1
|
|
||||||
# Examples: claude-desktop,continue-dev,zed-editor
|
|
||||||
#ALLOWED_MCP_CLIENTS=claude-desktop,continue-dev,zed-editor
|
|
||||||
|
|
||||||
# Token cache configuration for Token Broker Service
|
|
||||||
# Cache TTL in seconds (default: 300 = 5 minutes)
|
|
||||||
#TOKEN_CACHE_TTL=300
|
|
||||||
# Early refresh threshold in seconds (default: 30)
|
|
||||||
#TOKEN_CACHE_EARLY_REFRESH=30
|
|
||||||
|
|
||||||
# Option 2: Basic Authentication (LEGACY - Less Secure)
|
|
||||||
# - Requires username and password
|
|
||||||
# - Credentials stored in environment variables
|
|
||||||
# - Use only for backward compatibility or if OAuth unavailable
|
|
||||||
# - If these are set, OAuth mode is disabled
|
|
||||||
NEXTCLOUD_USERNAME=
|
NEXTCLOUD_USERNAME=
|
||||||
NEXTCLOUD_PASSWORD=
|
NEXTCLOUD_PASSWORD=
|
||||||
|
#
|
||||||
|
# Optional features (semantic search, document processing):
|
||||||
|
# See "Optional Features" section below
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# MULTI-USER BASICAUTH MODE
|
||||||
|
# ============================================
|
||||||
|
# Users provide credentials in request headers (pass-through)
|
||||||
|
# Use for: Multi-user without OAuth, simple shared deployments
|
||||||
|
#
|
||||||
|
# Required:
|
||||||
|
#ENABLE_MULTI_USER_BASIC_AUTH=true
|
||||||
|
#
|
||||||
|
# Optional - Background Operations (for semantic search, future features):
|
||||||
|
# Enable background token storage using app passwords (via Astrolabe)
|
||||||
|
# Required for semantic search in multi-user mode
|
||||||
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables this in multi-user modes
|
||||||
|
#ENABLE_BACKGROUND_OPERATIONS=true
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_ID=
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=
|
||||||
|
#TOKEN_ENCRYPTION_KEY=
|
||||||
|
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
#
|
||||||
|
# Optional features (semantic search, document processing):
|
||||||
|
# See "Optional Features" section below
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# OAUTH SINGLE-AUDIENCE MODE (Recommended)
|
||||||
|
# ============================================
|
||||||
|
# Multi-user OAuth with single-audience tokens
|
||||||
|
# Use for: Multi-user production deployments, enhanced security
|
||||||
|
# Tokens work for both MCP server and Nextcloud APIs (pass-through)
|
||||||
|
#
|
||||||
|
# Required: None (uses Dynamic Client Registration if credentials not provided)
|
||||||
|
#
|
||||||
|
# Optional - Pre-registered OAuth Client:
|
||||||
|
# If you pre-register the client instead of using DCR:
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_ID=
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=
|
||||||
|
#
|
||||||
|
# Optional - Background Operations (for semantic search, future features):
|
||||||
|
# Enable refresh token storage for offline access
|
||||||
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables this in multi-user modes
|
||||||
|
#ENABLE_BACKGROUND_OPERATIONS=true
|
||||||
|
#TOKEN_ENCRYPTION_KEY=
|
||||||
|
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
#
|
||||||
|
# Optional - Custom OIDC Discovery:
|
||||||
|
# Auto-detected from NEXTCLOUD_HOST if not set
|
||||||
|
#NEXTCLOUD_OIDC_DISCOVERY_URL=
|
||||||
|
#
|
||||||
|
# Optional - Custom Scopes:
|
||||||
|
# Default: openid profile email offline_access notes:* calendar:* contacts:* tables:* webdav:* deck:* cookbook:*
|
||||||
|
#NEXTCLOUD_OIDC_SCOPES=openid profile email notes:* calendar:*
|
||||||
|
#
|
||||||
|
# MCP Server URL (for OAuth redirects):
|
||||||
|
#NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
||||||
|
#
|
||||||
|
# Optional features (semantic search, document processing):
|
||||||
|
# See "Optional Features" section below
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# OAUTH TOKEN EXCHANGE MODE (Advanced)
|
||||||
|
# ============================================
|
||||||
|
# Multi-user OAuth with RFC 8693 token exchange
|
||||||
|
# Use for: Advanced deployments requiring separate MCP and Nextcloud tokens
|
||||||
|
# MCP tokens are separate from Nextcloud tokens
|
||||||
|
#
|
||||||
|
# Required:
|
||||||
|
#ENABLE_TOKEN_EXCHANGE=true
|
||||||
|
#
|
||||||
|
# Optional - Pre-registered OAuth Client:
|
||||||
|
# If you pre-register the client instead of using DCR:
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_ID=
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=
|
||||||
|
#
|
||||||
|
# Optional - Token Exchange Configuration:
|
||||||
|
# Cache TTL in seconds (default: 300 = 5 minutes)
|
||||||
|
#TOKEN_EXCHANGE_CACHE_TTL=300
|
||||||
|
#
|
||||||
|
# Optional - Background Operations:
|
||||||
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables this in multi-user modes
|
||||||
|
#ENABLE_BACKGROUND_OPERATIONS=true
|
||||||
|
#TOKEN_ENCRYPTION_KEY=
|
||||||
|
#TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
#
|
||||||
|
# Optional - Custom OIDC Discovery:
|
||||||
|
#NEXTCLOUD_OIDC_DISCOVERY_URL=
|
||||||
|
#
|
||||||
|
# MCP Server URL (for OAuth redirects):
|
||||||
|
#NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
||||||
|
#
|
||||||
|
# Optional features (semantic search, document processing):
|
||||||
|
# See "Optional Features" section below
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# SMITHERY STATELESS MODE
|
||||||
|
# ============================================
|
||||||
|
# Stateless multi-tenant deployment for Smithery platform
|
||||||
|
# Configuration comes from session URL parameters
|
||||||
|
# No persistent storage, no OAuth, no vector sync
|
||||||
|
#
|
||||||
|
# Required: None (all config from session URL)
|
||||||
|
# This mode is activated automatically when deployed to Smithery
|
||||||
|
|
||||||
|
# ============================================
|
||||||
|
# OPTIONAL FEATURES (All Deployment Modes)
|
||||||
|
# ============================================
|
||||||
|
|
||||||
|
# ===== SEMANTIC SEARCH =====
|
||||||
|
# AI-powered semantic search across Nextcloud content
|
||||||
|
# Requires: Qdrant vector database + embedding provider (Ollama, Bedrock, or Simple fallback)
|
||||||
|
#
|
||||||
|
# Enable semantic search:
|
||||||
|
#ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
#
|
||||||
|
# Note for Multi-User Modes:
|
||||||
|
# ENABLE_SEMANTIC_SEARCH automatically enables background operations when needed
|
||||||
|
# No need to set ENABLE_BACKGROUND_OPERATIONS separately
|
||||||
|
# The server will automatically request refresh tokens and store them encrypted
|
||||||
|
#
|
||||||
|
# Vector Database - Choose ONE mode:
|
||||||
|
# 1. In-memory (default): Set neither QDRANT_URL nor QDRANT_LOCATION
|
||||||
|
# 2. Persistent local: Set QDRANT_LOCATION=/path/to/data
|
||||||
|
# 3. Network: Set QDRANT_URL=http://qdrant:6333
|
||||||
|
#
|
||||||
|
#QDRANT_URL=http://qdrant:6333
|
||||||
|
#QDRANT_LOCATION=:memory:
|
||||||
|
#QDRANT_API_KEY=
|
||||||
|
#QDRANT_COLLECTION=nextcloud_content
|
||||||
|
#
|
||||||
|
# Embedding Provider - Choose ONE:
|
||||||
|
# 1. Ollama (recommended for local deployment):
|
||||||
|
#OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
#OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
||||||
|
#OLLAMA_VERIFY_SSL=true
|
||||||
|
#
|
||||||
|
# 2. Amazon Bedrock (for AWS deployments):
|
||||||
|
#AWS_REGION=us-east-1
|
||||||
|
#BEDROCK_EMBEDDING_MODEL=amazon.titan-embed-text-v2:0
|
||||||
|
# Optional: AWS credentials (uses credential chain if not set)
|
||||||
|
#AWS_ACCESS_KEY_ID=
|
||||||
|
#AWS_SECRET_ACCESS_KEY=
|
||||||
|
#
|
||||||
|
# 3. Simple (automatic fallback, no configuration needed)
|
||||||
|
# Uses basic in-memory embeddings if no provider configured
|
||||||
|
#
|
||||||
|
# Document Chunking:
|
||||||
|
# Configure how documents are split before embedding
|
||||||
|
#DOCUMENT_CHUNK_SIZE=512
|
||||||
|
#DOCUMENT_CHUNK_OVERLAP=50
|
||||||
|
|
||||||
|
# ===== SEMANTIC SEARCH TUNING =====
|
||||||
|
# Advanced parameters for vector sync background operations
|
||||||
|
# Only modify if you understand the implications
|
||||||
|
#
|
||||||
|
# Document scan interval in seconds (default: 300 = 5 minutes)
|
||||||
|
#VECTOR_SYNC_SCAN_INTERVAL=300
|
||||||
|
#
|
||||||
|
# Concurrent indexing workers (default: 3)
|
||||||
|
#VECTOR_SYNC_PROCESSOR_WORKERS=3
|
||||||
|
#
|
||||||
|
# Max queued documents (default: 10000)
|
||||||
|
#VECTOR_SYNC_QUEUE_MAX_SIZE=10000
|
||||||
|
|
||||||
|
# ===== DOCUMENT PROCESSING =====
|
||||||
|
# Extract text from PDFs, images, DOCX, etc. for semantic search
|
||||||
|
# Disabled by default
|
||||||
|
#
|
||||||
|
#ENABLE_DOCUMENT_PROCESSING=false
|
||||||
|
#DOCUMENT_PROCESSOR=unstructured
|
||||||
|
#
|
||||||
|
# Unstructured.io Processor (recommended):
|
||||||
|
#ENABLE_UNSTRUCTURED=false
|
||||||
|
#UNSTRUCTURED_API_URL=http://unstructured:8000
|
||||||
|
#UNSTRUCTURED_TIMEOUT=120
|
||||||
|
#UNSTRUCTURED_STRATEGY=auto
|
||||||
|
#UNSTRUCTURED_LANGUAGES=eng,deu
|
||||||
|
#PROGRESS_INTERVAL=10
|
||||||
|
#
|
||||||
|
# Tesseract OCR (lightweight, images only):
|
||||||
|
#ENABLE_TESSERACT=false
|
||||||
|
#TESSERACT_CMD=/usr/bin/tesseract
|
||||||
|
#TESSERACT_LANG=eng
|
||||||
|
#
|
||||||
|
# Custom Processor (your own API):
|
||||||
|
#ENABLE_CUSTOM_PROCESSOR=false
|
||||||
|
#CUSTOM_PROCESSOR_NAME=my_ocr
|
||||||
|
#CUSTOM_PROCESSOR_URL=http://localhost:9000/process
|
||||||
|
#CUSTOM_PROCESSOR_API_KEY=
|
||||||
|
#CUSTOM_PROCESSOR_TIMEOUT=60
|
||||||
|
#CUSTOM_PROCESSOR_TYPES=application/pdf,image/jpeg,image/png
|
||||||
|
|
||||||
|
# ===== SECURITY & ADVANCED =====
|
||||||
# Cookie security (browser UI)
|
# Cookie security (browser UI)
|
||||||
# Auto-detects from NEXTCLOUD_HOST protocol if not set
|
# Auto-detects from NEXTCLOUD_HOST protocol if not set
|
||||||
# Set explicitly for non-standard setups
|
|
||||||
#COOKIE_SECURE=true
|
#COOKIE_SECURE=true
|
||||||
|
|
||||||
# ============================================
|
# ============================================
|
||||||
# Document Processing Configuration
|
# DEPRECATED VARIABLES (Backward Compatibility)
|
||||||
# ============================================
|
# ============================================
|
||||||
# Enable document processing (PDF, DOCX, images, etc.)
|
# These variables still work but will be removed in v1.0.0
|
||||||
# Set to false to disable all document processing
|
# Please migrate to new names:
|
||||||
ENABLE_DOCUMENT_PROCESSING=false
|
#
|
||||||
|
# Old Name → New Name
|
||||||
# Default processor to use when multiple are available
|
# VECTOR_SYNC_ENABLED → ENABLE_SEMANTIC_SEARCH
|
||||||
# Options: unstructured, tesseract, custom
|
# ENABLE_OFFLINE_ACCESS → ENABLE_BACKGROUND_OPERATIONS
|
||||||
DOCUMENT_PROCESSOR=unstructured
|
#
|
||||||
|
# Migration is optional - both old and new names work
|
||||||
# ============================================
|
# Deprecation warnings will be logged when old names are used
|
||||||
# Unstructured.io Processor
|
|
||||||
# ============================================
|
|
||||||
# Enable Unstructured processor (requires unstructured service in docker-compose)
|
|
||||||
# This is a cloud-based/API processor supporting many document types
|
|
||||||
ENABLE_UNSTRUCTURED=false
|
|
||||||
|
|
||||||
# Unstructured API endpoint
|
|
||||||
UNSTRUCTURED_API_URL=http://unstructured:8000
|
|
||||||
|
|
||||||
# Request timeout in seconds (default: 120)
|
|
||||||
# OCR operations can take 30-120 seconds for large documents
|
|
||||||
UNSTRUCTURED_TIMEOUT=120
|
|
||||||
|
|
||||||
# Parsing strategy: auto, fast, hi_res
|
|
||||||
# - auto: Automatically choose based on document type
|
|
||||||
# - fast: Fast parsing without OCR
|
|
||||||
# - hi_res: High-resolution with OCR (slowest, most accurate)
|
|
||||||
UNSTRUCTURED_STRATEGY=auto
|
|
||||||
|
|
||||||
# OCR languages (comma-separated ISO 639-3 codes)
|
|
||||||
# Common: eng=English, deu=German, fra=French, spa=Spanish
|
|
||||||
UNSTRUCTURED_LANGUAGES=eng,deu
|
|
||||||
|
|
||||||
# Progress reporting interval in seconds (default: 10)
|
|
||||||
# During long-running OCR operations, progress notifications are sent to the MCP client
|
|
||||||
# at this interval to prevent timeouts and provide status updates
|
|
||||||
PROGRESS_INTERVAL=10
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Tesseract Processor (Local OCR)
|
|
||||||
# ============================================
|
|
||||||
# Enable Tesseract processor (requires tesseract binary installed)
|
|
||||||
# This is a local, lightweight OCR solution for images only
|
|
||||||
ENABLE_TESSERACT=false
|
|
||||||
|
|
||||||
# Path to tesseract executable (optional, auto-detected if in PATH)
|
|
||||||
#TESSERACT_CMD=/usr/bin/tesseract
|
|
||||||
|
|
||||||
# OCR language (e.g., eng, deu, eng+deu for multiple)
|
|
||||||
TESSERACT_LANG=eng
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Custom Processor (Your own API)
|
|
||||||
# ============================================
|
|
||||||
# Enable custom document processor via HTTP API
|
|
||||||
ENABLE_CUSTOM_PROCESSOR=false
|
|
||||||
|
|
||||||
# Unique name for your processor
|
|
||||||
#CUSTOM_PROCESSOR_NAME=my_ocr
|
|
||||||
|
|
||||||
# Your custom processor API endpoint
|
|
||||||
#CUSTOM_PROCESSOR_URL=http://localhost:9000/process
|
|
||||||
|
|
||||||
# Optional API key for authentication
|
|
||||||
#CUSTOM_PROCESSOR_API_KEY=your-api-key-here
|
|
||||||
|
|
||||||
# Request timeout in seconds
|
|
||||||
#CUSTOM_PROCESSOR_TIMEOUT=60
|
|
||||||
|
|
||||||
# Comma-separated MIME types your processor supports
|
|
||||||
#CUSTOM_PROCESSOR_TYPES=application/pdf,image/jpeg,image/png
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Semantic Search & Vector Sync Configuration
|
|
||||||
# ============================================
|
|
||||||
# EXPERIMENTAL: Semantic search for Notes app (multi-app support planned)
|
|
||||||
# Requires: Qdrant vector database + Ollama embedding service
|
|
||||||
# Disabled by default
|
|
||||||
|
|
||||||
# Enable background vector indexing
|
|
||||||
VECTOR_SYNC_ENABLED=false
|
|
||||||
|
|
||||||
# Document scan interval in seconds (default: 300 = 5 minutes)
|
|
||||||
# How often to check for new/updated documents
|
|
||||||
#VECTOR_SYNC_SCAN_INTERVAL=300
|
|
||||||
|
|
||||||
# Concurrent indexing workers (default: 3)
|
|
||||||
# Number of parallel workers for embedding generation
|
|
||||||
#VECTOR_SYNC_PROCESSOR_WORKERS=3
|
|
||||||
|
|
||||||
# Max queued documents (default: 10000)
|
|
||||||
# Maximum documents waiting to be processed
|
|
||||||
#VECTOR_SYNC_QUEUE_MAX_SIZE=10000
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Qdrant Vector Database Configuration
|
|
||||||
# ============================================
|
|
||||||
# Choose ONE of three modes:
|
|
||||||
# 1. In-memory mode (default): Set neither QDRANT_URL nor QDRANT_LOCATION
|
|
||||||
# 2. Persistent local: Set QDRANT_LOCATION=/path/to/data
|
|
||||||
# 3. Network mode: Set QDRANT_URL=http://qdrant:6333
|
|
||||||
|
|
||||||
# Network mode: URL to Qdrant service
|
|
||||||
#QDRANT_URL=http://qdrant:6333
|
|
||||||
|
|
||||||
# Local mode: Path to store vectors (use :memory: for in-memory)
|
|
||||||
#QDRANT_LOCATION=:memory:
|
|
||||||
|
|
||||||
# API key for network mode (optional)
|
|
||||||
#QDRANT_API_KEY=
|
|
||||||
|
|
||||||
# Collection name (optional - auto-generated if not set)
|
|
||||||
# Auto-generation format: {deployment-id}-{model-name}
|
|
||||||
# Allows safe model switching and multi-server deployments
|
|
||||||
#QDRANT_COLLECTION=nextcloud_content
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Ollama Embedding Service Configuration
|
|
||||||
# ============================================
|
|
||||||
# Ollama endpoint for embeddings (if not set, uses SimpleEmbeddingProvider fallback)
|
|
||||||
#OLLAMA_BASE_URL=http://ollama:11434
|
|
||||||
|
|
||||||
# Embedding model to use (default: nomic-embed-text, 768 dimensions)
|
|
||||||
# Changing this creates a new collection (requires re-embedding all documents)
|
|
||||||
#OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
|
||||||
|
|
||||||
# Verify SSL certificates (default: true)
|
|
||||||
#OLLAMA_VERIFY_SSL=true
|
|
||||||
|
|
||||||
# ============================================
|
|
||||||
# Document Chunking Configuration
|
|
||||||
# ============================================
|
|
||||||
# Configure how documents are split before embedding
|
|
||||||
|
|
||||||
# Words per chunk (default: 512)
|
|
||||||
# Smaller chunks (256-384): More precise, less context, more storage
|
|
||||||
# Larger chunks (768-1024): More context, less precise, less storage
|
|
||||||
#DOCUMENT_CHUNK_SIZE=512
|
|
||||||
|
|
||||||
# Overlapping words between chunks (default: 50)
|
|
||||||
# Recommended: 10-20% of chunk size
|
|
||||||
# Preserves context across chunk boundaries
|
|
||||||
#DOCUMENT_CHUNK_OVERLAP=50
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# ============================================
|
||||||
|
# OAUTH TOKEN EXCHANGE QUICK START (Advanced)
|
||||||
|
# ============================================
|
||||||
|
# Advanced OAuth deployment with RFC 8693 token exchange
|
||||||
|
# Use for: Deployments requiring separate MCP and Nextcloud tokens
|
||||||
|
# Features: Dual-audience tokens, enhanced security boundaries
|
||||||
|
#
|
||||||
|
# Copy this file to .env and configure
|
||||||
|
|
||||||
|
# ===== REQUIRED SETTINGS =====
|
||||||
|
# Your Nextcloud instance URL (without trailing slash)
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
|
||||||
|
# Enable token exchange mode
|
||||||
|
ENABLE_TOKEN_EXCHANGE=true
|
||||||
|
|
||||||
|
# ===== REQUIRED: LEAVE USERNAME/PASSWORD EMPTY =====
|
||||||
|
# OAuth mode activates when these are NOT set
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# ===== OPTIONAL: EXPLICIT MODE DECLARATION =====
|
||||||
|
# Recommended for clarity
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_token_exchange
|
||||||
|
|
||||||
|
# ===== OPTIONAL: PRE-REGISTERED OAUTH CLIENT =====
|
||||||
|
# If you pre-register the OAuth client instead of using DCR:
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_ID=your-client-id
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
|
||||||
|
|
||||||
|
# MCP Server URL (for OAuth redirects)
|
||||||
|
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
||||||
|
|
||||||
|
# ===== OPTIONAL: TOKEN EXCHANGE TUNING =====
|
||||||
|
# Cache TTL for exchanged tokens (default: 300 seconds = 5 minutes)
|
||||||
|
TOKEN_EXCHANGE_CACHE_TTL=300
|
||||||
|
|
||||||
|
# ===== OPTIONAL: SEMANTIC SEARCH =====
|
||||||
|
# AI-powered semantic search with automatic background operation setup
|
||||||
|
#
|
||||||
|
# Note: ENABLE_SEMANTIC_SEARCH automatically enables background operations
|
||||||
|
# in token exchange mode, just like in OAuth single-audience mode
|
||||||
|
#
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
|
||||||
|
# Vector Database (required for semantic search)
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
|
||||||
|
# Embedding Provider (required for semantic search)
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
||||||
|
|
||||||
|
# Token Storage (required for background operations - auto-enabled by semantic search)
|
||||||
|
# Generate encryption key: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-encryption-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
|
||||||
|
# ===== OPTIONAL: DOCUMENT PROCESSING =====
|
||||||
|
# Extract text from PDFs, images, DOCX for semantic search
|
||||||
|
#ENABLE_DOCUMENT_PROCESSING=true
|
||||||
|
#ENABLE_UNSTRUCTURED=true
|
||||||
|
#UNSTRUCTURED_API_URL=http://unstructured:8000
|
||||||
|
|
||||||
|
# ===== TOKEN EXCHANGE MODE EXPLANATION =====
|
||||||
|
# In this mode:
|
||||||
|
# 1. MCP clients authenticate with tokens scoped to "mcp-server" audience
|
||||||
|
# 2. Server exchanges MCP tokens for Nextcloud tokens on each request
|
||||||
|
# 3. Provides clear separation between MCP session and Nextcloud access
|
||||||
|
# 4. Enables fine-grained token lifecycle management
|
||||||
|
#
|
||||||
|
# When to use:
|
||||||
|
# - Strict security requirements (separate token contexts)
|
||||||
|
# - Complex multi-service architectures
|
||||||
|
# - Need independent token expiration policies
|
||||||
|
#
|
||||||
|
# When NOT to use:
|
||||||
|
# - Simple deployments (use oauth_single_audience instead)
|
||||||
|
# - High-performance requirements (token exchange adds latency)
|
||||||
|
|
||||||
|
# For more configuration options, see env.sample
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
# ============================================
|
||||||
|
# OAUTH MULTI-USER QUICK START (Recommended)
|
||||||
|
# ============================================
|
||||||
|
# Multi-user deployment with OAuth authentication
|
||||||
|
# Use for: Multi-user production deployments, enhanced security
|
||||||
|
# Features: Single-audience tokens, automatic client registration (DCR)
|
||||||
|
#
|
||||||
|
# Copy this file to .env and configure
|
||||||
|
|
||||||
|
# ===== REQUIRED SETTINGS =====
|
||||||
|
# Your Nextcloud instance URL (without trailing slash)
|
||||||
|
NEXTCLOUD_HOST=https://nextcloud.example.com
|
||||||
|
|
||||||
|
# ===== REQUIRED: LEAVE USERNAME/PASSWORD EMPTY =====
|
||||||
|
# OAuth mode activates when these are NOT set
|
||||||
|
NEXTCLOUD_USERNAME=
|
||||||
|
NEXTCLOUD_PASSWORD=
|
||||||
|
|
||||||
|
# ===== OPTIONAL: EXPLICIT MODE DECLARATION =====
|
||||||
|
# Recommended for clarity
|
||||||
|
MCP_DEPLOYMENT_MODE=oauth_single_audience
|
||||||
|
|
||||||
|
# ===== OPTIONAL: PRE-REGISTERED OAUTH CLIENT =====
|
||||||
|
# If you pre-register the OAuth client instead of using DCR:
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_ID=your-client-id
|
||||||
|
#NEXTCLOUD_OIDC_CLIENT_SECRET=your-client-secret
|
||||||
|
|
||||||
|
# MCP Server URL (for OAuth redirects)
|
||||||
|
NEXTCLOUD_MCP_SERVER_URL=http://localhost:8000
|
||||||
|
|
||||||
|
# ===== OPTIONAL: SEMANTIC SEARCH (Recommended) =====
|
||||||
|
# AI-powered semantic search with automatic background operation setup
|
||||||
|
#
|
||||||
|
# When you enable semantic search in multi-user mode:
|
||||||
|
# 1. ENABLE_SEMANTIC_SEARCH automatically enables background operations
|
||||||
|
# 2. Server requests refresh tokens for offline indexing
|
||||||
|
# 3. Tokens are stored encrypted in TOKEN_STORAGE_DB
|
||||||
|
# 4. No need to set ENABLE_BACKGROUND_OPERATIONS separately!
|
||||||
|
#
|
||||||
|
ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
|
||||||
|
# Vector Database (required for semantic search)
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
# OR for in-memory mode:
|
||||||
|
#QDRANT_LOCATION=:memory:
|
||||||
|
|
||||||
|
# Embedding Provider (required for semantic search)
|
||||||
|
# Option 1: Ollama (recommended for local deployment)
|
||||||
|
OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
||||||
|
|
||||||
|
# Option 2: Amazon Bedrock (for AWS deployments)
|
||||||
|
#AWS_REGION=us-east-1
|
||||||
|
#BEDROCK_EMBEDDING_MODEL=amazon.titan-embed-text-v2:0
|
||||||
|
|
||||||
|
# Token Storage (required for background operations - auto-enabled by semantic search)
|
||||||
|
# Generate encryption key: python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"
|
||||||
|
TOKEN_ENCRYPTION_KEY=your-encryption-key-here
|
||||||
|
TOKEN_STORAGE_DB=/app/data/tokens.db
|
||||||
|
|
||||||
|
# ===== OPTIONAL: DOCUMENT PROCESSING =====
|
||||||
|
# Extract text from PDFs, images, DOCX for semantic search
|
||||||
|
#ENABLE_DOCUMENT_PROCESSING=true
|
||||||
|
#ENABLE_UNSTRUCTURED=true
|
||||||
|
#UNSTRUCTURED_API_URL=http://unstructured:8000
|
||||||
|
|
||||||
|
# ===== SUMMARY OF AUTO-ENABLEMENT =====
|
||||||
|
# With ENABLE_SEMANTIC_SEARCH=true in OAuth mode:
|
||||||
|
# ✅ Background operations enabled automatically
|
||||||
|
# ✅ Refresh token storage enabled automatically
|
||||||
|
# ✅ OAuth credentials required (DCR or pre-registered)
|
||||||
|
# ✅ Encryption key required for token storage
|
||||||
|
#
|
||||||
|
# You only need to set ENABLE_SEMANTIC_SEARCH and provide the required
|
||||||
|
# infrastructure (Qdrant, Ollama, encryption key). The rest is automatic!
|
||||||
|
|
||||||
|
# For more advanced configuration, see env.sample
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
# ============================================
|
||||||
|
# SINGLE-USER BASICAUTH QUICK START
|
||||||
|
# ============================================
|
||||||
|
# Simplest deployment mode - one user, credentials in environment
|
||||||
|
# Use for: Personal instances, local development, testing
|
||||||
|
#
|
||||||
|
# Copy this file to .env and fill in your credentials
|
||||||
|
|
||||||
|
# ===== REQUIRED SETTINGS =====
|
||||||
|
# Your Nextcloud instance URL (without trailing slash)
|
||||||
|
NEXTCLOUD_HOST=http://localhost:8080
|
||||||
|
|
||||||
|
# Your Nextcloud credentials
|
||||||
|
NEXTCLOUD_USERNAME=admin
|
||||||
|
NEXTCLOUD_PASSWORD=password
|
||||||
|
|
||||||
|
# ===== OPTIONAL: EXPLICIT MODE DECLARATION =====
|
||||||
|
# Recommended to avoid ambiguity
|
||||||
|
MCP_DEPLOYMENT_MODE=single_user_basic
|
||||||
|
|
||||||
|
# ===== OPTIONAL: SEMANTIC SEARCH =====
|
||||||
|
# Uncomment to enable AI-powered semantic search
|
||||||
|
# Requires: Qdrant + embedding provider (Ollama or Bedrock)
|
||||||
|
#
|
||||||
|
#ENABLE_SEMANTIC_SEARCH=true
|
||||||
|
#QDRANT_LOCATION=:memory:
|
||||||
|
#OLLAMA_BASE_URL=http://ollama:11434
|
||||||
|
#OLLAMA_EMBEDDING_MODEL=nomic-embed-text
|
||||||
|
|
||||||
|
# ===== OPTIONAL: DOCUMENT PROCESSING =====
|
||||||
|
# Extract text from PDFs, images, DOCX for semantic search
|
||||||
|
#ENABLE_DOCUMENT_PROCESSING=true
|
||||||
|
#ENABLE_UNSTRUCTURED=true
|
||||||
|
#UNSTRUCTURED_API_URL=http://unstructured:8000
|
||||||
|
|
||||||
|
# That's it! Single-user mode is the simplest to configure.
|
||||||
|
# For more options, see env.sample
|
||||||
@@ -163,6 +163,12 @@ def get_document_processor_config() -> dict[str, Any]:
|
|||||||
class Settings:
|
class Settings:
|
||||||
"""Application settings from environment variables."""
|
"""Application settings from environment variables."""
|
||||||
|
|
||||||
|
# Deployment mode (ADR-021: explicit mode selection)
|
||||||
|
# Optional: If not set, mode is auto-detected from other settings
|
||||||
|
# Valid values: single_user_basic, multi_user_basic, oauth_single_audience,
|
||||||
|
# oauth_token_exchange, smithery
|
||||||
|
deployment_mode: Optional[str] = None
|
||||||
|
|
||||||
# OAuth/OIDC settings
|
# OAuth/OIDC settings
|
||||||
oidc_discovery_url: Optional[str] = None
|
oidc_discovery_url: Optional[str] = None
|
||||||
oidc_client_id: Optional[str] = None
|
oidc_client_id: Optional[str] = None
|
||||||
@@ -351,13 +357,131 @@ class Settings:
|
|||||||
return f"{deployment_id}-{model_name}"
|
return f"{deployment_id}-{model_name}"
|
||||||
|
|
||||||
|
|
||||||
|
def _get_semantic_search_enabled() -> bool:
|
||||||
|
"""Get semantic search enabled status, supporting both old and new variable names.
|
||||||
|
|
||||||
|
Supports:
|
||||||
|
- ENABLE_SEMANTIC_SEARCH (new, preferred)
|
||||||
|
- VECTOR_SYNC_ENABLED (old, deprecated)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if semantic search should be enabled
|
||||||
|
"""
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
new_value = os.getenv("ENABLE_SEMANTIC_SEARCH", "").lower() == "true"
|
||||||
|
old_value = os.getenv("VECTOR_SYNC_ENABLED", "").lower() == "true"
|
||||||
|
|
||||||
|
if new_value and old_value:
|
||||||
|
logger.warning(
|
||||||
|
"Both ENABLE_SEMANTIC_SEARCH and VECTOR_SYNC_ENABLED are set. "
|
||||||
|
"Using ENABLE_SEMANTIC_SEARCH. "
|
||||||
|
"VECTOR_SYNC_ENABLED is deprecated and will be removed in v1.0.0."
|
||||||
|
)
|
||||||
|
elif old_value and not new_value:
|
||||||
|
logger.warning(
|
||||||
|
"VECTOR_SYNC_ENABLED is deprecated. "
|
||||||
|
"Please use ENABLE_SEMANTIC_SEARCH instead. "
|
||||||
|
"Support for VECTOR_SYNC_ENABLED will be removed in v1.0.0."
|
||||||
|
)
|
||||||
|
|
||||||
|
return new_value or old_value
|
||||||
|
|
||||||
|
|
||||||
|
def _is_multi_user_mode() -> bool:
|
||||||
|
"""Detect if this is a multi-user deployment mode.
|
||||||
|
|
||||||
|
Multi-user modes are:
|
||||||
|
- Multi-user BasicAuth (ENABLE_MULTI_USER_BASIC_AUTH=true)
|
||||||
|
- OAuth Single-Audience (no username/password set)
|
||||||
|
- OAuth Token Exchange (ENABLE_TOKEN_EXCHANGE=true)
|
||||||
|
|
||||||
|
Single-user modes are:
|
||||||
|
- Single-user BasicAuth (username and password both set)
|
||||||
|
- Smithery Stateless (SMITHERY_DEPLOYMENT=true)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if multi-user mode detected
|
||||||
|
"""
|
||||||
|
# Smithery is always single-user (stateless)
|
||||||
|
if os.getenv("SMITHERY_DEPLOYMENT", "false").lower() == "true":
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Multi-user BasicAuth explicitly enabled
|
||||||
|
if os.getenv("ENABLE_MULTI_USER_BASIC_AUTH", "false").lower() == "true":
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Token exchange implies OAuth multi-user
|
||||||
|
if os.getenv("ENABLE_TOKEN_EXCHANGE", "false").lower() == "true":
|
||||||
|
return True
|
||||||
|
|
||||||
|
# If both username and password are set, it's single-user BasicAuth
|
||||||
|
has_username = bool(os.getenv("NEXTCLOUD_USERNAME"))
|
||||||
|
has_password = bool(os.getenv("NEXTCLOUD_PASSWORD"))
|
||||||
|
if has_username and has_password:
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Otherwise, assume OAuth multi-user (default when no credentials provided)
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def _get_background_operations_enabled() -> bool:
|
||||||
|
"""Get background operations enabled status with auto-enablement for semantic search.
|
||||||
|
|
||||||
|
Supports:
|
||||||
|
- ENABLE_BACKGROUND_OPERATIONS (new, preferred)
|
||||||
|
- ENABLE_OFFLINE_ACCESS (old, deprecated)
|
||||||
|
- Auto-enabled if ENABLE_SEMANTIC_SEARCH=true in multi-user modes
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if background operations should be enabled
|
||||||
|
"""
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Check new and old variable names
|
||||||
|
explicit = os.getenv("ENABLE_BACKGROUND_OPERATIONS", "").lower() == "true"
|
||||||
|
legacy = os.getenv("ENABLE_OFFLINE_ACCESS", "").lower() == "true"
|
||||||
|
|
||||||
|
if explicit and legacy:
|
||||||
|
logger.warning(
|
||||||
|
"Both ENABLE_BACKGROUND_OPERATIONS and ENABLE_OFFLINE_ACCESS are set. "
|
||||||
|
"Using ENABLE_BACKGROUND_OPERATIONS. "
|
||||||
|
"ENABLE_OFFLINE_ACCESS is deprecated and will be removed in v1.0.0."
|
||||||
|
)
|
||||||
|
elif legacy and not explicit:
|
||||||
|
logger.warning(
|
||||||
|
"ENABLE_OFFLINE_ACCESS is deprecated. "
|
||||||
|
"Please use ENABLE_BACKGROUND_OPERATIONS instead. "
|
||||||
|
"Support for ENABLE_OFFLINE_ACCESS will be removed in v1.0.0."
|
||||||
|
)
|
||||||
|
|
||||||
|
# Auto-enable if semantic search is enabled in multi-user mode
|
||||||
|
semantic_search_enabled = _get_semantic_search_enabled()
|
||||||
|
is_multi_user = _is_multi_user_mode()
|
||||||
|
auto_enabled = semantic_search_enabled and is_multi_user
|
||||||
|
|
||||||
|
if auto_enabled and not (explicit or legacy):
|
||||||
|
logger.info(
|
||||||
|
"Automatically enabled background operations for semantic search in multi-user mode. "
|
||||||
|
"Set ENABLE_BACKGROUND_OPERATIONS=false to disable (this will also disable semantic search)."
|
||||||
|
)
|
||||||
|
|
||||||
|
return explicit or legacy or auto_enabled
|
||||||
|
|
||||||
|
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
"""Get application settings from environment variables.
|
"""Get application settings from environment variables.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Settings object with configuration values
|
Settings object with configuration values
|
||||||
"""
|
"""
|
||||||
|
# Get consolidated values with smart dependency resolution
|
||||||
|
enable_semantic_search = _get_semantic_search_enabled()
|
||||||
|
enable_background_operations = _get_background_operations_enabled()
|
||||||
|
|
||||||
return Settings(
|
return Settings(
|
||||||
|
# Deployment mode (ADR-021)
|
||||||
|
deployment_mode=os.getenv("MCP_DEPLOYMENT_MODE"),
|
||||||
# OAuth/OIDC settings
|
# OAuth/OIDC settings
|
||||||
oidc_discovery_url=os.getenv("OIDC_DISCOVERY_URL"),
|
oidc_discovery_url=os.getenv("OIDC_DISCOVERY_URL"),
|
||||||
oidc_client_id=os.getenv("NEXTCLOUD_OIDC_CLIENT_ID"),
|
oidc_client_id=os.getenv("NEXTCLOUD_OIDC_CLIENT_ID"),
|
||||||
@@ -378,9 +502,7 @@ def get_settings() -> Settings:
|
|||||||
enable_token_exchange=(
|
enable_token_exchange=(
|
||||||
os.getenv("ENABLE_TOKEN_EXCHANGE", "false").lower() == "true"
|
os.getenv("ENABLE_TOKEN_EXCHANGE", "false").lower() == "true"
|
||||||
),
|
),
|
||||||
enable_offline_access=(
|
enable_offline_access=enable_background_operations, # Smart dependency resolution
|
||||||
os.getenv("ENABLE_OFFLINE_ACCESS", "false").lower() == "true"
|
|
||||||
),
|
|
||||||
# Multi-user BasicAuth pass-through mode
|
# Multi-user BasicAuth pass-through mode
|
||||||
enable_multi_user_basic_auth=(
|
enable_multi_user_basic_auth=(
|
||||||
os.getenv("ENABLE_MULTI_USER_BASIC_AUTH", "false").lower() == "true"
|
os.getenv("ENABLE_MULTI_USER_BASIC_AUTH", "false").lower() == "true"
|
||||||
@@ -391,9 +513,7 @@ def get_settings() -> Settings:
|
|||||||
token_encryption_key=os.getenv("TOKEN_ENCRYPTION_KEY"),
|
token_encryption_key=os.getenv("TOKEN_ENCRYPTION_KEY"),
|
||||||
token_storage_db=os.getenv("TOKEN_STORAGE_DB", "/tmp/tokens.db"),
|
token_storage_db=os.getenv("TOKEN_STORAGE_DB", "/tmp/tokens.db"),
|
||||||
# Vector sync settings (ADR-007)
|
# Vector sync settings (ADR-007)
|
||||||
vector_sync_enabled=(
|
vector_sync_enabled=enable_semantic_search, # Smart dependency resolution
|
||||||
os.getenv("VECTOR_SYNC_ENABLED", "false").lower() == "true"
|
|
||||||
),
|
|
||||||
vector_sync_scan_interval=int(os.getenv("VECTOR_SYNC_SCAN_INTERVAL", "300")),
|
vector_sync_scan_interval=int(os.getenv("VECTOR_SYNC_SCAN_INTERVAL", "300")),
|
||||||
vector_sync_processor_workers=int(
|
vector_sync_processor_workers=int(
|
||||||
os.getenv("VECTOR_SYNC_PROCESSOR_WORKERS", "3")
|
os.getenv("VECTOR_SYNC_PROCESSOR_WORKERS", "3")
|
||||||
|
|||||||
@@ -110,10 +110,9 @@ MODE_REQUIREMENTS: dict[AuthMode, ModeRequirements] = {
|
|||||||
"token_encryption_key",
|
"token_encryption_key",
|
||||||
"token_storage_db",
|
"token_storage_db",
|
||||||
],
|
],
|
||||||
"vector_sync_enabled": [
|
# Note: vector_sync_enabled (now ENABLE_SEMANTIC_SEARCH) automatically
|
||||||
# Requires offline access for background sync
|
# enables background operations in multi-user modes. No explicit
|
||||||
"enable_offline_access",
|
# enable_offline_access setting required.
|
||||||
],
|
|
||||||
},
|
},
|
||||||
description="Multi-user deployment with BasicAuth pass-through. "
|
description="Multi-user deployment with BasicAuth pass-through. "
|
||||||
"Users provide credentials in request headers. "
|
"Users provide credentials in request headers. "
|
||||||
@@ -152,9 +151,9 @@ MODE_REQUIREMENTS: dict[AuthMode, ModeRequirements] = {
|
|||||||
"token_encryption_key",
|
"token_encryption_key",
|
||||||
"token_storage_db",
|
"token_storage_db",
|
||||||
],
|
],
|
||||||
"vector_sync_enabled": [
|
# Note: vector_sync_enabled (now ENABLE_SEMANTIC_SEARCH) automatically
|
||||||
"enable_offline_access", # Background sync requires refresh tokens
|
# enables background operations in multi-user modes. No explicit
|
||||||
],
|
# enable_offline_access setting required.
|
||||||
},
|
},
|
||||||
description="OAuth multi-user deployment with single-audience tokens. "
|
description="OAuth multi-user deployment with single-audience tokens. "
|
||||||
"Tokens work for both MCP server and Nextcloud APIs (pass-through). "
|
"Tokens work for both MCP server and Nextcloud APIs (pass-through). "
|
||||||
@@ -192,9 +191,9 @@ MODE_REQUIREMENTS: dict[AuthMode, ModeRequirements] = {
|
|||||||
"token_encryption_key",
|
"token_encryption_key",
|
||||||
"token_storage_db",
|
"token_storage_db",
|
||||||
],
|
],
|
||||||
"vector_sync_enabled": [
|
# Note: vector_sync_enabled (now ENABLE_SEMANTIC_SEARCH) automatically
|
||||||
"enable_offline_access",
|
# enables background operations in multi-user modes. No explicit
|
||||||
],
|
# enable_offline_access setting required.
|
||||||
},
|
},
|
||||||
description="OAuth multi-user deployment with token exchange (RFC 8693). "
|
description="OAuth multi-user deployment with token exchange (RFC 8693). "
|
||||||
"MCP tokens are separate from Nextcloud tokens. "
|
"MCP tokens are separate from Nextcloud tokens. "
|
||||||
@@ -225,7 +224,8 @@ MODE_REQUIREMENTS: dict[AuthMode, ModeRequirements] = {
|
|||||||
def detect_auth_mode(settings: Settings) -> AuthMode:
|
def detect_auth_mode(settings: Settings) -> AuthMode:
|
||||||
"""Detect authentication mode from configuration.
|
"""Detect authentication mode from configuration.
|
||||||
|
|
||||||
Mode detection priority (most specific to most general):
|
Mode detection priority (ADR-021):
|
||||||
|
0. Explicit MCP_DEPLOYMENT_MODE (if set) - NEW in ADR-021
|
||||||
1. Smithery (explicit flag)
|
1. Smithery (explicit flag)
|
||||||
2. Token exchange (most specific OAuth mode)
|
2. Token exchange (most specific OAuth mode)
|
||||||
3. Multi-user BasicAuth
|
3. Multi-user BasicAuth
|
||||||
@@ -237,12 +237,43 @@ def detect_auth_mode(settings: Settings) -> AuthMode:
|
|||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Detected AuthMode
|
Detected AuthMode
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: If explicit deployment_mode is invalid or conflicts with detected mode
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
import os
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# ADR-021: Check for explicit deployment mode first
|
||||||
|
if settings.deployment_mode:
|
||||||
|
mode_str = settings.deployment_mode.lower().strip()
|
||||||
|
|
||||||
|
# Map string to AuthMode enum
|
||||||
|
mode_map = {
|
||||||
|
"single_user_basic": AuthMode.SINGLE_USER_BASIC,
|
||||||
|
"multi_user_basic": AuthMode.MULTI_USER_BASIC,
|
||||||
|
"oauth_single_audience": AuthMode.OAUTH_SINGLE_AUDIENCE,
|
||||||
|
"oauth_token_exchange": AuthMode.OAUTH_TOKEN_EXCHANGE,
|
||||||
|
"smithery": AuthMode.SMITHERY_STATELESS,
|
||||||
|
}
|
||||||
|
|
||||||
|
if mode_str not in mode_map:
|
||||||
|
valid_modes = ", ".join(mode_map.keys())
|
||||||
|
raise ValueError(
|
||||||
|
f"Invalid MCP_DEPLOYMENT_MODE: '{settings.deployment_mode}'. "
|
||||||
|
f"Valid values: {valid_modes}"
|
||||||
|
)
|
||||||
|
|
||||||
|
explicit_mode = mode_map[mode_str]
|
||||||
|
logger.info(f"Using explicit deployment mode: {explicit_mode.value}")
|
||||||
|
return explicit_mode
|
||||||
|
|
||||||
|
# Auto-detection (existing behavior)
|
||||||
# Check for Smithery mode (explicit environment variable)
|
# Check for Smithery mode (explicit environment variable)
|
||||||
# Note: This checks the environment directly, not settings
|
# Note: This checks the environment directly, not settings
|
||||||
# because Smithery mode has no settings-based config
|
# because Smithery mode has no settings-based config
|
||||||
import os
|
|
||||||
|
|
||||||
if os.getenv("SMITHERY_DEPLOYMENT", "false").lower() == "true":
|
if os.getenv("SMITHERY_DEPLOYMENT", "false").lower() == "true":
|
||||||
return AuthMode.SMITHERY_STATELESS
|
return AuthMode.SMITHERY_STATELESS
|
||||||
|
|
||||||
@@ -364,22 +395,20 @@ def validate_configuration(settings: Settings) -> tuple[AuthMode, list[str]]:
|
|||||||
)
|
)
|
||||||
|
|
||||||
if mode == AuthMode.MULTI_USER_BASIC:
|
if mode == AuthMode.MULTI_USER_BASIC:
|
||||||
# Validate that if offline access enabled, we have OAuth credentials
|
# Validate that if background operations enabled, we have OAuth credentials
|
||||||
if settings.enable_offline_access:
|
if settings.enable_offline_access:
|
||||||
if not settings.oidc_client_id or not settings.oidc_client_secret:
|
if not settings.oidc_client_id or not settings.oidc_client_secret:
|
||||||
errors.append(
|
errors.append(
|
||||||
f"[{mode.value}] NEXTCLOUD_OIDC_CLIENT_ID and "
|
f"[{mode.value}] NEXTCLOUD_OIDC_CLIENT_ID and "
|
||||||
"NEXTCLOUD_OIDC_CLIENT_SECRET are required when "
|
"NEXTCLOUD_OIDC_CLIENT_SECRET are required when "
|
||||||
"ENABLE_OFFLINE_ACCESS is enabled (for app password retrieval)"
|
"ENABLE_BACKGROUND_OPERATIONS (or deprecated ENABLE_OFFLINE_ACCESS) "
|
||||||
|
"is enabled (for app password retrieval)"
|
||||||
)
|
)
|
||||||
|
|
||||||
# Validate vector sync requirements
|
# Note: Vector sync no longer requires explicit ENABLE_OFFLINE_ACCESS setting
|
||||||
if settings.vector_sync_enabled and not settings.enable_offline_access:
|
# ENABLE_SEMANTIC_SEARCH (formerly VECTOR_SYNC_ENABLED) automatically enables
|
||||||
errors.append(
|
# background operations in multi-user modes via smart dependency resolution
|
||||||
f"[{mode.value}] ENABLE_OFFLINE_ACCESS must be enabled when "
|
# in config.py
|
||||||
"VECTOR_SYNC_ENABLED is true (background sync requires "
|
|
||||||
"app passwords or refresh tokens)"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Note: Embedding provider validation removed - Simple provider is always
|
# Note: Embedding provider validation removed - Simple provider is always
|
||||||
# available as fallback (ADR-015). Users can optionally configure Ollama or OpenAI
|
# available as fallback (ADR-015). Users can optionally configure Ollama or OpenAI
|
||||||
|
|||||||
@@ -311,20 +311,35 @@ class TestMultiUserBasicValidation:
|
|||||||
assert mode == AuthMode.MULTI_USER_BASIC
|
assert mode == AuthMode.MULTI_USER_BASIC
|
||||||
assert any("token_encryption_key" in err.lower() for err in errors)
|
assert any("token_encryption_key" in err.lower() for err in errors)
|
||||||
|
|
||||||
def test_vector_sync_requires_offline_access(self):
|
def test_vector_sync_auto_enables_background_ops_in_multi_user_mode(self):
|
||||||
"""Test error when vector sync enabled but offline access disabled."""
|
"""Test vector sync automatically enables background operations in multi-user mode (ADR-021)."""
|
||||||
settings = Settings(
|
# Before ADR-021: This would have failed validation (required explicit ENABLE_OFFLINE_ACCESS)
|
||||||
nextcloud_host="http://localhost",
|
# After ADR-021: vector_sync_enabled auto-enables background operations
|
||||||
enable_multi_user_basic_auth=True,
|
with patch.dict(
|
||||||
vector_sync_enabled=True,
|
os.environ,
|
||||||
qdrant_location=":memory:",
|
{
|
||||||
ollama_base_url="http://ollama:11434",
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
)
|
"ENABLE_MULTI_USER_BASIC_AUTH": "true",
|
||||||
|
"VECTOR_SYNC_ENABLED": "true", # Using old name for backward compat test
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
"OLLAMA_BASE_URL": "http://ollama:11434",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
"NEXTCLOUD_OIDC_CLIENT_ID": "test-client-id",
|
||||||
|
"NEXTCLOUD_OIDC_CLIENT_SECRET": "test-client-secret",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
mode, errors = validate_configuration(settings)
|
settings = get_settings()
|
||||||
|
mode, errors = validate_configuration(settings)
|
||||||
|
|
||||||
assert mode == AuthMode.MULTI_USER_BASIC
|
assert mode == AuthMode.MULTI_USER_BASIC
|
||||||
assert any("enable_offline_access" in err.lower() for err in errors)
|
# Should have no errors - background operations auto-enabled
|
||||||
|
assert len(errors) == 0
|
||||||
|
# Verify background operations were auto-enabled
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
|
||||||
class TestOAuthSingleAudienceValidation:
|
class TestOAuthSingleAudienceValidation:
|
||||||
@@ -396,19 +411,33 @@ class TestOAuthSingleAudienceValidation:
|
|||||||
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
assert any("token_encryption_key" in err.lower() for err in errors)
|
assert any("token_encryption_key" in err.lower() for err in errors)
|
||||||
|
|
||||||
def test_vector_sync_requires_offline_access(self):
|
def test_vector_sync_auto_enables_background_ops_in_oauth_mode(self):
|
||||||
"""Test error when vector sync enabled but offline access disabled."""
|
"""Test vector sync automatically enables background operations in OAuth mode (ADR-021)."""
|
||||||
settings = Settings(
|
# Before ADR-021: This would have failed validation (required explicit ENABLE_OFFLINE_ACCESS)
|
||||||
nextcloud_host="http://localhost",
|
# After ADR-021: vector_sync_enabled auto-enables background operations in multi-user modes
|
||||||
vector_sync_enabled=True,
|
with patch.dict(
|
||||||
qdrant_location=":memory:",
|
os.environ,
|
||||||
ollama_base_url="http://ollama:11434",
|
{
|
||||||
)
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"VECTOR_SYNC_ENABLED": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
"OLLAMA_BASE_URL": "http://ollama:11434",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
# Note: No username/password = OAuth mode
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
mode, errors = validate_configuration(settings)
|
settings = get_settings()
|
||||||
|
mode, errors = validate_configuration(settings)
|
||||||
|
|
||||||
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
assert any("enable_offline_access" in err.lower() for err in errors)
|
# Should have no errors - background operations auto-enabled
|
||||||
|
assert len(errors) == 0
|
||||||
|
# Verify background operations were auto-enabled
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
|
||||||
class TestOAuthTokenExchangeValidation:
|
class TestOAuthTokenExchangeValidation:
|
||||||
@@ -576,3 +605,387 @@ class TestEdgeCases:
|
|||||||
|
|
||||||
# Should have errors for missing host (OAuth mode is default)
|
# Should have errors for missing host (OAuth mode is default)
|
||||||
assert len(errors) > 0
|
assert len(errors) > 0
|
||||||
|
|
||||||
|
|
||||||
|
class TestConfigurationConsolidation:
|
||||||
|
"""Test ADR-021 configuration consolidation and backward compatibility.
|
||||||
|
|
||||||
|
Tests verify:
|
||||||
|
- New variable names work (ENABLE_SEMANTIC_SEARCH, ENABLE_BACKGROUND_OPERATIONS)
|
||||||
|
- Old variable names still work (VECTOR_SYNC_ENABLED, ENABLE_OFFLINE_ACCESS)
|
||||||
|
- Deprecation warnings are logged
|
||||||
|
- Auto-enablement of background operations in multi-user modes
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_new_semantic_search_variable_name(self):
|
||||||
|
"""Test ENABLE_SEMANTIC_SEARCH (new name) works correctly."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"ENABLE_SEMANTIC_SEARCH": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
assert settings.vector_sync_enabled is True
|
||||||
|
|
||||||
|
def test_old_vector_sync_variable_name_backward_compat(self):
|
||||||
|
"""Test VECTOR_SYNC_ENABLED (old name) still works for backward compatibility."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"VECTOR_SYNC_ENABLED": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
assert settings.vector_sync_enabled is True
|
||||||
|
|
||||||
|
def test_new_background_operations_variable_name(self):
|
||||||
|
"""Test ENABLE_BACKGROUND_OPERATIONS (new name) works correctly."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"ENABLE_BACKGROUND_OPERATIONS": "true",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
def test_old_offline_access_variable_name_backward_compat(self):
|
||||||
|
"""Test ENABLE_OFFLINE_ACCESS (old name) still works for backward compatibility."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"ENABLE_OFFLINE_ACCESS": "true",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
def test_semantic_search_auto_enables_background_ops_in_oauth_mode(self):
|
||||||
|
"""Test ENABLE_SEMANTIC_SEARCH automatically enables background operations in OAuth mode."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"ENABLE_SEMANTIC_SEARCH": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
# Note: No NEXTCLOUD_USERNAME/PASSWORD = OAuth mode
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Semantic search enabled
|
||||||
|
assert settings.vector_sync_enabled is True
|
||||||
|
|
||||||
|
# Background operations auto-enabled (even though not explicitly set)
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
def test_semantic_search_does_not_auto_enable_in_single_user_mode(self):
|
||||||
|
"""Test ENABLE_SEMANTIC_SEARCH does NOT auto-enable background ops in single-user mode."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"NEXTCLOUD_USERNAME": "admin",
|
||||||
|
"NEXTCLOUD_PASSWORD": "password",
|
||||||
|
"ENABLE_SEMANTIC_SEARCH": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
# Note: Username/password set = single-user BasicAuth mode
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Semantic search enabled
|
||||||
|
assert settings.vector_sync_enabled is True
|
||||||
|
|
||||||
|
# Background operations NOT auto-enabled (not needed in single-user mode)
|
||||||
|
assert settings.enable_offline_access is False
|
||||||
|
|
||||||
|
def test_explicit_background_ops_still_works(self):
|
||||||
|
"""Test explicitly setting ENABLE_BACKGROUND_OPERATIONS works even without semantic search."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"ENABLE_BACKGROUND_OPERATIONS": "true",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
# Note: No semantic search enabled
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Semantic search NOT enabled
|
||||||
|
assert settings.vector_sync_enabled is False
|
||||||
|
|
||||||
|
# Background operations explicitly enabled
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
def test_both_old_and_new_semantic_search_names_prefers_new(self):
|
||||||
|
"""Test setting both ENABLE_SEMANTIC_SEARCH and VECTOR_SYNC_ENABLED uses new name."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"ENABLE_SEMANTIC_SEARCH": "true",
|
||||||
|
"VECTOR_SYNC_ENABLED": "false", # Old name says false
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Should use new name value (true)
|
||||||
|
assert settings.vector_sync_enabled is True
|
||||||
|
|
||||||
|
def test_both_old_and_new_background_ops_names_prefers_new(self):
|
||||||
|
"""Test setting both ENABLE_BACKGROUND_OPERATIONS and ENABLE_OFFLINE_ACCESS uses new name."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"ENABLE_BACKGROUND_OPERATIONS": "true",
|
||||||
|
"ENABLE_OFFLINE_ACCESS": "false", # Old name says false
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Should use new name value (true)
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
def test_validation_no_longer_requires_both_variables(self):
|
||||||
|
"""Test validation no longer requires explicit ENABLE_OFFLINE_ACCESS when semantic search enabled."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"ENABLE_MULTI_USER_BASIC_AUTH": "true",
|
||||||
|
"ENABLE_SEMANTIC_SEARCH": "true",
|
||||||
|
"QDRANT_LOCATION": ":memory:",
|
||||||
|
"TOKEN_ENCRYPTION_KEY": "test-key",
|
||||||
|
"TOKEN_STORAGE_DB": "/tmp/test.db",
|
||||||
|
# OAuth credentials required for app password retrieval (when background ops enabled)
|
||||||
|
"NEXTCLOUD_OIDC_CLIENT_ID": "test-client-id",
|
||||||
|
"NEXTCLOUD_OIDC_CLIENT_SECRET": "test-client-secret",
|
||||||
|
# Note: ENABLE_OFFLINE_ACCESS not set - should auto-enable
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode, errors = validate_configuration(settings)
|
||||||
|
|
||||||
|
# Should have no validation errors
|
||||||
|
# (Previously would have required explicit ENABLE_OFFLINE_ACCESS)
|
||||||
|
assert len(errors) == 0
|
||||||
|
assert mode == AuthMode.MULTI_USER_BASIC
|
||||||
|
# Verify background operations were auto-enabled
|
||||||
|
assert settings.enable_offline_access is True
|
||||||
|
|
||||||
|
|
||||||
|
class TestExplicitModeSelection:
|
||||||
|
"""Test ADR-021 explicit mode selection via MCP_DEPLOYMENT_MODE.
|
||||||
|
|
||||||
|
Tests verify:
|
||||||
|
- Explicit mode selection works for all modes
|
||||||
|
- Invalid mode names raise ValueError
|
||||||
|
- Explicit mode takes precedence over auto-detection
|
||||||
|
"""
|
||||||
|
|
||||||
|
def test_explicit_single_user_basic_mode(self):
|
||||||
|
"""Test explicit single_user_basic mode selection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "single_user_basic",
|
||||||
|
"NEXTCLOUD_USERNAME": "admin",
|
||||||
|
"NEXTCLOUD_PASSWORD": "password",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.SINGLE_USER_BASIC
|
||||||
|
|
||||||
|
def test_explicit_multi_user_basic_mode(self):
|
||||||
|
"""Test explicit multi_user_basic mode selection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "multi_user_basic",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.MULTI_USER_BASIC
|
||||||
|
|
||||||
|
def test_explicit_oauth_single_audience_mode(self):
|
||||||
|
"""Test explicit oauth_single_audience mode selection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "oauth_single_audience",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
|
|
||||||
|
def test_explicit_oauth_token_exchange_mode(self):
|
||||||
|
"""Test explicit oauth_token_exchange mode selection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "oauth_token_exchange",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.OAUTH_TOKEN_EXCHANGE
|
||||||
|
|
||||||
|
def test_explicit_smithery_mode(self):
|
||||||
|
"""Test explicit smithery mode selection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"MCP_DEPLOYMENT_MODE": "smithery",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.SMITHERY_STATELESS
|
||||||
|
|
||||||
|
def test_invalid_deployment_mode_raises_error(self):
|
||||||
|
"""Test invalid MCP_DEPLOYMENT_MODE raises ValueError."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "invalid_mode",
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
|
||||||
|
# Should raise ValueError with clear message
|
||||||
|
try:
|
||||||
|
detect_auth_mode(settings)
|
||||||
|
assert False, "Should have raised ValueError"
|
||||||
|
except ValueError as e:
|
||||||
|
assert "Invalid MCP_DEPLOYMENT_MODE" in str(e)
|
||||||
|
assert "invalid_mode" in str(e)
|
||||||
|
assert "Valid values:" in str(e)
|
||||||
|
|
||||||
|
def test_explicit_mode_overrides_auto_detection(self):
|
||||||
|
"""Test explicit mode takes precedence over auto-detection."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"NEXTCLOUD_USERNAME": "admin", # Would auto-detect as single_user_basic
|
||||||
|
"NEXTCLOUD_PASSWORD": "password",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "oauth_single_audience", # Explicit override
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
# Should use explicit mode, not auto-detected mode
|
||||||
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
|
|
||||||
|
def test_case_insensitive_mode_names(self):
|
||||||
|
"""Test MCP_DEPLOYMENT_MODE is case-insensitive."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": "OAUTH_SINGLE_AUDIENCE", # Uppercase
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
|
|
||||||
|
def test_whitespace_in_mode_name_stripped(self):
|
||||||
|
"""Test whitespace in MCP_DEPLOYMENT_MODE is stripped."""
|
||||||
|
with patch.dict(
|
||||||
|
os.environ,
|
||||||
|
{
|
||||||
|
"NEXTCLOUD_HOST": "http://localhost:8080",
|
||||||
|
"MCP_DEPLOYMENT_MODE": " oauth_single_audience ", # Whitespace
|
||||||
|
},
|
||||||
|
clear=True,
|
||||||
|
):
|
||||||
|
from nextcloud_mcp_server.config import get_settings
|
||||||
|
|
||||||
|
settings = get_settings()
|
||||||
|
mode = detect_auth_mode(settings)
|
||||||
|
|
||||||
|
assert mode == AuthMode.OAUTH_SINGLE_AUDIENCE
|
||||||
|
|||||||
Reference in New Issue
Block a user