- Fix inconsistent error code in set_collective_emoji (400 → -32603)
- Allow clearing emoji via set_collective_emoji(emoji=None)
- Remove destructiveHint from trash operations (soft deletes are recoverable)
- Change delete_collective to idempotentHint=False (requires trash precondition)
- Add restore_collective and get_trashed_collectives tools
- Add unit tests for ValueError guard, clear-emoji path, and new tools
- Add integration test for full trash/restore/delete lifecycle
- Verify move_page returns new title in response message
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Bug fixes:
- Catch OCSError/HTTPStatusError in all server tools, convert to McpError
- Guard update_collective against empty body (raise ValueError)
- Use restore_page response data in status message
ADR-017 annotation fix:
- Distinguish "remove" (reversible association) from "delete" (permanent):
remove_tag and deck_remove_label_from_card no longer set destructiveHint
- Update annotation test to exclude "remove" from destructive keywords
Data model improvements:
- Add trashTimestamp field to PageInfo
- Create ListTrashedPagesResponse with is_trash context flag
- Add collective_id to ListTagsResponse
Test robustness:
- Read NC credentials from environment variables (not hardcoded)
- Filter landing page by parentId == 0 instead of assuming pages[0]
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add destructiveHint=True to deck_remove_label_from_card and
deck_unassign_user_from_card (ADR-017 compliance)
- Set idempotentHint=True since remove operations produce same end state
- Update test_annotations.py to exclude nc_webdav_create_directory from
non-idempotent check (MKCOL is idempotent by design - returns 405 if exists)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Address all reviewer comments from PR #387:
1. ✅ Add unit tests for annotations (tests/server/test_annotations.py)
- 10 comprehensive test functions validating all annotation patterns
- Tests for titles, read-only, destructive, idempotent operations
- Validates specific ADR-017 decisions (webdav write, semantic search)
- Cross-category consistency checks
2. ✅ Fix nc_webdav_write_file idempotency classification
- Changed from idempotentHint=False to idempotentHint=True
- Rationale: Uses HTTP PUT without version control
- Writing same content to same path = same end state (idempotent)
3. ✅ Fix semantic search openWorldHint inconsistency
- Changed from openWorldHint=False to openWorldHint=True
- Rationale: Consistent with other Nextcloud tools
- Nextcloud is external to MCP server (indexed data is implementation detail)
4. ✅ Update ADR-017 with resolved decisions
- Converted Open Questions to Resolved Questions
- Added detailed rationale for webdav write and semantic search
- Updated status from Proposed to Implemented
- Added decision timeline with dates
5. ✅ Add MCP Tool Annotations guidelines to CLAUDE.md
- Comprehensive section with code examples for all patterns
- Key principles documented (idempotency, destructive, open world)
- References ADR-017 for detailed rationale
All OAuth tools verified to have proper annotations (oauth_tools.py lines 686-751).