codeant-ai-for-open-source[bot] commented on code in PR #40469:
URL: https://github.com/apache/superset/pull/40469#discussion_r3311458075


##########
superset/mcp_service/jwt_verifier.py:
##########
@@ -61,21 +63,227 @@
     "_jwt_failure_reason", default=None
 )
 
+_HTML_STYLES = """
+    *, *::before, *::after { box-sizing: border-box; }
+    body {
+      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 
sans-serif;
+      background: #f5f5f5;
+      color: #1a1a1a;
+      margin: 0;
+      padding: 40px 16px;
+      line-height: 1.6;
+    }
+    .card {
+      max-width: 640px;
+      margin: 0 auto;
+      background: #ffffff;
+      border-radius: 8px;
+      box-shadow: 0 1px 4px rgba(0,0,0,.12);
+      padding: 40px 40px 32px;
+    }
+    h1 { font-size: 1.4rem; margin: 0 0 8px; }
+    .badge {
+      display: inline-block;
+      background: #e8f4fd;
+      color: #0070c0;
+      font-size: .75rem;
+      font-weight: 600;
+      padding: 2px 8px;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      letter-spacing: .04em;
+      text-transform: uppercase;
+    }
+    p { margin: 0 0 20px; color: #444; }
+    h2 { font-size: 1rem; margin: 24px 0 8px; color: #1a1a1a; }
+    pre {
+      background: #f0f0f0;
+      border-radius: 6px;
+      padding: 16px;
+      font-size: .85rem;
+      overflow-x: auto;
+      margin: 0 0 24px;
+    }
+    code {
+      font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, 
monospace;
+    }
+    .note {
+      font-size: .85rem;
+      color: #666;
+      border-left: 3px solid #ddd;
+      padding-left: 12px;
+      margin-top: 24px;
+    }"""
+
+_DEFAULT_CLIENTS = [
+    "Claude Desktop",
+    "Claude Code (CLI)",
+    "Cursor",
+]
+
+_DEFAULT_HELLO_PAGE_CONFIG: dict[str, Any] = {
+    # Page heading and browser tab title
+    "title": "Superset MCP Server",
+    # Key name used in the mcpServers config snippet (e.g. "superset", 
"my-company")
+    "server_key": "superset",
+    # Include "transport": "streamable-http" in the config snippet.
+    # Recommended: Claude Desktop defaults to SSE so the transport must be 
explicit.
+    "show_transport": True,
+    # Supported MCP clients listed on the page
+    "clients": _DEFAULT_CLIENTS,
+}
+
+
+def _build_config_snippet(
+    auth_enabled: bool, server_key: str, show_transport: bool
+) -> str:
+    inner_parts = ['      "url": "<this-url>"']
+    if show_transport:
+        inner_parts.append('      "transport": "streamable-http"')
+    if auth_enabled:
+        inner_parts.append(
+            '      "headers": {\n'
+            '        "Authorization": "Bearer <your-api-key>"\n'
+            "      }"
+        )
+    inner = ",\n".join(inner_parts)
+    return f'{{\n  "mcpServers": {{\n    "{server_key}": {{\n{inner}\n    }}\n 
 }}\n}}'

Review Comment:
   **Suggestion:** The generated JSON config snippet inserts `server_key` 
directly into a JSON string literal; if the configured key contains quotes or 
backslashes, the snippet becomes invalid JSON and setup instructions will fail 
for users. Serialize or escape `server_key` as a JSON string before 
interpolation. [logic error]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ⚠️ Generated MCP client snippet may be invalid JSON.
   - ⚠️ Users copying config see confusing parse-time failures.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure the MCP hello page via Flask config so that
   `flask_app.config["MCP_HELLO_PAGE"]` contains a `server_key` value with 
characters that
   must be escaped in JSON, for example: `MCP_HELLO_PAGE = {"server_key": 
"my\"superset"}`;
   this config is later read by `_build_starlette_middleware()` at
   `superset/mcp_service/server.py:79`.
   
   2. Start the MCP HTTP server via `run_server()` in
   `superset/mcp_service/server.py:90-151`, which invokes
   `_build_starlette_middleware(flask_app)` at `server.py:167-169`; that 
