diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index f8b3af0..84a9e6c 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -6,8 +6,15 @@ repos: - id: commitizen-branch stages: - pre-push -- repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.5 +- repo: local hooks: - id: ruff-check + name: ruff-check + entry: uv run ruff check + language: system + types: [python] - id: ruff-format + name: ruff-format + entry: uv run ruff format + language: system + types: [python] diff --git a/CLAUDE.md b/CLAUDE.md index 69db26a..f7e5e87 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,6 +38,9 @@ mcp run --transport sse nextcloud_mcp_server.app:mcp # Docker development environment with Nextcloud instance docker-compose up +# After code changes, rebuild and restart only the MCP server container +docker-compose up --build -d mcp + # Build Docker image docker build -t nextcloud-mcp-server . ``` @@ -96,6 +99,7 @@ Each Nextcloud app has a corresponding server module that: - **Integration tests** in `tests/integration/` - Test real Nextcloud API interactions - **Fixtures** in `tests/conftest.py` - Shared test setup and utilities - Tests are marked with `@pytest.mark.integration` for selective running +- **Important**: Integration tests run against live Docker containers. After making code changes to the MCP server, rebuild only the MCP container with `docker-compose up --build -d mcp` before running tests ### Configuration Files diff --git a/nextcloud_mcp_server/client/base.py b/nextcloud_mcp_server/client/base.py index 664353b..3dbabdf 100644 --- a/nextcloud_mcp_server/client/base.py +++ b/nextcloud_mcp_server/client/base.py @@ -39,6 +39,13 @@ def retry_on_429(func): f"429 Client Error: Too Many Requests, Number of attempts: {retries}" ) time.sleep(5) + elif e.response.status_code == 404: + # 404 errors are often expected (e.g., checking if attachments exist) + # Log as debug instead of warning + logger.debug( + f"HTTPStatusError {e.response.status_code}: {e}, Number of attempts: {retries}" + ) + raise else: logger.warning( f"HTTPStatusError {e.response.status_code}: {e}, Number of attempts: {retries}" diff --git a/nextcloud_mcp_server/client/webdav.py b/nextcloud_mcp_server/client/webdav.py index fbe4f28..d6f3fd9 100644 --- a/nextcloud_mcp_server/client/webdav.py +++ b/nextcloud_mcp_server/client/webdav.py @@ -31,7 +31,7 @@ class WebDAVClient(BaseNextcloudClient): # First try a PROPFIND to verify resource exists propfind_headers = {"Depth": "0", "OCS-APIRequest": "true"} try: - propfind_resp = await self._client.request( + propfind_resp = await self._make_request( "PROPFIND", webdav_path, headers=propfind_headers ) logger.debug( @@ -44,8 +44,7 @@ class WebDAVClient(BaseNextcloudClient): # For other errors, continue with deletion attempt # Proceed with deletion - response = await self._client.delete(webdav_path, headers=headers) - response.raise_for_status() + response = await self._make_request("DELETE", webdav_path, headers=headers) logger.debug(f"Successfully deleted WebDAV resource '{path}'") return {"status_code": response.status_code}