Skip to content

Race conditions in SSE server code #22

@bastiandoetsch

Description

@bastiandoetsch

It seems like there's data races (at least during testing):

==================
WARNING: DATA RACE
Read at 0x00c003564228 by goroutine 47:
  bufio.(*Writer).Available()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:656 +0xa8
  bufio.(*Writer).Write()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:674 +0x1c
  fmt.Fprintf()
      /opt/homebrew/opt/go/libexec/src/fmt/print.go:225 +0x94
  net/http.(*chunkWriter).Write()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:383 +0x2c0
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:639 +0xc0
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1772 +0x60
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:196 +0x560
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Previous write at 0x00c003564228 by goroutine 40:
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:651 +0x2a8
  net/http.(*chunkWriter).flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:403 +0x8c
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1773 +0x78
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:149 +0x8ec
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Goroutine 47 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298
[snip]

Goroutine 40 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298
[snip]
==================
==================
WARNING: DATA RACE
Write at 0x00c0035ac000 by goroutine 47:
  runtime.slicecopy()
      /opt/homebrew/opt/go/libexec/src/runtime/slice.go:355 +0x0
  bufio.(*Writer).Write()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:691 +0x2a8
  fmt.Fprintf()
      /opt/homebrew/opt/go/libexec/src/fmt/print.go:225 +0x94
  net/http.(*chunkWriter).Write()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:383 +0x2c0
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:639 +0xc0
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1772 +0x60
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:196 +0x560
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Previous read at 0x00c0035ac000 by goroutine 40:
  runtime.racereadrange()
      <autogenerated>:1 +0x14
  internal/poll.ignoringEINTRIO()
      /opt/homebrew/opt/go/libexec/src/internal/poll/fd_unix.go:745 +0x3f8
  internal/poll.(*FD).Write()
      /opt/homebrew/opt/go/libexec/src/internal/poll/fd_unix.go:381 +0x234
  net.(*netFD).Write()
      /opt/homebrew/opt/go/libexec/src/net/fd_posix.go:96 +0x44
  net.(*conn).Write()
      /opt/homebrew/opt/go/libexec/src/net/net.go:201 +0x84
  net.(*TCPConn).Write()
      <autogenerated>:1 +0x4c
  net/http.checkConnErrorWriter.Write()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3872 +0x60
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:639 +0xc0
  net/http.(*chunkWriter).flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:403 +0x8c
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1773 +0x78
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:149 +0x8ec
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Goroutine 47 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298

Goroutine 40 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298
==================
==================
WARNING: DATA RACE
Write at 0x00c0035ac116 by goroutine 47:
  runtime.slicecopy()
      /opt/homebrew/opt/go/libexec/src/runtime/slice.go:355 +0x0
  bufio.(*Writer).Write()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:691 +0x2a8
  net/http.(*chunkWriter).Write()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:391 +0x3a8
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:639 +0xc0
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1772 +0x60
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:196 +0x560
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleMessage-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Previous read at 0x00c0035ac110 by goroutine 40:
  runtime.racereadrange()
      <autogenerated>:1 +0x14
  internal/poll.ignoringEINTRIO()
      /opt/homebrew/opt/go/libexec/src/internal/poll/fd_unix.go:745 +0x3f8
  internal/poll.(*FD).Write()
      /opt/homebrew/opt/go/libexec/src/internal/poll/fd_unix.go:381 +0x234
  net.(*netFD).Write()
      /opt/homebrew/opt/go/libexec/src/net/fd_posix.go:96 +0x44
  net.(*conn).Write()
      /opt/homebrew/opt/go/libexec/src/net/net.go:201 +0x84
  net.(*TCPConn).Write()
      <autogenerated>:1 +0x4c
  net/http.checkConnErrorWriter.Write()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3872 +0x60
  bufio.(*Writer).Flush()
      /opt/homebrew/opt/go/libexec/src/bufio/bufio.go:639 +0xc0
  net/http.(*chunkWriter).flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:403 +0x8c
  net/http.(*response).FlushError()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1773 +0x78
  net/http.(*response).Flush()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:1765 +0x28
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:149 +0x8ec
  github.com/mark3labs/mcp-go/server.(*SSEServer).handleSSE-fm()
      <autogenerated>:1 +0x4c
  net/http.HandlerFunc.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2220 +0x48
  net/http.(*ServeMux).ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2747 +0x1c4
  net/http.serverHandler.ServeHTTP()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3210 +0x2a8
  net/http.(*conn).serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:2092 +0xe58
  net/http.(*Server).Serve.gowrap3()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x4c

Goroutine 47 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298
  [snip]

Goroutine 40 (running) created at:
  net/http.(*Server).Serve()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3360 +0x674
  net/http.(*Server).ListenAndServe()
      /opt/homebrew/opt/go/libexec/src/net/http/server.go:3259 +0xb0
  github.com/mark3labs/mcp-go/server.(*SSEServer).Start()
      /Users/x/workspace/go/pkg/mod/github.com/mark3labs/[email protected]/server/sse.go:74 +0x298
[snip]
==================

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