Skip to content

Transports Guide

Jeffrie Budde edited this page Nov 25, 2025 · 1 revision

Transports Guide

FastRMCP supports STDIO, SSE, and WebSocket. Choose based on client platform and latency needs. See Troubleshooting for common pitfalls.

STDIO (default)

  • Use for CLI clients or editor integrations that speak MCP over stdin/stdout.
#[tokio::main]
async fn main() -> Result<()> {
    FastMCP::new("stdio-server").version("1.0.0").run().await
}
  • Feature flag: enabled by default (no extra flags).
  • Run: cargo run

SSE (Server-Sent Events)

use fastrmcp::{FastMCP, transport::{SseTransport, run_sse_server}};
use std::net::SocketAddr;

#[tokio::main]
async fn main() -> Result<()> {
    let server = FastMCP::new("sse-server").version("1.0.0");
    let (transport, router) = SseTransport::new();
    tokio::spawn(async move { run_sse_server(router, SocketAddr::from(([127,0,0,1], 3000))).await });
    server.run_with_transport(transport).await
}
  • Feature flag: --features sse (or --features full).
  • Endpoints: GET /mcp/sse for events, POST /mcp/message for client → server.
  • Connection IDs: first SSE event contains { "type":"connection", "connectionId": "<uuid>" }; include "connectionId" (or _connectionId) in every POST body so the server routes responses correctly.
  • Minimal client (curl):
curl -N http://localhost:3000/mcp/sse   # stream responses
curl -X POST http://localhost:3000/mcp/message -H 'Content-Type: application/json' \
  -d '{"connectionId":"<from-first-event>","jsonrpc":"2.0","id":1,"method":"ping","params":{}}'
  • JS client:
const es = new EventSource('http://localhost:3000/mcp/sse');
let connectionId;
es.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === 'connection') connectionId = msg.connectionId;
  console.log('recv', msg);
};
async function send(message) {
  await fetch('http://localhost:3000/mcp/message', {
    method: 'POST',
    headers: {'Content-Type':'application/json'},
    body: JSON.stringify({ connectionId, ...message }),
  });
}

WebSocket

use fastrmcp::{FastMCP, transport::{WebSocketTransport, run_websocket_server}};
use std::net::SocketAddr;

#[tokio::main]
async fn main() -> Result<()> {
    let server = FastMCP::new("ws-server").version("1.0.0");
    let (transport, router) = WebSocketTransport::new();
    tokio::spawn(async move { run_websocket_server(router, SocketAddr::from(([127,0,0,1], 3001))).await.ok(); });
    server.run_with_transport(transport).await
}
  • Feature flag: --features websocket (or --features full).
  • Endpoint: GET /mcp/ws upgrades to WebSocket.
  • Connection IDs: server keeps context of current connection; server-initiated requests (notifications/requests) go to the active connection unless you include metadata.connectionId in request params to target another connection.
  • JS client:
const ws = new WebSocket('ws://localhost:3001/mcp/ws');
ws.onopen = () => ws.send(JSON.stringify({"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"web","version":"1.0.0"}}}));
ws.onmessage = (e) => console.log('recv', JSON.parse(e.data));
function send(msg){ ws.send(JSON.stringify(msg)); }

Deployment Notes

  • Features: enable with --features sse, --features websocket, or --features full in Cargo.
  • Ports: SSE default in examples is 3000, WebSocket 3001. Pick non-conflicting ports and expose only what you need.
  • HTTP/2: SSE/WS automatically support HTTP/2 via Axum 0.7/Hyper 1.0; add TLS for production (see docs/HTTP2.md in repo).
  • CORS: examples use permissive CORS; lock down origins/methods for production (see Security).
  • One transport per FastMCP instance: choose the transport when calling run() vs run_with_transport.

Related: Subscriptions & Notifications for server push • Troubleshooting for connectionId errors.

Back to Home

Clone this wiki locally