# SSE vs Streamable HTTP vs OpenAPI: MetaMCP Endpoint Types Explained

> Understand MetaMCP endpoint types: SSE, Streamable HTTP, and OpenAPI. Learn their differences in directionality, session lifecycle, and implementation. Choose the right transport for your RPC or request/response needs.

- Repository: [metatool-ai/metamcp](https://github.com/metatool-ai/metamcp)
- Tags: deep-dive
- Published: 2026-03-07

---

**MetaMCP supports three distinct public endpoint transports—SSE (Server-Sent Events), Streamable HTTP, and OpenAPI—each differing in directionality, session lifecycle, and transport implementation, with SSE being deprecated in favor of Streamable HTTP for bidirectional RPC while OpenAPI provides stateless HTTP request/response access.**

MetaMCP exposes namespaces through three endpoint types defined in the `McpServerTypeEnum` within [`packages/zod-types/src/mcp-servers.zod.ts`](https://github.com/metatool-ai/metamcp/blob/main/packages/zod-types/src/mcp-servers.zod.ts). While all three share the same logical endpoint record, they implement fundamentally different communication patterns: SSE provides unidirectional server pushes, Streamable HTTP enables bidirectional RPC sessions, and OpenAPI offers stateless RESTful access. Understanding these **SSE, Streamable HTTP, and OpenAPI endpoint types** is essential for selecting the appropriate integration pattern for real-time streaming, interactive tool calls, or simple HTTP-based automation.

## Server-Sent Events (SSE)

### Transport Implementation

The SSE transport utilizes `SSEServerTransport` on the server and `SSEClientTransport` on the client. In [`apps/backend/src/routers/public-metamcp/sse.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/sse.ts), the server creates a transport instance bound directly to the HTTP response object:

```typescript
const webAppTransport = new SSEServerTransport(
  `/metamcp/${endpointName}/message`,
  res,
);
sessionManager.addSession(webAppTransport.sessionId, webAppTransport);

```

This implementation is **unidirectional**, allowing the server to push events to the client but not receive messages over the same channel.

### Session Lifecycle and Deprecation

Sessions are created when a client opens `GET /:endpoint_name/sse` and are automatically cleaned up when the HTTP connection closes. The `SessionLifetimeManagerImpl` in [`apps/backend/src/lib/session-lifetime-manager.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/lib/session-lifetime-manager.ts) handles disposal via the `res.on("close")` handler triggering `cleanupSession`.

**Important:** SSE is deprecated as of the current MetaMCP codebase. According to line 747 in [`apps/backend/src/routers/mcp-proxy.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/mcp-proxy.ts), the server logs: `"New SSE connection request. NOTE: the sse transport is deprecated and has been replaced by StreamableHttp"`.

### Routing and Client Usage

The SSE router registers two endpoints:

- `GET /:endpoint_name/sse` – Opens the event stream
- `POST /:endpoint_name/message` – Allows clients to post data back to the session

Client-side usage typically involves:

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

const transport = new SSEClientTransport(new URL("<meta-mcp-url>/sse"));
await transport.connect();
await transport.sendMessage({ ... });

```

## Streamable HTTP

### Bidirectional RPC Transport

**Streamable HTTP** represents the current recommended transport, replacing SSE with full bidirectional communication. It uses `StreamableHTTPServerTransport` and `StreamableHTTPClientTransport` classes defined in [`apps/backend/src/routers/public-metamcp/streamable-http.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/streamable-http.ts).

Unlike SSE, this transport persists across multiple HTTP calls, enabling true RPC-style interaction where clients send requests and receive responses over the same logical session.

### Explicit Session Management

Sessions are created on the first `POST /:endpoint_name/mcp` request (or `GET` if the client supplies a session ID). The server implementation requires clients to include an `mcp-session-id` header for subsequent requests:

```typescript
if (!sessionId) {
  const newSessionId = randomUUID();
  const transport = new StreamableHTTPServerTransport({
    sessionIdGenerator: () => newSessionId,
    // ...
  });
  sessionManager.addSession(newSessionId, transport);
  await mcpServerInstance.server.connect(transport);
  await transport.handleRequest(req, res);
}

```

The session lives until the client explicitly calls `DELETE /:endpoint_name/mcp` or the automatic cleanup timer expires. This design allows the transport to live **outside** the individual HTTP request lifecycle.

### Routing Structure

The Streamable HTTP router registers three main routes:

1. `GET /:endpoint_name/mcp` – For GET-based messages (with session ID)
2. `POST /:endpoint_name/mcp` – Primary message endpoint and session creation
3. `DELETE /:endpoint_name/mcp` – Explicit session termination

## OpenAPI Endpoints

### Stateless HTTP Access

The **OpenAPI** endpoint type provides stateless access without any special transport classes. Implemented in [`apps/backend/src/routers/public-metamcp/openapi/routes.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/openapi/routes.ts), this approach treats each request as independent, using ordinary HTTP request/response semantics.

No persistent session is maintained; instead, the router generates documentation and handles tool execution on-demand.

### Schema Generation and Tool Execution

The OpenAPI router dynamically generates specifications using `generateOpenApiSchema` in [`apps/backend/src/routers/public-metamcp/openapi/schema-generator.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/openapi/schema-generator.ts), based on the `listToolsWithMiddleware` response:

```typescript
const result = await listToolsWithMiddleware(listToolsRequest, handlerContext);
const openApiSchema = await generateOpenApiSchema(result.tools || [], endpointName);
res.json(openApiSchema);

```

Available routes include:

- `GET /:endpoint_name/api` – HTML Swagger UI for documentation
- `GET /:endpoint_name/api/openapi.json` – JSON schema definition
- `POST /:endpoint_name/api/:tool_name` – Direct tool execution via `executeToolWithMiddleware`

### Client Integration

Clients interact with OpenAPI endpoints using standard HTTP fetch:

```typescript
// Fetch schema
const schema = await fetch(
  "https://my-metamcp.com/metamcp/my-endpoint/api/openapi.json"
).then(r => r.json());

// Execute tool
const result = await fetch(
  "https://my-metamcp.com/metamcp/my-endpoint/api/myTool",
  {
    method: "POST",
    headers: { 
      "Content-Type": "application/json", 
      "x-api-key": "..."
    },
    body: JSON.stringify({ /* tool params */ })
  }
).then(r => r.json());

```

## Key Architectural Differences

| Aspect | SSE | Streamable HTTP | OpenAPI |
|--------|-----|-----------------|---------|
| **Directionality** | Unidirectional (server → client) | Bidirectional (client ↔ server) | Stateless request/response |
| **Transport Class** | `SSEServerTransport` / `SSEClientTransport` | `StreamableHTTPServerTransport` / `StreamableHTTPClientTransport` | None (plain HTTP) |
| **Session Handling** | Implicit, tied to HTTP connection; auto-cleanup on close | Explicit via `mcp-session-id`; requires `DELETE` or timer cleanup | No session |
| **Primary Routes** | `/sse`, `/message` | `/mcp` (GET/POST/DELETE) | `/api`, [`/api/openapi.json`](https://github.com/metatool-ai/metamcp/blob/main//api/openapi.json), `/api/:tool` |
| **Status** | Deprecated | Current recommended transport | Always available |
| **Use Case** | Real-time streaming, progress events | Interactive RPC, multiplexed messages | Documentation, simple HTTP tool calls |

## Summary

- **SSE** provides unidirectional server pushes via `SSEServerTransport` but is deprecated; sessions automatically clean up on connection close.
- **Streamable HTTP** offers bidirectional RPC using `StreamableHTTPServerTransport` with explicit session management via the `mcp-session-id` header, requiring manual or timed cleanup.
- **OpenAPI** delivers stateless HTTP access without transport classes, generating schemas on-the-fly via `generateOpenApiSchema` and executing tools through standard REST endpoints.
- All three endpoint types share the same underlying MetaMCP server instance but differ fundamentally in session lifecycle and communication patterns.
- Authentication uses the same API-key middleware across all transports, with Streamable HTTP additionally requiring session identification headers.

## Frequently Asked Questions

### What replaced the deprecated SSE transport in MetaMCP?

**Streamable HTTP is the official replacement for SSE.** According to the deprecation notice in [`apps/backend/src/routers/mcp-proxy.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/mcp-proxy.ts) (line 747), the system logs a warning when new SSE connections are established, directing users to adopt `StreamableHTTPServerTransport` instead. Streamable HTTP provides superior bidirectional communication compared to SSE's unidirectional event streaming.

### How does session management differ between Streamable HTTP and SSE?

**SSE sessions are implicitly tied to the HTTP connection lifecycle**, automatically cleaning up when the client disconnects via the `res.on("close")` handler in [`apps/backend/src/routers/public-metamcp/sse.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/sse.ts). **Streamable HTTP uses explicit session management** where the server creates a session ID on the first POST to `/:endpoint_name/mcp`, requires the `mcp-session-id` header for subsequent requests, and persists until receiving a DELETE request or triggering the automatic cleanup timer.

### Can I use standard HTTP clients with MetaMCP without implementing MCP SDK transports?

**Yes, the OpenAPI endpoint type is designed specifically for standard HTTP clients.** Unlike SSE and Streamable HTTP which require specific transport classes (`SSEClientTransport` or `StreamableHTTPClientTransport`), OpenAPI endpoints in [`apps/backend/src/routers/public-metamcp/openapi/routes.ts`](https://github.com/metatool-ai/metamcp/blob/main/apps/backend/src/routers/public-metamcp/openapi/routes.ts) accept ordinary HTTP requests. You can fetch the schema from `/:endpoint_name/api/openapi.json` and execute tools via `POST /:endpoint_name/api/:tool_name` using any HTTP library or tool like cURL.

### Which endpoint type should I choose for real-time interactive tool calls?

**Use Streamable HTTP for real-time interactive scenarios.** While SSE supports real-time updates, it only allows server-to-client pushes and is deprecated. Streamable HTTP enables true bidirectional RPC where clients can send multiple requests and receive incremental results over the same logical session, making it ideal for web UIs and interactive applications that need to maintain conversation state across multiple tool invocations.