SSE vs Streamable HTTP vs OpenAPI: MetaMCP Endpoint Types Explained

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. 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, the server creates a transport instance bound directly to the HTTP response object:

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 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, 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:

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.

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:

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, 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, based on the listToolsWithMiddleware response:

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:

// 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, /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 (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. 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 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.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →