# SSE or Streamable HTTP transport implemented correctly if offered

- **Pattern:** `ab-001835` (`mcp-server.transport-protocol.http-transport`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-18
- **Canonical URL:** https://auditbuffet.com/patterns/ab-001835
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-001835)

## Why it matters

Servers offering HTTP/SSE transport must produce strictly formatted SSE events with `data:` prefixes and proper `Content-Type: text/event-stream`. Omitting the `data:` prefix causes clients to receive unparseable chunks. Missing CORS headers (CWE-942) block browser-based MCP clients entirely via same-origin policy. Broken session ID management means concurrent clients corrupt each other's message streams. These are protocol-level failures that make the HTTP transport path non-functional for any client not on localhost.

## Severity rationale

Medium because SSE format errors and missing CORS headers break HTTP transport for specific client types without affecting stdio-connected clients.

## Remediation

Use the SDK's `SSEServerTransport` or `StreamableHTTPServerTransport` rather than implementing SSE manually.

```ts
// src/transport/http.ts
import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'
import { randomUUID } from 'crypto'

app.post('/mcp', async (req, res) => {
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: () => randomUUID(),
  })
  await server.connect(transport)
  await transport.handleRequest(req, res)
})
```

If you need custom CORS for browser clients, add `Access-Control-Allow-Origin` before the SSE response headers. Never implement the `data:` prefix manually — use the SDK transport.

## Detection

- **ID:** `http-transport`
- **Severity:** `medium`
- **What to look for:** Count all HTTP/SSE transport implementations. Enumerate whether the server supports Streamable HTTP with proper SSE event formatting. If the server offers HTTP-based transport (SSE or Streamable HTTP), check that the SSE endpoint sends proper `event: message` and `data:` fields. Check that the HTTP endpoint handles POST requests for client-to-server messages and GET/SSE for server-to-client messages. Check CORS headers if the server is meant to be accessed from browser-based clients. Check that the session ID mechanism works correctly for multi-client scenarios.
- **Pass criteria:** SSE events follow the standard format. HTTP endpoints correctly handle the request/response flow. CORS is configured if needed. Session management works for concurrent clients. HTTP transport must support SSE with proper `Content-Type: text/event-stream` headers and handle at least 10 concurrent connections.
- **Fail criteria:** SSE format is incorrect (missing event type or data prefix), HTTP endpoint doesn't handle POST correctly, missing CORS headers for browser clients, or session handling breaks with multiple clients.
- **Skip (N/A) when:** The server only uses stdio transport (no HTTP/SSE). All checks skip when no MCP server is detected.

- **Cross-reference:** For stdio transport, see `stdio-transport`.
- **Detail on fail:** `"SSE endpoint sends raw JSON without 'data: ' prefix — clients cannot parse the stream"` or `"HTTP transport has no CORS headers — browser-based MCP clients will be blocked by same-origin policy"`
- **Remediation:** If offering HTTP transport, follow the SSE and Streamable HTTP specs:

  ```ts
  // src/transport/http.ts — Streamable HTTP transport
  import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"
  ```

  ```ts
  // TypeScript SDK — SSE transport
  import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'

  app.get('/sse', async (req, res) => {
    const transport = new SSEServerTransport('/message', res)
    await server.connect(transport)
  })

  app.post('/message', async (req, res) => {
    await transport.handlePostMessage(req, res)
  })

  // Streamable HTTP transport
  import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'

  app.post('/mcp', async (req, res) => {
    const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID() })
    await server.connect(transport)
    await transport.handleRequest(req, res)
  })
  ```

## External references

- cwe CWE-942
- external mcp-spec-http-transport — https://modelcontextprotocol.io/docs/concepts/transports#http-with-sse

Taxons: inference-contract, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-001835
