FastRMCP web transports (SSE and WebSocket) support HTTP/2 out of the box through Axum 0.7 and Hyper 1.0.
HTTP/2 provides several benefits over HTTP/1.1:
- Multiplexing: Multiple requests over a single connection
- Header Compression: Reduced bandwidth usage
- Server Push: Proactive resource delivery (when supported)
- Binary Protocol: More efficient parsing
FastRMCP's SSE and WebSocket transports automatically support both HTTP/1.1 and HTTP/2:
use fastrmcp::transport::SseTransport;
let (transport, router) = SseTransport::new();
// This server automatically supports both HTTP/1.1 and HTTP/2
let listener = tokio::net::TcpListener::bind("127.0.0.1:3000").await?;
axum::serve(listener, router).await?;Note: HTTP/2 typically requires TLS in browsers (h2), though cleartext HTTP/2 (h2c) is supported for testing.
For production use with HTTP/2, configure TLS:
Add to Cargo.toml:
[dependencies]
axum-server = { version = "0.6", features = ["tls-rustls"] }
rustls = "0.22"Example server with TLS:
use fastrmcp::transport::SseTransport;
use axum_server::tls_rustls::RustlsConfig;
use std::net::SocketAddr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Load TLS configuration
let config = RustlsConfig::from_pem_file(
"cert.pem",
"key.pem"
).await?;
let (transport, router) = SseTransport::new();
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
println!("Server listening on https://localhost:3000");
// Serve with TLS - automatically negotiates HTTP/2
axum_server::bind_rustls(addr, config)
.serve(router.into_make_service())
.await?;
Ok(())
}For development and testing:
# Generate private key
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes
# Or using mkcert (easier for local development)
mkcert -install
mkcert localhost 127.0.0.1 ::1# HTTP/2 over TLS (h2)
curl -v --http2 https://localhost:3000/mcp/sse
# HTTP/2 cleartext (h2c) - not supported by all clients
curl -v --http2-prior-knowledge http://localhost:3000/mcp/sse- Open browser DevTools (F12)
- Go to Network tab
- Look for "Protocol" column
- Should show "h2" for HTTP/2 connections
use hyper::client::conn::http2;
// Configure HTTP/2 client
let (mut sender, conn) = http2::handshake(io).await?;- Multiple Resources: Benefit from multiplexing
- Header-Heavy Requests: Compression reduces bandwidth
- Concurrent Requests: Single connection for multiple streams
- Single Request: No multiplexing benefit
- Very Simple Clients: HTTP/1.1 is simpler
- Legacy Systems: Better compatibility
WebSockets can be established over HTTP/2 connections:
use fastrmcp::transport::WebSocketTransport;
// WebSocket upgrade works over both HTTP/1.1 and HTTP/2
let transport = WebSocketTransport::new("127.0.0.1:3001")?;Note: WebSocket over HTTP/2 uses the extended CONNECT method (RFC 8441).
Configure maximum concurrent HTTP/2 streams:
use hyper::server::conn::http2;
let mut http2 = http2::Builder::new();
http2.max_concurrent_streams(100);Configure flow control window:
let mut http2 = http2::Builder::new();
http2.initial_connection_window_size(1024 * 1024); // 1 MBSolution: Ensure TLS certificate is valid and port is correct
Solution: Browsers require TLS for HTTP/2. Use HTTPS or test with curl
Solution: Server automatically falls back to HTTP/1.1
Solution: Use valid certificate or add self-signed cert to trusted store
- Production: Always use TLS with valid certificates
- Development: Use mkcert for local HTTPS testing
- Monitoring: Check protocol version in logs
- Fallback: Let server auto-negotiate (supports both HTTP/1.1 and HTTP/2)
- Testing: Test with both HTTP/1.1 and HTTP/2 clients
use fastrmcp::prelude::*;
use fastrmcp::transport::SseTransport;
use fastrmcp_macros::tool;
use axum_server::tls_rustls::RustlsConfig;
use std::net::SocketAddr;
#[tool]
async fn greet(name: String) -> Result<String> {
Ok(format!("Hello, {}!", name))
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize logging
tracing_subscriber::fmt()
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
.init();
// Load TLS configuration
let config = RustlsConfig::from_pem_file(
"cert.pem",
"key.pem"
).await?;
// Create MCP server
let (transport, router) = SseTransport::new();
let server = FastMCP::new("http2-server")
.version("1.0.0")
.description("Production HTTP/2 MCP server");
// Bind with TLS
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
tracing::info!("Server listening on https://0.0.0.0:3000");
tracing::info!("HTTP/2 enabled");
axum_server::bind_rustls(addr, config)
.serve(router.into_make_service())
.await?;
Ok(())
}