-
Notifications
You must be signed in to change notification settings - Fork 0
Transports Guide
Jeffrie Budde edited this page Nov 25, 2025
·
1 revision
FastRMCP supports STDIO, SSE, and WebSocket. Choose based on client platform and latency needs. See Troubleshooting for common pitfalls.
- 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
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/ssefor events,POST /mcp/messagefor 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 }),
});
}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/wsupgrades to WebSocket. - Connection IDs: server keeps context of current connection; server-initiated requests (notifications/requests) go to the active connection unless you include
metadata.connectionIdin 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)); }- Features: enable with
--features sse,--features websocket, or--features fullin 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.mdin 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()vsrun_with_transport.
Related: Subscriptions & Notifications for server push • Troubleshooting for connectionId errors.