Skip to content

Proxy JAR drops initialize message when sent before SSE handshake completes #72

@dgilmanuni

Description

@dgilmanuni

Summary

The mcp-proxy-all.jar silently drops JSON-RPC messages (including initialize) that arrive on stdin before the SSE connection to the Burp MCP Server is fully established. This causes MCP clients like Claude Code to fail to connect, as the initialize response is never received.

This is distinct from the SDK version mismatch fixed in commit 0a5ce34 (#53, #55) — the proxy now connects to the correct endpoint, but there is a ~3 second window during startup where stdin messages are lost.

Root Cause

The proxy JAR begins reading stdin on the main thread while the SSE connection is still being established asynchronously on the DefaultDispatcher thread. Messages received during this window are processed but have no active SSE session to forward to, so they are silently dropped with no error on stderr or stdout.

Startup sequence (observed via stderr logs):

T+0.000s  Starting Burp MCP proxy with SSE URL: http://127.0.0.1:9876
T+0.001s  No explicit authentication configured (will auto-detect OAuth 2.1)
T+0.017s  No authentication configured, checking if server supports OAuth 2.1...
T+0.162s  Using insecure HTTP for OAuth endpoints (OAuth probe)
T+0.244s  Using non-OAuth authentication for SSE connection
T+0.301s  Successfully connected to SSE server  ← stdin is only safe AFTER this

An MCP client that sends initialize at any point before ~T+0.3s will have its message dropped.

Reproduction

# ❌ FAILS: message sent immediately (how Claude Code invokes it)
echo '{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}},"id":1}' \
  | java -jar libs/mcp-proxy-all.jar --sse-url http://127.0.0.1:9876
# Result: proxy connects, reads the message, outputs nothing, exits on stdin EOF

# ✅ WORKS: message sent after SSE handshake (3s delay)
python3 -c "
import subprocess, time, json
proc = subprocess.Popen(
    ['java', '-jar', 'libs/mcp-proxy-all.jar', '--sse-url', 'http://127.0.0.1:9876'],
    stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
time.sleep(3)  # wait for SSE
proc.stdin.write(json.dumps({'jsonrpc':'2.0','method':'initialize','params':{'protocolVersion':'2024-11-05','capabilities':{},'clientInfo':{'name':'test','version':'1.0'}},'id':1}) + '\n')
proc.stdin.flush()
time.sleep(2)
print(proc.stdout.readline())  # prints valid initialize response
proc.kill()
"

Suggested Fix

Buffer stdin messages in the proxy until the SSE connection is established, then replay them in order. Alternatively, block the stdin reader thread until the SSE session ID is received.

Pseudocode:

// Current (broken): reads stdin immediately
launch { readStdin() }
launch { connectSse() }

// Fixed: gate stdin on SSE readiness
val sseReady = CompletableDeferred<Unit>()
launch { connectSse(); sseReady.complete(Unit) }
launch { sseReady.await(); readStdin() }

Workaround

Wrap the proxy JAR in a script that monitors stderr for "Successfully connected" before forwarding stdin:

#!/usr/bin/env python3
"""Buffer stdin until proxy's SSE connection is ready."""
import subprocess, sys, threading

proc = subprocess.Popen(
    ["java", "-jar", "libs/mcp-proxy-all.jar", "--sse-url", "http://127.0.0.1:9876"],
    stdin=subprocess.PIPE, stdout=sys.stdout.buffer, stderr=subprocess.PIPE)

# Wait for readiness signal on stderr
while True:
    line = proc.stderr.readline()
    if not line:
        break
    sys.stderr.buffer.write(line)
    sys.stderr.buffer.flush()
    if b"Successfully connected" in line:
        break

# Drain remaining stderr
threading.Thread(target=lambda: [sys.stderr.buffer.write(l) or sys.stderr.buffer.flush()
    for l in proc.stderr], daemon=True).start()

# Forward stdin
try:
    for line in sys.stdin.buffer:
        proc.stdin.write(line)
        proc.stdin.flush()
except (BrokenPipeError, IOError):
    pass
finally:
    proc.stdin.close()
sys.exit(proc.wait())

Environment

  • Burp Suite Professional, MCP Server extension loaded from local build (repo HEAD 77c423b)
  • mcp-proxy-all.jar from commit 0a5ce34 (Feb 18 update)
  • macOS Darwin 25.3.0, Java 21
  • Claude Code (MCP client, stdio transport)

Related Issues

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions