Skip to content

Commit 3f95af0

Browse files
authored
feat: stream container stderr in real-time instead of only on failure (#621)
Container/process stderr is now streamed to logs continuously while the process runs, rather than only being printed when the connection fails. This helps with debugging container issues as they happen. - Uses io.MultiWriter to capture stderr to both a buffer and a pipe - Goroutine streams stderr lines to logs in real-time - Buffer is still available for error reporting on failure
2 parents 68b07be + 9a7168f commit 3f95af0

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

internal/mcp/connection.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package mcp
22

33
import (
4+
"bufio"
45
"bytes"
56
"context"
67
"encoding/json"
@@ -190,11 +191,25 @@ func NewConnection(ctx context.Context, command string, args []string, env map[s
190191
}
191192
}
192193

193-
// Capture stderr to help diagnose container failures
194+
// Capture and stream stderr to help diagnose container issues
194195
// The SDK's CommandTransport only uses stdin/stdout for MCP protocol,
195196
// so we can capture stderr separately for debugging
197+
// Use a TeeReader-style approach: write to both a buffer (for error reporting)
198+
// and to a pipe that streams to logs in real-time
196199
var stderrBuf bytes.Buffer
197-
cmd.Stderr = &stderrBuf
200+
stderrPipeReader, stderrPipeWriter := io.Pipe()
201+
cmd.Stderr = io.MultiWriter(&stderrBuf, stderrPipeWriter)
202+
203+
// Stream stderr to logs in a goroutine
204+
go func() {
205+
defer stderrPipeReader.Close()
206+
scanner := bufio.NewScanner(stderrPipeReader)
207+
for scanner.Scan() {
208+
line := scanner.Text()
209+
logger.LogInfo("backend", "[%s stderr] %s", command, line)
210+
logConn.Printf("[stderr] %s", line)
211+
}
212+
}()
198213

199214
logger.LogInfo("backend", "Starting MCP backend server, command=%s, args=%v", command, sanitize.SanitizeArgs(expandedArgs))
200215
log.Printf("Starting MCP server command: %s %v", command, sanitize.SanitizeArgs(expandedArgs))
@@ -206,6 +221,7 @@ func NewConnection(ctx context.Context, command string, args []string, env map[s
206221
session, err := client.Connect(ctx, transport, nil)
207222
if err != nil {
208223
cancel()
224+
stderrPipeWriter.Close() // Close pipe to stop the stderr streaming goroutine
209225

210226
// Enhanced error context for debugging
211227
logger.LogErrorMd("backend", "MCP backend connection failed, command=%s, args=%v, error=%v", command, sanitize.SanitizeArgs(expandedArgs), err)

0 commit comments

Comments
 (0)