|
23 | 23 | from http.server import HTTPServer, BaseHTTPRequestHandler |
24 | 24 | from datetime import datetime |
25 | 25 | from pathlib import Path |
26 | | -from typing import Dict |
27 | 26 |
|
28 | 27 |
|
29 | 28 | # Global storage for captured headers (last request) |
30 | | -last_headers: Dict[str, str] = {} |
| 29 | +last_headers: dict[str, str] = {} |
31 | 30 | request_log: list = [] |
32 | 31 |
|
33 | 32 |
|
@@ -79,19 +78,22 @@ def do_POST(self) -> None: # pylint: disable=invalid-name |
79 | 78 |
|
80 | 79 | # Determine tool name based on authorization header to avoid collisions |
81 | 80 | auth_header = self.headers.get("Authorization", "") |
82 | | - if "test-secret-token" in auth_header: |
83 | | - tool_name = "mock_tool_file" |
84 | | - tool_desc = "Mock tool with file-based auth" |
85 | | - elif "my-k8s-token" in auth_header: |
86 | | - tool_name = "mock_tool_k8s" |
87 | | - tool_desc = "Mock tool with Kubernetes token" |
88 | | - elif "my-client-token" in auth_header: |
89 | | - tool_name = "mock_tool_client" |
90 | | - tool_desc = "Mock tool with client-provided token" |
91 | | - else: |
92 | | - # No auth header or unrecognized token |
93 | | - tool_name = "mock_tool_no_auth" |
94 | | - tool_desc = "Mock tool with no authorization" |
| 81 | + |
| 82 | + # Match based on token content |
| 83 | + match auth_header: |
| 84 | + case _ if "test-secret-token" in auth_header: |
| 85 | + tool_name = "mock_tool_file" |
| 86 | + tool_desc = "Mock tool with file-based auth" |
| 87 | + case _ if "my-k8s-token" in auth_header: |
| 88 | + tool_name = "mock_tool_k8s" |
| 89 | + tool_desc = "Mock tool with Kubernetes token" |
| 90 | + case _ if "my-client-token" in auth_header: |
| 91 | + tool_name = "mock_tool_client" |
| 92 | + tool_desc = "Mock tool with client-provided token" |
| 93 | + case _: |
| 94 | + # No auth header or unrecognized token |
| 95 | + tool_name = "mock_tool_no_auth" |
| 96 | + tool_desc = "Mock tool with no authorization" |
95 | 97 |
|
96 | 98 | # Handle MCP protocol methods |
97 | 99 | if method == "initialize": |
@@ -150,51 +152,53 @@ def do_POST(self) -> None: # pylint: disable=invalid-name |
150 | 152 |
|
151 | 153 | def do_GET(self) -> None: # pylint: disable=invalid-name |
152 | 154 | """Handle GET requests (debug endpoints).""" |
153 | | - # Debug endpoint to view captured headers |
154 | | - if self.path == "/debug/headers": |
155 | | - self.send_response(200) |
156 | | - self.send_header("Content-Type", "application/json") |
157 | | - self.end_headers() |
158 | | - response = { |
159 | | - "last_headers": last_headers, |
160 | | - "request_count": len(request_log), |
161 | | - } |
162 | | - self.wfile.write(json.dumps(response, indent=2).encode()) |
163 | | - |
164 | | - # Debug endpoint to view request log |
165 | | - elif self.path == "/debug/requests": |
166 | | - self.send_response(200) |
167 | | - self.send_header("Content-Type", "application/json") |
168 | | - self.end_headers() |
169 | | - self.wfile.write(json.dumps(request_log, indent=2).encode()) |
170 | | - |
171 | | - # Root endpoint - show help |
172 | | - elif self.path == "/": |
173 | | - self.send_response(200) |
174 | | - self.send_header("Content-Type", "text/html") |
175 | | - self.end_headers() |
176 | | - help_html = """ |
177 | | - <html> |
178 | | - <head><title>MCP Mock Server</title></head> |
179 | | - <body> |
180 | | - <h1>MCP Mock Server</h1> |
181 | | - <p>This is a development mock server for testing MCP integrations.</p> |
182 | | - <h2>Debug Endpoints:</h2> |
183 | | - <ul> |
184 | | - <li><a href="/debug/headers">/debug/headers</a> - View last captured headers</li> |
185 | | - <li><a href="/debug/requests">/debug/requests</a> - View recent request log</li> |
186 | | - </ul> |
187 | | - <h2>MCP Endpoints:</h2> |
188 | | - <ul> |
189 | | - <li>POST /mcp/v1/list_tools - Mock MCP tools endpoint</li> |
190 | | - </ul> |
191 | | - </body> |
192 | | - </html> |
193 | | - """ |
194 | | - self.wfile.write(help_html.encode()) |
195 | | - else: |
196 | | - self.send_response(404) |
197 | | - self.end_headers() |
| 155 | + # Handle different GET endpoints |
| 156 | + match self.path: |
| 157 | + case "/debug/headers": |
| 158 | + self._send_json_response( |
| 159 | + {"last_headers": last_headers, "request_count": len(request_log)} |
| 160 | + ) |
| 161 | + case "/debug/requests": |
| 162 | + self._send_json_response(request_log) |
| 163 | + case "/": |
| 164 | + self._send_help_page() |
| 165 | + case _: |
| 166 | + self.send_response(404) |
| 167 | + self.end_headers() |
| 168 | + |
| 169 | + def _send_json_response(self, data: dict | list) -> None: |
| 170 | + """Send a JSON response.""" |
| 171 | + self.send_response(200) |
| 172 | + self.send_header("Content-Type", "application/json") |
| 173 | + self.end_headers() |
| 174 | + self.wfile.write(json.dumps(data, indent=2).encode()) |
| 175 | + |
| 176 | + def _send_help_page(self) -> None: |
| 177 | + """Send HTML help page for root endpoint.""" |
| 178 | + self.send_response(200) |
| 179 | + self.send_header("Content-Type", "text/html") |
| 180 | + self.end_headers() |
| 181 | + help_html = """<!DOCTYPE html> |
| 182 | + <html> |
| 183 | + <head><title>MCP Mock Server</title></head> |
| 184 | + <body> |
| 185 | + <h1>MCP Mock Server</h1> |
| 186 | + <p>Development mock server for testing MCP integrations.</p> |
| 187 | + <h2>Debug Endpoints:</h2> |
| 188 | + <ul> |
| 189 | + <li><a href="/debug/headers">/debug/headers</a> - View captured headers</li> |
| 190 | + <li><a href="/debug/requests">/debug/requests</a> - View request log</li> |
| 191 | + </ul> |
| 192 | + <h2>MCP Protocol:</h2> |
| 193 | + <p>POST requests to <code>/</code> with JSON-RPC format:</p> |
| 194 | + <ul> |
| 195 | + <li><code>{"jsonrpc": "2.0", "id": 1, "method": "initialize"}</code></li> |
| 196 | + <li><code>{"jsonrpc": "2.0", "id": 1, "method": "tools/list"}</code></li> |
| 197 | + </ul> |
| 198 | + </body> |
| 199 | + </html> |
| 200 | + """ |
| 201 | + self.wfile.write(help_html.encode()) |
198 | 202 |
|
199 | 203 |
|
200 | 204 | def generate_self_signed_cert(cert_dir: Path) -> tuple[Path, Path]: |
|
0 commit comments