-
Notifications
You must be signed in to change notification settings - Fork 233
Description
Describe the bug
The MCP Go SDK does not enforce the MCP specification requirement that "In the stdio transport, the server MUST NOT write anything to its stdout that is not a valid MCP message." Applications using the SDK can easily bypass the transport layer and write arbitrary content directly to os.Stdout, violating the MCP protocol.
To Reproduce
Current stdio transport Implementation (How it fails to ensure compliance)
1. Transport Layer Implementation:
// mcp/transport.go:92-94
func (*StdioTransport) Connect(context.Context) (Connection, error) {
return newIOConn(rwc{os.Stdin, os.Stdout}), nil
}2. rwc Wrapper:
// mcp/transport.go:273-288
type rwc struct {
rc io.ReadCloser
wc io.WriteCloser
}
func (r rwc) Write(p []byte) (n int, err error) {
return r.wc.Write(p) // Direct passthrough to os.Stdout
}3. ioConn Write Method:
// mcp/transport.go:541-590
func (t *ioConn) Write(ctx context.Context, msg jsonrpc.Message) error {
data, err := jsonrpc2.EncodeMessage(msg) // Only validates JSON-RPC format
if err != nil {
return err
}
data = append(data, '\n')
_, err = t.rwc.Write(data) // Writes to wrapped stdout
return err
}Expected behavior
From MCP Spec (stdio transport):
"The server MUST NOT write anything to its
stdoutthat is not a valid MCP message."
Key Points:
- This is a MUST NOT requirement (mandatory compliance)
- Applies specifically to stdout writes
- Requires prevention of non-MCP content, not just correctness validation
How MCP Server Can Violate the Rule:
1. In the MCP Server, direct os.Stdout Access:
// This bypasses the SDK entirely
fmt.Fprintf(os.Stdout, "DEBUG: Server started\n")
os.Stdout.WriteString("Hello World!\n")
fmt.Print("Another violation!\n")2. No Prevention Mechanisms:
os.Stdoutremains globally accessible- No wrapper or interceptor around stdout
- No runtime validation of stdout content
- No warnings or errors when non-MCP content is written
Logs
If applicable, add logs to help explain your problem.
Additional context
Possible Fix
Option 1: Wrapper-Based Prevention (Recommended)
type mcpStdout struct {
original *os.File
validator func([]byte) error
}
func (m *mcpStdout) Write(p []byte) (n int, err error) {
if err := m.validator(p); err != nil {
return 0, fmt.Errorf("MCP compliance violation: %w", err)
}
return m.original.Write(p)
}