constructs
   `BrowserHelloMiddleware` whose `__init__()` (`jwt_verifier.py:251-260`) calls
   `_build_browser_hello_html(auth_enabled, page_config)` 
(`jwt_verifier.py:153-215`).
   
   3. `_build_browser_hello_html()` calls `_build_config_snippet(auth_enabled, 
server_key,
   show_transport)` at `jwt_verifier.py:163`, passing the configured 
`server_key` string
   containing an embedded quote.
   
   4. `_build_config_snippet()` builds the JSON snippet string using `return 
f'{{\n
   "mcpServers": {{\n "{server_key}": {{\n{inner}\n }}\n }}\n}}'` at 
`jwt_verifier.py:150`
   without escaping `server_key`; when the browser loads the hello page and the 
operator
   copies the `<code>` block into an MCP client config, the resulting JSON 
contains a key
   like `"my"superset": { ... }`, which is syntactically invalid and will cause 
JSON parsing
   failures in the client.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=52a14186df96452792c8f38f9d7f5230&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=52a14186df96452792c8f38f9d7f5230&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/jwt_verifier.py
   **Line:** 150:150
   **Comment:**
        *Logic Error: The generated JSON config snippet inserts `server_key` 
directly into a JSON string literal; if the configured key contains quotes or 
backslashes, the snippet becomes invalid JSON and setup instructions will fail 
for users. Serialize or escape `server_key` as a JSON string before 
interpolation.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=820b5b880dc735e53012efcf3ee2b72f85c6e10e4e4275b21ea30566a61e95ac&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=820b5b880dc735e53012efcf3ee2b72f85c6e10e4e4275b21ea30566a61e95ac&reaction=dislike'>👎</a>



##########
superset/mcp_service/jwt_verifier.py:
##########
@@ -61,21 +63,227 @@
     "_jwt_failure_reason", default=None
 )
 
+_HTML_STYLES = """
+    *, *::before, *::after { box-sizing: border-box; }
+    body {
+      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 
sans-serif;
+      background: #f5f5f5;
+      color: #1a1a1a;
+      margin: 0;
+      padding: 40px 16px;
+      line-height: 1.6;
+    }
+    .card {
+      max-width: 640px;
+      margin: 0 auto;
+      background: #ffffff;
+      border-radius: 8px;
+      box-shadow: 0 1px 4px rgba(0,0,0,.12);
+      padding: 40px 40px 32px;
+    }
+    h1 { font-size: 1.4rem; margin: 0 0 8px; }
+    .badge {
+      display: inline-block;
+      background: #e8f4fd;
+      color: #0070c0;
+      font-size: .75rem;
+      font-weight: 600;
+      padding: 2px 8px;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      letter-spacing: .04em;
+      text-transform: uppercase;
+    }
+    p { margin: 0 0 20px; color: #444; }
+    h2 { font-size: 1rem; margin: 24px 0 8px; color: #1a1a1a; }
+    pre {
+      background: #f0f0f0;
+      border-radius: 6px;
+      padding: 16px;
+      font-size: .85rem;
+      overflow-x: auto;
+      margin: 0 0 24px;
+    }
+    code {
+      font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, 
monospace;
+    }
+    .note {
+      font-size: .85rem;
+      color: #666;
+      border-left: 3px solid #ddd;
+      padding-left: 12px;
+      margin-top: 24px;
+    }"""
+
+_DEFAULT_CLIENTS = [
+    "Claude Desktop",
+    "Claude Code (CLI)",
+    "Cursor",
+]
+
+_DEFAULT_HELLO_PAGE_CONFIG: dict[str, Any] = {
+    # Page heading and browser tab title
+    "title": "Superset MCP Server",
+    # Key name used in the mcpServers config snippet (e.g. "superset", 
"my-company")
+    "server_key": "superset",
+    # Include "transport": "streamable-http" in the config snippet.
+    # Recommended: Claude Desktop defaults to SSE so the transport must be 
explicit.
+    "show_transport": True,
+    # Supported MCP clients listed on the page
+    "clients": _DEFAULT_CLIENTS,
+}
+
+
+def _build_config_snippet(
+    auth_enabled: bool, server_key: str, show_transport: bool
+) -> str:
+    inner_parts = ['      "url": "&lt;this-url&gt;"']
+    if show_transport:
+        inner_parts.append('      "transport": "streamable-http"')
+    if auth_enabled:
+        inner_parts.append(
+            '      "headers": {\n'
+            '        "Authorization": "Bearer &lt;your-api-key&gt;"\n'
+            "      }"
+        )
+    inner = ",\n".join(inner_parts)
+    return f'{{\n  "mcpServers": {{\n    "{server_key}": {{\n{inner}\n    }}\n 
 }}\n}}'
+
+
+def _build_browser_hello_html(
+    auth_enabled: bool,
+    page_config: dict[str, Any] | None = None,
+) -> str:
+    cfg = {**_DEFAULT_HELLO_PAGE_CONFIG, **(page_config or {})}
+    title: str = cfg["title"]
+    server_key: str = cfg["server_key"]
+    show_transport: bool = cfg["show_transport"]
+    clients: list[str] = cfg["clients"]
+
+    config_block = _build_config_snippet(auth_enabled, server_key, 
show_transport)
+
+    if auth_enabled:
+        connect_desc = (
+            "Add the following to your MCP client configuration, "
+            "replacing the URL and API key with your actual values:"
+        )
+        note = (
+            "Replace <code>&lt;this-url&gt;</code> with the full URL of this 
page and "
+            "<code>&lt;your-api-key&gt;</code> with a valid API key or JWT 
token."
+        )
+    else:
+        connect_desc = (
+            "Add the following to your MCP client configuration, "
+            "replacing the URL with your actual server URL:"
+        )
+        note = "Replace <code>&lt;this-url&gt;</code> with the full URL of 
this page."
+
+    client_items = "\n".join(f"      <li>{c}</li>" for c in clients)
+
+    return f"""<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>{title}</title>
+  <style>{_HTML_STYLES}
+  </style>
+</head>
+<body>
+  <div class="card">
+    <div class="badge">MCP API Endpoint</div>
+    <h1>{title}</h1>
+    <p>

Review Comment:
   **Suggestion:** Config-driven page values are interpolated directly into 
HTML without escaping, so a crafted `MCP_HELLO_PAGE["title"]` value can inject 
markup/script into the response. Escape dynamic HTML content before rendering 
to prevent XSS and broken markup. [security]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Admin-defined hello page config can inject arbitrary HTML.
   - ⚠️ XSS possible if config built from untrusted inputs.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Configure the Flask app used by the MCP service so that
   `flask_app.config["MCP_HELLO_PAGE"]` includes an untrusted HTML string for 
`title`, for
   example in deployment config: `MCP_HELLO_PAGE = {"title": "<img src=x 
onerror=alert(1)>",
   "server_key": "superset"}`; this config is later read in 
`_build_starlette_middleware()`
   at `superset/mcp_service/server.py:79`.
   
   2. Start the MCP HTTP server via `run_server()` in 
`superset/mcp_service/server.py:90-151`
   (e.g. `superset mcp run --port 5008`), which obtains a Flask app from 
`get_flask_app()`
   (`superset/mcp_service/flask_singleton.py:99-106`) and then calls
   `_build_starlette_middleware(flask_app)` at `server.py:167-169`.
   
   3. `_build_starlette_middleware()` reads `page_config =
   flask_app.config.get("MCP_HELLO_PAGE", None)` at `server.py:79` and 
constructs
   `BrowserHelloMiddleware` with this `page_config`; 
`BrowserHelloMiddleware.__init__()`
   (`jwt_verifier.py:251-260`) calls `_build_browser_hello_html(auth_enabled, 
page_config)`
   at `jwt_verifier.py:153-215`.
   
   4. `_build_browser_hello_html()` merges defaults and config into `cfg` and 
interpolates
   `cfg["title"]` directly into the HTML template at `jwt_verifier.py:188-196` 
— specifically
   `<title>{title}</title>` and `<h1>{title}</h1>` — without escaping; when a 
browser
   requests `GET /mcp` with a browser-style `Accept: text/html` header 
(triggering
   `BrowserHelloMiddleware.dispatch()` at `jwt_verifier.py:262-267`), the 
response contains
   `<img src=x onerror=alert(1)>` in the title and heading, and the `onerror` 
JavaScript
   executes in the MCP server's origin context.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=ee4aa5f1b432408d954357875a0047aa&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=ee4aa5f1b432408d954357875a0047aa&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/jwt_verifier.py
   **Line:** 189:196
   **Comment:**
        *Security: Config-driven page values are interpolated directly into 
HTML without escaping, so a crafted `MCP_HELLO_PAGE["title"]` value can inject 
markup/script into the response. Escape dynamic HTML content before rendering 
to prevent XSS and broken markup.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=3d6bd2405ffe33fa2273f662c3dfdb75480d63d5e121f9fc04af63895716be7f&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=3d6bd2405ffe33fa2273f662c3dfdb75480d63d5e121f9fc04af63895716be7f&reaction=dislike'>👎</a>



##########
superset/mcp_service/jwt_verifier.py:
##########
@@ -61,21 +63,227 @@
     "_jwt_failure_reason", default=None
 )
 
+_HTML_STYLES = """
+    *, *::before, *::after { box-sizing: border-box; }
+    body {
+      font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, 
sans-serif;
+      background: #f5f5f5;
+      color: #1a1a1a;
+      margin: 0;
+      padding: 40px 16px;
+      line-height: 1.6;
+    }
+    .card {
+      max-width: 640px;
+      margin: 0 auto;
+      background: #ffffff;
+      border-radius: 8px;
+      box-shadow: 0 1px 4px rgba(0,0,0,.12);
+      padding: 40px 40px 32px;
+    }
+    h1 { font-size: 1.4rem; margin: 0 0 8px; }
+    .badge {
+      display: inline-block;
+      background: #e8f4fd;
+      color: #0070c0;
+      font-size: .75rem;
+      font-weight: 600;
+      padding: 2px 8px;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      letter-spacing: .04em;
+      text-transform: uppercase;
+    }
+    p { margin: 0 0 20px; color: #444; }
+    h2 { font-size: 1rem; margin: 24px 0 8px; color: #1a1a1a; }
+    pre {
+      background: #f0f0f0;
+      border-radius: 6px;
+      padding: 16px;
+      font-size: .85rem;
+      overflow-x: auto;
+      margin: 0 0 24px;
+    }
+    code {
+      font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, 
monospace;
+    }
+    .note {
+      font-size: .85rem;
+      color: #666;
+      border-left: 3px solid #ddd;
+      padding-left: 12px;
+      margin-top: 24px;
+    }"""
+
+_DEFAULT_CLIENTS = [
+    "Claude Desktop",
+    "Claude Code (CLI)",
+    "Cursor",
+]
+
+_DEFAULT_HELLO_PAGE_CONFIG: dict[str, Any] = {
+    # Page heading and browser tab title
+    "title": "Superset MCP Server",
+    # Key name used in the mcpServers config snippet (e.g. "superset", 
"my-company")
+    "server_key": "superset",
+    # Include "transport": "streamable-http" in the config snippet.
+    # Recommended: Claude Desktop defaults to SSE so the transport must be 
explicit.
+    "show_transport": True,
+    # Supported MCP clients listed on the page
+    "clients": _DEFAULT_CLIENTS,
+}
+
+
+def _build_config_snippet(
+    auth_enabled: bool, server_key: str, show_transport: bool
+) -> str:
+    inner_parts = ['      "url": "&lt;this-url&gt;"']
+    if show_transport:
+        inner_parts.append('      "transport": "streamable-http"')
+    if auth_enabled:
+        inner_parts.append(
+            '      "headers": {\n'
+            '        "Authorization": "Bearer &lt;your-api-key&gt;"\n'
+            "      }"
+        )
+    inner = ",\n".join(inner_parts)
+    return f'{{\n  "mcpServers": {{\n    "{server_key}": {{\n{inner}\n    }}\n 
 }}\n}}'
+
+
+def _build_browser_hello_html(
+    auth_enabled: bool,
+    page_config: dict[str, Any] | None = None,
+) -> str:
+    cfg = {**_DEFAULT_HELLO_PAGE_CONFIG, **(page_config or {})}
+    title: str = cfg["title"]
+    server_key: str = cfg["server_key"]
+    show_transport: bool = cfg["show_transport"]
+    clients: list[str] = cfg["clients"]
+
+    config_block = _build_config_snippet(auth_enabled, server_key, 
show_transport)
+
+    if auth_enabled:
+        connect_desc = (
+            "Add the following to your MCP client configuration, "
+            "replacing the URL and API key with your actual values:"
+        )
+        note = (
+            "Replace <code>&lt;this-url&gt;</code> with the full URL of this 
page and "
+            "<code>&lt;your-api-key&gt;</code> with a valid API key or JWT 
token."
+        )
+    else:
+        connect_desc = (
+            "Add the following to your MCP client configuration, "
+            "replacing the URL with your actual server URL:"
+        )
+        note = "Replace <code>&lt;this-url&gt;</code> with the full URL of 
this page."
+
+    client_items = "\n".join(f"      <li>{c}</li>" for c in clients)
+
+    return f"""<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=device-width, initial-scale=1.0">
+  <title>{title}</title>
+  <style>{_HTML_STYLES}
+  </style>
+</head>
+<body>
+  <div class="card">
+    <div class="badge">MCP API Endpoint</div>
+    <h1>{title}</h1>
+    <p>
+      This is the <strong>Model Context Protocol (MCP)</strong> endpoint for
+      Apache Superset. It is an API designed for AI coding assistants —
+      not a web page to browse directly.
+    </p>
+    <h2>How to connect</h2>
+    <p>{connect_desc}</p>
+    <pre><code>{config_block}</code></pre>
+    <h2>Supported clients</h2>
+    <p>This endpoint works with any MCP-compatible client, including:</p>
+    <ul style="color:#444;margin:0 0 20px;padding-left:20px;">
+{client_items}
+      <li>Any client that supports the <code>streamable-http</code> 
transport</li>
+    </ul>
+    <div class="note">
+      {note}
+    </div>
+  </div>
+</body>
+</html>"""
+
+
+# Pre-built for _auth_error_handler (auth-required context, default config)
+_MCP_BROWSER_HELLO_HTML = _build_browser_hello_html(auth_enabled=True)
+
+
+def _prefers_browser_html(conn: HTTPConnection) -> bool:
+    """Return True when the request looks like a browser navigation.
+
+    Checks both the HTTP method (GET/HEAD only) and the Accept header
+    (text/html present, application/json and text/event-stream absent).
+    Case-insensitive to handle unusual but valid header values.
+    """
+    if conn.scope.get("method") not in ("GET", "HEAD"):
+        return False
+    accept = conn.headers.get("accept", "").lower()
+    return (
+        "text/html" in accept
+        and "application/json" not in accept
+        and "text/event-stream" not in accept
+    )
+
+
+class BrowserHelloMiddleware(BaseHTTPMiddleware):
+    """Starlette middleware that returns a browser-friendly hello page.
+
+    Intercepts GET/HEAD requests with a browser Accept header before they
+    reach FastMCP's router (which returns 405 for GET). Works regardless
+    of whether MCP_AUTH_ENABLED is True or False.
+
+    When auth_enabled=True the page includes Bearer token setup instructions.
+    When auth_enabled=False the page omits the Authorization header from the
+    config snippet since no credentials are required.
+    """
+
+    def __init__(
+        self,
+        app: Any,
+        auth_enabled: bool = False,
+        page_config: dict[str, Any] | None = None,
+    ) -> None:
+        super().__init__(app)
+        self._html = _build_browser_hello_html(
+            auth_enabled=auth_enabled, page_config=page_config
+        )
+
+    async def dispatch(
+        self, request: Request, call_next: Callable[..., Any]
+    ) -> Response:
+        if request.method in ("GET", "HEAD") and 
_prefers_browser_html(request):
+            return HTMLResponse(content=self._html, status_code=200)

Review Comment:
   **Suggestion:** The hello middleware currently returns the HTML page for any 
`GET`/`HEAD` request that advertises `text/html`, without checking the request 
path. That makes unrelated or unknown routes return `200` with the MCP page 
instead of their real response (for example, expected `404`/`405`), which can 
mask routing errors and break endpoint behavior. Restrict this branch to the 
MCP endpoint path only. [incorrect condition logic]
   
   <details>
   <summary><b>Severity Level:</b> Major ⚠️</summary>
   
   ```mdx
   - ❌ Unknown MCP HTTP paths return 200 hello instead 404.
   - ⚠️ Masks routing errors when debugging MCP reverse proxies.
   ```
   </details>
   <details>
   <summary><b>Steps of Reproduction ✅ </b></summary>
   
   ```mdx
   1. Start the MCP HTTP server via `run_server()` in
   `superset/mcp_service/server.py:90-151`, e.g. using the documented CLI 
`superset mcp run
   --port 5008`, which constructs an HTTP app and passes 
`middleware=starlette_middleware` at
   `server.py:179-185`.
   
   2. `_build_starlette_middleware()` in `superset/mcp_service/server.py:72-87` 
wraps the
   FastMCP ASGI app with `BrowserHelloMiddleware` (from
   `superset/mcp_service/jwt_verifier.py:239-267`) as Starlette middleware, so 
it sees all
   incoming HTTP requests regardless of path.
   
   3. From a browser (or with curl mimicking a browser header), send a GET 
request to an
   undefined path on the MCP server, for example: `GET /nonexistent HTTP/1.1` 
with header
   `Accept: text/html,*/*` against `http://localhost:5008` (the host/port used 
in
   `run_server()`).
   
   4. `BrowserHelloMiddleware.dispatch()` at `jwt_verifier.py:262-267` evaluates
   `request.method in ("GET", "HEAD")` and calls 
`_prefers_browser_html(request)` at
   `jwt_verifier.py:222-236`, which returns True because `Accept` contains 
`text/html` and
   not `application/json`/`text/event-stream`; it then immediately returns
   `HTMLResponse(content=self._html, status_code=200)` for `/nonexistent`, so 
the underlying
   FastMCP router never runs and the client sees a 200 MCP hello page instead 
of the expected
   404/405 for an unknown route.
   ```
   </details>
   
   [Fix in 
Cursor](https://app.codeant.ai/fix-in-ide?tool=cursor&prompt_id=3e7b9d1633904e3bbc8385f5548a70f7&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
 | [Fix in VSCode 
Claude](https://app.codeant.ai/fix-in-ide?tool=vscode-claude&prompt_id=3e7b9d1633904e3bbc8385f5548a70f7&service=github&base_url=https%3A%2F%2Fgithub.com&org=apache&repo=apache%2Fsuperset)
   
   *(Use Cmd/Ctrl + Click for best experience)*
   <details>
   <summary><b>Prompt for AI Agent 🤖 </b></summary>
   
   ```mdx
   This is a comment left during a code review.
   
   **Path:** superset/mcp_service/jwt_verifier.py
   **Line:** 265:266
   **Comment:**
        *Incorrect Condition Logic: The hello middleware currently returns the 
HTML page for any `GET`/`HEAD` request that advertises `text/html`, without 
checking the request path. That makes unrelated or unknown routes return `200` 
with the MCP page instead of their real response (for example, expected 
`404`/`405`), which can mask routing errors and break endpoint behavior. 
Restrict this branch to the MCP endpoint path only.
   
   Validate the correctness of the flagged issue. If correct, How can I resolve 
this? If you propose a fix, implement it and please make it concise.
   Once fix is implemented, also check other comments on the same PR, and ask 
user if the user wants to fix the rest of the comments as well. if said yes, 
then fetch all the comments validate the correctness and implement a minimal fix
   ```
   </details>
   <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=bc86581180a79fb66ae16ad83f19a3245d92776e8e680f819645352787053e59&reaction=like'>👍</a>
 | <a 
href='https://app.codeant.ai/feedback?pr_url=https%3A%2F%2Fgithub.com%2Fapache%2Fsuperset%2Fpull%2F40469&comment_hash=bc86581180a79fb66ae16ad83f19a3245d92776e8e680f819645352787053e59&reaction=dislike'>👎</a>



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to