SIGPIPE Analysis
Date: 2026-01-31 Impact: CRITICAL for Unix/Linux MCP server stability
Executive Summary¶
SIGPIPE handling is NOT optional for production MCP servers on Unix/Linux!
- Without SIGPIPE handling: Server process terminates when client disconnects
- With SIGPIPE handling: Server gracefully detects disconnect and cleans up
- Windows: No SIGPIPE exists, errors returned directly (already handled)
What is SIGPIPE?¶
Unix/Linux Behavior¶
SIGPIPE = "Broken Pipe" Signal
- Sent when: Process writes to a pipe/socket with closed reading end
- Default action: TERMINATE THE PROCESS (no core dump)
- MCP Context: Client dies/disconnects → server tries to write → SIGPIPE → server crashes
Real-World MCP Scenario¶
1. MCP client launches server subprocess (stdio transport)
2. Client and server communicate via stdin/stdout pipes
3. Client crashes or user closes editor
4. Server tries to write response to stdout
5. WITHOUT SIGPIPE HANDLER: Server process terminates immediately
6. WITH SIGPIPE HANDLER: Server detects disconnect, cleans up, exits gracefully
Impact Analysis¶
Unix/Linux Servers (CRITICAL)¶
| Scenario | Without SIGPIPE Handling | With SIGPIPE Handling |
|---|---|---|
| Client disconnect | Server crashes | Graceful shutdown |
| Network issues | Process termination | Error detection |
| Docker containers | Abrupt exit | Clean exit |
| Resource cleanup | NOT EXECUTED | Properly executed |
| Logs | Incomplete/corrupted | Flushed properly |
Real Impact: - Database connections not closed - Temp files not cleaned up - Logs not flushed - Parent process left in zombie state
Windows Servers (NO IMPACT)¶
- Windows does NOT implement POSIX SIGPIPE
- Socket write failures return error codes directly (WSAECONNRESET, etc.)
- Our code already checks return values and handles errors
- Conclusion: Silent logging on Windows is appropriate
MCP Protocol Best Practices¶
From official MCP specification and community best practices:
Required: SIGPIPE Handling¶
# REQUIRED for robust MCP servers on Unix/Linux
import signal
# Option 1: Ignore SIGPIPE (get EPIPE error instead)
signal.signal(signal.SIGPIPE, signal.SIG_IGN)
# Option 2: Handle SIGPIPE for graceful shutdown
signal.signal(signal.SIGPIPE, graceful_shutdown_handler)
MCP Server Transport Requirements¶
- stdio communication: Client ↔ Server via stdin/stdout
- JSON-RPC messages: One per line, newline-delimited
- stdout MUST ONLY contain protocol messages (no logs, no debug output)
- stderr for logs only
- SIGPIPE handling REQUIRED for graceful disconnect detection
Current Implementation Analysis¶
What the Code Does Now¶
# src/mcp_atlassian/utils/lifecycle.py (line 40-45)
if hasattr(signal, "SIGPIPE"):
signal.signal(signal.SIGPIPE, signal_handler)
logger.debug("SIGPIPE handler registered")
else:
logger.debug("SIGPIPE not available on this platform")
Behavior: - Unix/Linux: Registers graceful shutdown handler → Server survives client disconnect - Windows: Logs that SIGPIPE isn't available → No issue (Windows doesn't need it)
Signal Handler Implementation¶
def signal_handler(signum: int, frame: Any) -> None:
"""Handle shutdown signals gracefully."""
_shutdown_event.set() # Thread-safe shutdown trigger
What this achieves:
- SIGPIPE triggers shutdown event
- Main loop detects shutdown event
- ensure_clean_exit() flushes streams
- Resources cleaned up properly
- Process exits cleanly
Decision: Is Silent Logging Appropriate?¶
Option 1: Keep Debug-Level Logging (CURRENT)¶
Pros: - No noise in production logs - Developers see it when debugging (debug level) - Appropriate for platform difference (not an error)
Cons: - Silent on Windows (but Windows doesn't need it)
Option 2: Upgrade to Info-Level Logging¶
Pros: - More visible in logs - Makes cross-platform behavior explicit
Cons: - Log noise on every Windows startup - Not actionable (Windows users can't "fix" this)
Option 3: Warning-Level Logging¶
Pros: - Alerts to potential issue
Cons: - FALSE WARNING - Windows handles disconnects differently (via error codes) - Creates unnecessary alarm
Recommendation¶
✅ KEEP DEBUG-LEVEL LOGGING (Current Implementation)¶
Rationale:
- Windows doesn't need SIGPIPE - It handles disconnects via error codes (WSAECONNRESET)
- Not an error or warning - It's expected platform behavior
- Debug visibility - Developers debugging can see the platform detection
- No action needed - Users can't and shouldn't do anything about it
- Follows Python conventions - Debug for informational platform differences
Enhancement: Improve Documentation¶
Update the docstring to make the platform behavior explicit:
def setup_signal_handlers() -> None:
"""Set up signal handlers for graceful shutdown.
Registers handlers for SIGTERM, SIGINT, and SIGPIPE (Unix/Linux only) to ensure
the application shuts down cleanly when receiving termination signals.
Platform Behavior:
- Unix/Linux: SIGPIPE handled to prevent process termination on client disconnect
- Windows: SIGPIPE not available (socket errors returned directly instead)
This is particularly important for:
- MCP stdio transport (client disconnect detection)
- Docker containers running with the -i flag
- Long-running server processes with unreliable clients
"""
Celebration: What We Fixed¶
🎉 Mypy Error FIXED¶
Before: Module has no attribute "SIGPIPE"
After: Type-safe check with hasattr(signal, "SIGPIPE")
🎉 Pre-commit Hooks ENABLED¶
Before: Had to use --no-verify to commit
After: All checks pass cleanly!
🎉 Technical Debt REMOVED¶
Before: Pre-existing error blocking all contributors After: Clean codebase for everyone!
🎉 Platform Support VERIFIED¶
Before: Assumed SIGPIPE was optional After: Confirmed it's CRITICAL for Unix/Linux MCP servers
Testing Coverage¶
Current Tests ✅¶
- test_setup_signal_handlers_all_platforms - SIGPIPE available (Unix/Linux)
- test_setup_signal_handlers_no_sigpipe - SIGPIPE not available (Windows)
- test_signal_handler_function - Handler sets shutdown event correctly
All tests passing with new hasattr() implementation!
References¶
- MCP Specification - Transports
- MCP Lifecycle & Graceful Shutdown
- SIGPIPE Best Practices for Servers
- Handling SIGPIPE Properly (Stack Overflow)
- Building MCP Servers with stdio
Conclusion¶
Silent debug logging for missing SIGPIPE is the RIGHT choice:
✅ Windows doesn't need SIGPIPE (different error handling) ✅ Not an error or warning (expected platform difference) ✅ Debug visibility for developers ✅ No actionable information for users ✅ Follows Python logging best practices
The implementation is CORRECT and CRITICAL for production MCP servers!