# MCP Server Transport Mechanisms: STDIO, SSE, and Streamable HTTP Explained

> Explore MCP server transport mechanisms: STDIO, SSE, and Streamable HTTP. Understand these SDK transport classes for flexible JSON-RPC communication in your deployments.

- Repository: [Model Context Protocol/servers](https://github.com/modelcontextprotocol/servers)
- Tags: deep-dive
- Published: 2026-03-01

---

**The Model Context Protocol (MCP) server supports three distinct transport mechanisms—STDIO, Server-Sent Events (SSE), and Streamable HTTP—each implemented via specific SDK transport classes that enable JSON-RPC communication across different deployment scenarios.**

The Model Context Protocol (MCP) provides standardized communication between AI clients and servers through pluggable transport layers. In the `modelcontextprotocol/servers` repository, the reference implementation exposes three MCP server transport mechanisms that handle message serialization differently while sharing identical core logic. These transports range from simple process pipes for local development to sophisticated HTTP-based streaming with automatic reconnection support.

## STDIO Transport

The **STDIO transport** provides the simplest communication mechanism using standard process input and output streams.

### Implementation Details

In [`src/everything/transports/stdio.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/transports/stdio.ts), the server instantiates `StdioServerTransport` from the MCP SDK to create a bidirectional pipe. This transport reads JSON-RPC messages from `process.stdin` and writes responses to `process.stdout`, making it ideal for local development, testing scenarios, or when the MCP server runs as a spawned child process.

When you execute the server without arguments or explicitly specify `stdio`, the transport initializes immediately and begins parsing newline-delimited JSON-RPC frames from the parent process.

## Server-Sent Events (SSE) Transport

The **SSE transport** enables HTTP-based streaming communication using the Server-Sent Events protocol for unidirectional server-to-client pushes.

### Implementation Details

Located in [`src/everything/transports/sse.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/transports/sse.ts), this implementation uses Express to expose two critical endpoints:

1. **GET /sse** – Creates a new `SSEServerTransport` instance and registers it in a `Map<string, SSEServerTransport>` keyed by a generated `sessionId`
2. **POST /message** – Receives client-initiated JSON-RPC requests, looks up the corresponding transport by `sessionId`, and forwards the request via `transport.handlePostMessage`

The transport maintains persistent connections with `Content-Type: text/event-stream`, pushing server-side events to connected clients as they occur. This approach suits scenarios requiring real-time updates but relies on separate HTTP POST requests for client-to-server communication.

## Streamable HTTP Transport

The **Streamable HTTP transport** offers the most robust solution, combining bidirectional HTTP communication with resumable stream capabilities.

### Implementation Details

Implemented in [`src/everything/transports/streamableHttp.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/transports/streamableHttp.ts), this transport uses `StreamableHTTPServerTransport` from the SDK and introduces several advanced features:

**Session Management** – A `Map<string, StreamableHTTPServerTransport>` stores active transports per `sessionId`, enabling multiple concurrent client connections.

**POST /mcp Endpoint** – Handles both session initialization (when no `mcp-session-id` header exists) and subsequent requests (when the header is present). During initialization, the server generates a `randomUUID` session identifier and attaches an `InMemoryEventStore` to buffer events for replay.

**GET /mcp Endpoint** – Provides an SSE-compatible stream for established sessions. The server checks the optional `Last-Event-ID` header and replays missed events from the in-memory store, enabling seamless client reconnection after network interruptions.

**DELETE /mcp Endpoint** – Terminates active sessions, explicitly cleaning up the transport instance and associated event store to prevent memory leaks.

The `InMemoryEventStore` class (defined within the same file) maintains a bounded buffer of server-sent events, allowing clients to resume streams exactly where they left off using standard HTTP headers.

## How Transport Selection Works

The entry point at [`src/everything/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/index.ts) parses a single CLI argument to determine which transport module to load:

```bash
node ./index.js [stdio|sse|streamableHttp]

```

If omitted, the system defaults to `stdio`. The selected transport module's `main()` routine creates the appropriate transport instance, builds the core MCP server via `createServer()`, connects them, and installs graceful shutdown handlers for `SIGINT` signals.

## Practical Code Examples

### Starting a STDIO Server

```bash
node ./src/everything/index.js stdio

```

**Output:**

```

Starting default (STDIO) server...

```

### Starting an SSE Server

```bash
node ./src/everything/index.js sse

```

**Output:**

```

Starting SSE server...
Server is running on port 3001

```

**Client connection example:**

```javascript
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";

const transport = new SSEClientTransport({
  url: "http://localhost:3001/sse",
});

await transport.connect();
const response = await transport.request({ 
  jsonrpc: "2.0", 
  method: "ping", 
  id: 1 
});
console.log(response);

```

### Starting a Streamable HTTP Server

```bash
node ./src/everything/index.js streamableHttp

```

**Output:**

```

Starting Streamable HTTP server...

```

**Client connection example:**

```javascript
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

const transport = new StreamableHTTPClientTransport({
  url: "http://localhost:3001/mcp",
});

await transport.connect(); // Receives mcp-session-id header
const resp = await transport.request({ 
  jsonrpc: "2.0", 
  method: "status", 
  id: 42 
});
console.log(resp);

```

### Embedding Transport Directly

For embedding the server within existing applications:

```typescript
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { createServer } from "./src/everything/server/index.js";

async function runEmbedded() {
  const transport = new StdioServerTransport();
  const { server, cleanup } = createServer();
  await server.connect(transport);
  
  process.on("SIGINT", async () => {
    await server.close();
    cleanup();
    process.exit(0);
  });
}
runEmbedded();

```

## Summary

- **STDIO** provides process-based communication through `process.stdin` and `process.stdout`, ideal for local development and child process spawning.
- **SSE** enables HTTP streaming via Express routes (`/sse` and `/message`), using session maps to manage multiple client connections.
- **Streamable HTTP** offers production-grade bidirectional communication with automatic session resumption via `InMemoryEventStore` and standard HTTP headers.
- All transports share the same core server logic from [`src/everything/server/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/server/index.ts), differing only in their message serialization layers.
- Transport selection occurs at startup through CLI arguments parsed in [`src/everything/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/index.ts), defaulting to STDIO when unspecified.

## Frequently Asked Questions

### What is the difference between SSE and Streamable HTTP transports?

**SSE provides unidirectional server-to-client streaming over HTTP**, requiring separate POST requests for client-to-server communication and managing sessions through a `Map<string, SSEServerTransport>`. **Streamable HTTP offers true bidirectional communication** through a single endpoint (`/mcp`) with support for session resumption via the `Last-Event-ID` header and the `InMemoryEventStore`, making it more resilient for production environments where network interruptions occur.

### When should I use STDIO instead of HTTP-based transports?

**Use STDIO when running the MCP server as a local child process or during development**, as implemented in [`src/everything/transports/stdio.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/transports/stdio.ts). This transport eliminates network overhead and simplifies debugging by using standard process pipes. HTTP transports (SSE or Streamable HTTP) become necessary when clients need to connect over networks or when the server must handle multiple concurrent connections across different machines.

### How does session resumption work in the Streamable HTTP transport?

The **Streamable HTTP transport** in [`src/everything/transports/streamableHttp.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/transports/streamableHttp.ts) stores emitted events in an `InMemoryEventStore` associated with each session ID. When a client reconnects using the `Last-Event-ID` header on the GET `/mcp` endpoint, the server replays missed events from the store before streaming new ones. This mechanism ensures no messages are lost during temporary disconnections, though events are currently stored in memory and lost if the server process restarts.

### Can I switch transports without modifying the core server logic?

**Yes**, the transport layer is completely decoupled from the core MCP server implementation. As shown in [`src/everything/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/index.ts), all transports use the same `createServer()` factory function from [`src/everything/server/index.ts`](https://github.com/modelcontextprotocol/servers/blob/main/src/everything/server/index.ts). You can switch between STDIO, SSE, and Streamable HTTP simply by changing the CLI argument or importing a different transport module, without altering any business logic or tool implementations within the server itself.