Skip to content

[Bug] MCP SSE endpoint event omits the /server prefix, so clients behind the built-in nginx proxy get a 404 on /mcp/messages #1854

Closed

Description

@frdmn

What installation are you running?

Production (netalertx) 📦

Is there an existing issue for this?

The issue occurs in the following browsers. Select at least 2.

  • N/A - This is an issue with the backend

Current Behavior

When you connect to the MCP server through the built-in nginx proxy (http://<host>:20211/server/mcp/sse), the SSE endpoint event sends back an absolute path that has no /server prefix:

event: endpoint
data: /mcp/messages?session_id=0b6b10b07cd94f9989df9c38be26ed77

MCP clients resolve this against the origin and send their requests to http://<host>:20211/mcp/messages?.... nginx has no route for that path and tries to serve it as a static file from /app/front, which returns a 404. The client never finishes connecting. Claude Code shows Error POSTing to endpoint (HTTP 404): ... nginx.

The same request with the /server prefix works (202). Only the advertised URL is wrong. The cause is in server/api_server/mcp_endpoint.py:1061:

yield f"event: endpoint\ndata: /mcp/messages?session_id={session_id}\n\n"

Related but different: #1275 (MCP server), #1440 (backend and reverse proxy setup).

Expected Behavior

The advertised endpoint should resolve to a working URL behind the bundled proxy. Two possible fixes:

  • Send a relative path (messages?session_id=...). It resolves against .../mcp/sse, so it works both directly and behind any prefix.
  • Prepend the prefix from X-Forwarded-Prefix or request.script_root, and have the bundled nginx set that header for /server.

Workaround: connect straight to http://<host>:<GRAPHQL_PORT>/mcp/sse. This bypasses the reverse proxy and any auth middleware in front of it.

Steps To Reproduce

H='Authorization: Bearer <API_TOKEN>'; S='Sec-Fetch-Site: same-origin'
curl -sN -H "$H" -H "$S" http://<host>:20211/server/mcp/sse   # -> data: /mcp/messages?session_id=XYZ

curl -X POST -H "$H" -H "$S" -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}' \
  "http://<host>:20211/mcp/messages?session_id=XYZ"           # -> 404 (nginx)

curl -X POST -H "$H" -H "$S" -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"ping"}' \
  "http://<host>:20211/server/mcp/messages?session_id=XYZ"    # -> 202 accepted

Relevant app.conf settings

LOG_LEVEL='trace'
API_TOKEN='<redacted>'
# GRAPHQL_PORT=20214 set via environment

docker-compose.yml

services:
  netalertx:
    image: ghcr.io/netalertx/netalertx:latest
    container_name: netalertx
    network_mode: host
    read_only: true
    restart: unless-stopped
    cap_drop:
      - ALL
    cap_add:
      - NET_ADMIN
      - NET_RAW
      - NET_BIND_SERVICE
      - CHOWN
      - SETUID
      - SETGID
    volumes:
      - ./data:/data
      - /etc/localtime:/etc/localtime:ro
    tmpfs:
      - "/tmp:mode=1700,uid=0,gid=0,rw,noexec,nosuid,nodev,async,noatime,nodiratime"
    environment:
      PUID: "20211"
      PGID: "20211"
      LISTEN_ADDR: "0.0.0.0"
      PORT: "20211"
      GRAPHQL_PORT: "20214"

Debug or Trace enabled

  • I have read and followed the steps in the wiki link above and provided the required debug logs and the log section covers the time when the issue occurs.

Relevant app.log section

12:55:43 [MCP] Created session: 0b6b10b07cd94f9989df9c38be26ed77
12:55:46 [HTTP] POST /mcp/messages from 127.0.0.1
127.0.0.1 - - [21/Oct/2026 12:55:46] "POST /mcp/messages?session_id=0b6b10b07cd94f9989df9c38be26ed77 HTTP/1.1" 202 -
12:55:46 [MCP] Deleted session: 0b6b10b07cd94f9989df9c38be26ed77

nginx-access.log: the unprefixed request gets a 404, the prefixed one is proxied and gets a 202:

<client> - - [21/Oct/2026:12:55:46 +0200] "POST /mcp/messages?session_id=0b6b10b07cd94f9989df9c38be26ed77 HTTP/1.1" 404 146 "-" "curl/8.7.1" "-"
<client> - - [21/Oct/2026:12:55:46 +0200] "POST /server/mcp/messages?session_id=0b6b10b07cd94f9989df9c38be26ed77 HTTP/1.1" 202 37 "-" "curl/8.7.1" "-"

nginx-error.log: the unprefixed path falls through to static file serving:

2026/10/21 12:55:46 [error] 253#253: *40 open() "/app/front/mcp/messages" failed (2: No such file or directory), client: <client>, server: , request: "POST /mcp/messages?session_id=0b6b10b07cd94f9989df9c38be26ed77 HTTP/1.1", host: "<host>:20211"

Docker Logs

12:53:20 [MCP] Cleaning up expired session: bdf10972895f4efeafecfcf7b50d76c4

(docker logs netalertx --tail 200 2>&1 | grep -iE "mcp|error": nothing else relevant. The 404 happens in nginx before the request reaches the backend.)

Activity

  1. added
    bug 🐛Something isn't working
    Waiting for reply⏳Waiting for the original poster to respond, or discussion in progress.
    next release/in dev image 🚀This is coming in the next release or was already released if the issue is Closed.
    on Oct 23, 2026
  2. jokob-sk commented on Oct 23, 2026

    @jokob-sk
    Collaborator

    This should be available/fixed in the next release.

    It would be great if you could test the ghcr.io/netalertx/netalertx-dev / ghcr.io/netalertx/netalertx-dev-unsafe Docker image in ~15 minutes (or once the latest GitHub Action finishes).

    ⚠️ Please back up everything first, or ideally spin up a separate container (make sure you use a unique PORT and GRAPHQL_PORT if running instances concurrently) with its own DB and config (a copy of your current setup), as database changes may occur.

    After updating:

    • Click the 🔄 refresh button in the blue header at the top
    • Hard refresh your browser cache (shift + reload) to force js and css files reload

    👉 If I don’t receive confirmation that this works, I may revert the changes to avoid introducing bugs.

    Disclaimer: Running the dev container long-term may lead to data loss, as upgrade paths are not guaranteed.

    Thanks in advance,
    j

  3. frdmn commented on Oct 23, 2026

    @frdmn
    ContributorAuthor

    Tested ghcr.io/netalertx/netalertx-dev:latest in a separate container (own ports and data, same compose setup as in the report) — works 👍

    • SSE endpoint event is now relative: data: messages?session_id=...
    • Through the nginx proxy (http://<host>:<PORT>/server/mcp/sse), the client resolves it to /server/mcp/messages?...; initialize and tools/list both return 202 and the responses arrive on the stream (73 tools).
    • Claude Code connects via the proxied URL, which failed before with the 404.

    Thanks for the quick merge!

  4. jokob-sk commented on Oct 23, 2026

    @jokob-sk
    Collaborator

    Thanks - publishing in ~1h - > closing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Waiting for reply⏳Waiting for the original poster to respond, or discussion in progress.bug 🐛Something isn't workingnext release/in dev image 🚀This is coming in the next release or was already released if the issue is Closed.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions