From 03b984d5a7da24c3f514161dd75198515f4b9459 Mon Sep 17 00:00:00 2001 From: Chris Coutinho Date: Sat, 22 Nov 2025 22:01:18 +0100 Subject: [PATCH] fix(smithery): Enable JSON response format for scanner compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Smithery scanner was reporting "0 tools" despite the server returning valid tool definitions. Root cause: the server was returning SSE-formatted responses (event: message\ndata: {...}) which the scanner couldn't parse. Changes: - Add json_response=True to FastMCP for Smithery stateless mode - Clean up verbose docstring examples in semantic.py and webdav.py The MCP spec allows both SSE and plain JSON responses for HTTP transport. Setting json_response=True returns Content-Type: application/json with plain JSON-RPC instead of text/event-stream with SSE format. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- nextcloud_mcp_server/app.py | 6 +++++- nextcloud_mcp_server/server/semantic.py | 21 --------------------- nextcloud_mcp_server/server/webdav.py | 14 -------------- 3 files changed, 5 insertions(+), 36 deletions(-) diff --git a/nextcloud_mcp_server/app.py b/nextcloud_mcp_server/app.py index dd3357a..5e0a5be 100644 --- a/nextcloud_mcp_server/app.py +++ b/nextcloud_mcp_server/app.py @@ -1072,7 +1072,11 @@ def get_app(transport: str = "sse", enabled_apps: list[str] | None = None): # ADR-016: Use Smithery lifespan for stateless mode, BasicAuth otherwise if deployment_mode == DeploymentMode.SMITHERY_STATELESS: logger.info("Configuring MCP server for Smithery stateless mode") - mcp = FastMCP("Nextcloud MCP", lifespan=app_lifespan_smithery) + # json_response=True returns plain JSON-RPC instead of SSE format, + # required for Smithery scanner compatibility + mcp = FastMCP( + "Nextcloud MCP", lifespan=app_lifespan_smithery, json_response=True + ) else: logger.info("Configuring MCP server for BasicAuth mode") mcp = FastMCP("Nextcloud MCP", lifespan=app_lifespan_basic) diff --git a/nextcloud_mcp_server/server/semantic.py b/nextcloud_mcp_server/server/semantic.py index 65f0a97..3d88369 100644 --- a/nextcloud_mcp_server/server/semantic.py +++ b/nextcloud_mcp_server/server/semantic.py @@ -335,27 +335,6 @@ def configure_semantic_tools(mcp: FastMCP): Note: Requires MCP client to support sampling. If sampling is unavailable, the tool gracefully degrades to returning documents with an explanation. The client may prompt the user to approve the sampling request. - - Examples: - >>> # Query about objectives across multiple apps - >>> result = await nc_semantic_search_answer( - ... query="What are my Q1 2025 project goals?", - ... ctx=ctx - ... ) - >>> print(result.generated_answer) - "Based on Document 1 (note: Project Kickoff), Document 2 (calendar event: - Q1 Planning Meeting), and Document 3 (deck card: Implement semantic search), - your main goals are: 1) Improve semantic search accuracy by 20%, - 2) Deploy new embedding model, 3) Reduce indexing latency..." - - >>> # Query about appointments - >>> result = await nc_semantic_search_answer( - ... query="When is my next dentist appointment?", - ... ctx=ctx, - ... limit=10 - ... ) - >>> len(result.sources) # Calendar events and related notes - 3 """ # 1. Retrieve relevant documents via existing semantic search search_response = await nc_semantic_search( diff --git a/nextcloud_mcp_server/server/webdav.py b/nextcloud_mcp_server/server/webdav.py index 856bcdf..720e5b0 100644 --- a/nextcloud_mcp_server/server/webdav.py +++ b/nextcloud_mcp_server/server/webdav.py @@ -64,20 +64,6 @@ def configure_webdav_tools(mcp: FastMCP): - Text files are decoded to UTF-8 - Documents (PDF, DOCX, etc.) are parsed and text is extracted - Other binary files are base64 encoded - - Examples: - # Read a text file - result = await nc_webdav_read_file("Documents/readme.txt") - logger.info(result['content']) # Decoded text content - - # Read a PDF document (automatically parsed) - result = await nc_webdav_read_file("Documents/report.pdf") - logger.info(result['content']) # Extracted text from PDF - logger.info(result['parsing_metadata']) # Document parsing info - - # Read a binary file - result = await nc_webdav_read_file("Images/photo.jpg") - logger.info(result['encoding']) # 'base64' """ client = await get_client(ctx) content, content_type = await client.webdav.read_file(path)