MCP Server Connection Lifecycle in 5ire: Managing stdio, SSE, and HTTP Streaming Transports
The 5ire application handles the complete MCP server connection lifecycle through a unified state machine that discovers servers from the database, instantiates transport-specific clients, manages retry-aware connections, and emits discrete events for UI synchronization.
The MCPConnectionsManager class in the nanbingxyz/5ire repository orchestrates Model Context Protocol server connections across three transport types: stdio, Server-Sent Events (SSE), and HTTP streaming. According to the source code in src/main/services/mcp-connections-manager.ts, the manager abstracts protocol differences behind a consistent interface while maintaining transport-specific optimizations for process spawning, stream handling, and connection teardown.
Discovery and Initialization via Live Query
The lifecycle begins when MCPConnectionsManager.init() queries the database for all active MCP server records. This method, located at lines 420–432 in src/main/services/mcp-connections-manager.ts, establishes a live-query subscription that watches for inserts, updates, and deletes in real time.
Each database change triggers an automatic connect or disconnect operation. The server records include a transport field specifying either "stdio", "sse", or "http", which determines the subsequent transport instantiation strategy. This reactive architecture ensures the application state remains synchronized with the database without requiring manual refresh cycles.
Transport Creation and Protocol Abstraction
The private #transport method (lines 71–96) creates transport objects based on the server configuration. This abstraction layer allows the rest of the lifecycle to remain transport-agnostic.
stdio transports split the endpoint string into command and arguments, then instantiate StdioClientTransport from the MCP SDK:
const args = server.endpoint.split(" ").filter(Boolean);
const command = args.shift()!;
const transport = new StdioClientTransport({
command,
args,
env: server.config,
stderr: "ignore",
});
SSE and HTTP streaming transports both use StreamableHTTPClientTransport, a unified class that handles both Server-Sent Events and plain HTTP streaming protocols. The endpoint is parsed as a URL and passed to the transport constructor:
const url = new URL(server.endpoint);
const transport = new StreamableHTTPClientTransport(url, {
requestInit: { headers: server.config },
});
This design eliminates the need for separate SSEClientTransport logic, consolidating streaming HTTP handling into a single implementation.
Connection Establishment with Retry Logic
The #connect method (lines 103–193) implements the core connection handshake. It instantiates a Client with static implementation info (CLIENT_IMPLEMENTATION) and capabilities (CLIENT_CAPABILITIES), then attempts to connect using the previously created transport.
Connection attempts execute within a retry loop configured for maximum three attempts with exponential backoff via setTimeout. An AbortController provides cancellation semantics for in-flight connection attempts:
const client = new Client({ name: "5ire", version: "1.0" });
await client.connect(transport, {});
If the server returns valid capabilities, the manager stores a connected state object. Failed attempts record error states and close the client to prevent resource leaks.
State Management and Event Emission
The manager maintains connection state in a Map<string, Connection> where each entry tracks one of three statuses defined in the MCPConnectionsManager.Connection type (lines 66–88): connecting, connected, or error. State updates flow through the Stateful base class using the update method.
State transitions trigger specific events that UI components consume:
server-connected(lines 165–168): Emitted when capability negotiation succeedsserver-disconnected(lines 216–218): Emitted when a server is removed or explicitly disconnected
Listeners react to these high-level events without needing knowledge of the underlying transport implementation. This decoupling allows the frontend to display connection status consistently regardless of whether the backend uses stdio processes or HTTP streams.
Graceful Disconnection and Resource Cleanup
The #disconnect method handles teardown through two pathways depending on connection status. For established connections, it invokes client.close(), which delegates to the transport-specific shutdown logic—terminating stdio processes or canceling HTTP streams. For connections still in the connecting phase, it aborts the pending attempt via the AbortController.
After cleanup, the manager removes the entry from the internal state map and emits the disconnection event, completing the lifecycle.
Summary
- Discovery:
init()queries active servers and subscribes to live database changes at startup - Transport selection: The
#transportmethod createsStdioClientTransportfor local processes orStreamableHTTPClientTransportfor SSE/HTTP endpoints (lines 71–96) - Resilient connections: The
#connectmethod implements 3-attempt retry logic with exponential backoff and abort capabilities (lines 103–193) - Unified state: Three statuses (
connecting,connected,error) managed through theStatefulbase class - Event-driven architecture:
server-connectedandserver-disconnectedevents abstract transport details from UI components
Frequently Asked Questions
How does 5ire handle different MCP transport types internally?
The MCPConnectionsManager inspects the transport field in each server record. For stdio connections, it splits the endpoint into command arguments and creates a StdioClientTransport. For SSE and HTTP streaming, it parses the endpoint as a URL and instantiates StreamableHTTPClientTransport, which handles both protocols through a single implementation.
What happens when an MCP server connection fails?
The connection routine in #connect implements a retry loop with a maximum of three attempts and exponential backoff. If all retries exhaust without receiving server capabilities, the manager closes the client, records an error state in the connection map, and prevents further connection attempts until the next database update triggers a fresh cycle.
How does the application know when to connect or disconnect an MCP server?
The manager subscribes to a Supabase live query during initialization that monitors the MCP servers table. Insertions trigger automatic connection attempts, updates trigger reconnection cycles, and deletions trigger disconnection and cleanup. This reactive pattern ensures the connection state always reflects the current database configuration.
What's the difference between SSE and HTTP streaming in 5ire's implementation?
There is no functional difference in the connection lifecycle. Both transport types use the same StreamableHTTPClientTransport class from the MCP SDK, which automatically negotiates the appropriate streaming mechanism based on server capabilities. The manager treats SSE and HTTP streaming as identical HTTP-based transports, eliminating the need for separate handling logic.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →