|
| 1 | +# MCP SSE Implementation Fix for Claude.ai |
| 2 | + |
| 3 | +## Problem Summary |
| 4 | + |
| 5 | +The StrunzKnowledge MCP server shows "NO PROVIDED TOOLS" in Claude.ai despite the server reporting tools. The issue stems from fundamental implementation errors in how tools are exposed via the SSE transport. |
| 6 | + |
| 7 | +## Root Causes |
| 8 | + |
| 9 | +### 1. Incorrect Tool Registry Pattern |
| 10 | + |
| 11 | +**Current (Wrong):** |
| 12 | +```python |
| 13 | +# Trying to extract handler methods as tools |
| 14 | +for tool_name in dir(server_instance): |
| 15 | + if tool_name.startswith('_handle_'): |
| 16 | + actual_name = tool_name.replace('_handle_', '') |
| 17 | + tool_registry[actual_name] = getattr(server_instance, tool_name) |
| 18 | +``` |
| 19 | + |
| 20 | +**Issue:** The MCP SDK doesn't expose tools this way. Tools are defined in the `list_tools()` decorator, not as individual handler methods. |
| 21 | + |
| 22 | +### 2. Incorrect Tool Schema Generation |
| 23 | + |
| 24 | +**Current (Wrong):** |
| 25 | +```python |
| 26 | +tools.append({ |
| 27 | + "name": name, |
| 28 | + "description": (func.__doc__ or "").strip() or f"Tool: {name}", |
| 29 | + "inputSchema": { |
| 30 | + "type": "object", |
| 31 | + "properties": {}, # Empty properties! |
| 32 | + "additionalProperties": True |
| 33 | + } |
| 34 | +}) |
| 35 | +``` |
| 36 | + |
| 37 | +**Issue:** Empty property schemas prevent Claude.ai from understanding how to call the tools. |
| 38 | + |
| 39 | +### 3. Missing Proper SSE Message Flow |
| 40 | + |
| 41 | +The current implementation doesn't properly handle the SSE initialization flow that Claude.ai expects: |
| 42 | +- POST to /sse with initialization request |
| 43 | +- Proper JSON-RPC message formatting |
| 44 | +- Correct event types and data structure |
| 45 | + |
| 46 | +## Solution |
| 47 | + |
| 48 | +### 1. Proper Tool Definition |
| 49 | + |
| 50 | +Tools must be properly defined with complete schemas: |
| 51 | + |
| 52 | +```python |
| 53 | +{ |
| 54 | + "name": "knowledge_search", |
| 55 | + "description": "Search through Dr. Strunz's knowledge base", |
| 56 | + "inputSchema": { |
| 57 | + "type": "object", |
| 58 | + "properties": { |
| 59 | + "query": { |
| 60 | + "type": "string", |
| 61 | + "description": "Search query" |
| 62 | + }, |
| 63 | + "limit": { |
| 64 | + "type": "integer", |
| 65 | + "description": "Number of results", |
| 66 | + "default": 10 |
| 67 | + } |
| 68 | + }, |
| 69 | + "required": ["query"] |
| 70 | + } |
| 71 | +} |
| 72 | +``` |
| 73 | + |
| 74 | +### 2. Correct SSE Implementation |
| 75 | + |
| 76 | +```python |
| 77 | +@app.post("/sse") |
| 78 | +async def sse_endpoint(request: Request): |
| 79 | + # Handle POST initialization |
| 80 | + init_request = await request.json() |
| 81 | + |
| 82 | + async def event_generator(): |
| 83 | + if init_request.get("method") == "initialize": |
| 84 | + # Send proper initialization response |
| 85 | + yield { |
| 86 | + "event": "message", |
| 87 | + "data": json.dumps({ |
| 88 | + "jsonrpc": "2.0", |
| 89 | + "id": init_request.get("id"), |
| 90 | + "result": { |
| 91 | + "protocolVersion": "2025-03-26", |
| 92 | + "capabilities": { |
| 93 | + "tools": {"listChanged": False} |
| 94 | + }, |
| 95 | + "serverInfo": { |
| 96 | + "name": "Server Name", |
| 97 | + "version": "1.0.0" |
| 98 | + } |
| 99 | + } |
| 100 | + }) |
| 101 | + } |
| 102 | +``` |
| 103 | + |
| 104 | +### 3. Proper Tool Extraction from MCP SDK |
| 105 | + |
| 106 | +Instead of trying to extract handler methods, we need to: |
| 107 | + |
| 108 | +1. **Call the SDK's list_tools handler directly** |
| 109 | +2. **Convert the SDK's tool format to Claude.ai's expected format** |
| 110 | +3. **Ensure all tool schemas are complete** |
| 111 | + |
| 112 | +```python |
| 113 | +# Get tools from MCP SDK server |
| 114 | +async def get_sdk_tools(): |
| 115 | + """Extract tools from the MCP SDK server""" |
| 116 | + if hasattr(server_instance.server, 'list_tools'): |
| 117 | + # Call the list_tools handler |
| 118 | + tools_handler = server_instance.server._tool_list_handler |
| 119 | + if tools_handler: |
| 120 | + sdk_tools = await tools_handler() |
| 121 | + # Convert to Claude.ai format |
| 122 | + return [convert_tool_format(tool) for tool in sdk_tools] |
| 123 | + return [] |
| 124 | +``` |
| 125 | + |
| 126 | +## Testing Steps |
| 127 | + |
| 128 | +### 1. Local Testing with MCP Inspector |
| 129 | + |
| 130 | +```bash |
| 131 | +# Run the test server |
| 132 | +python src/mcp/test_sse_server.py |
| 133 | + |
| 134 | +# In another terminal, run the test script |
| 135 | +python src/scripts/test_mcp_inspector.py |
| 136 | +``` |
| 137 | + |
| 138 | +Then: |
| 139 | +1. Open https://inspector.mcp.run/ |
| 140 | +2. Select "SSE" transport |
| 141 | +3. Enter URL: http://localhost:8000/sse |
| 142 | +4. Click "Connect" |
| 143 | +5. Verify tools appear |
| 144 | + |
| 145 | +### 2. Claude.ai Testing |
| 146 | + |
| 147 | +1. Deploy the fixed server to Railway |
| 148 | +2. Add to Claude.ai with the public URL |
| 149 | +3. Tools should now appear properly |
| 150 | + |
| 151 | +## Key Differences from Working Servers |
| 152 | + |
| 153 | +Working MCP servers (like bloodtest-mcp-server) follow these patterns: |
| 154 | + |
| 155 | +1. **Complete tool schemas** with all properties defined |
| 156 | +2. **Proper SSE message flow** handling both GET and POST |
| 157 | +3. **Correct JSON-RPC formatting** throughout |
| 158 | +4. **Tool execution returns proper content structure** |
| 159 | + |
| 160 | +## Implementation Checklist |
| 161 | + |
| 162 | +- [ ] Fix tool extraction from MCP SDK |
| 163 | +- [ ] Implement proper SSE message handling |
| 164 | +- [ ] Add complete input schemas for all tools |
| 165 | +- [ ] Test with MCP Inspector |
| 166 | +- [ ] Deploy and test with Claude.ai |
| 167 | +- [ ] Verify all 20 tools appear and work |
| 168 | + |
| 169 | +## References |
| 170 | + |
| 171 | +- [MCP Python SDK SSE Transport](https://github.com/modelcontextprotocol/python-sdk/blob/main/src/mcp/server/sse.py) |
| 172 | +- [MCP Protocol Specification](https://modelcontextprotocol.io/docs/concepts/transports) |
| 173 | +- [Working MCP Server Examples](https://github.com/modelcontextprotocol/servers) |
0 commit comments