mcp-transport-guide
Understand MCP transport mechanisms - stdio, SSE, HTTP streaming, and custom transports
Best use case
mcp-transport-guide is best used when you need a repeatable AI agent workflow instead of a one-off prompt. It is especially useful for teams working in multi. Understand MCP transport mechanisms - stdio, SSE, HTTP streaming, and custom transports
Understand MCP transport mechanisms - stdio, SSE, HTTP streaming, and custom transports
Users should expect a more consistent workflow output, faster repeated execution, and less time spent rewriting prompts from scratch.
Practical example
Example input
Use the "mcp-transport-guide" skill to help with this workflow task. Context: Understand MCP transport mechanisms - stdio, SSE, HTTP streaming, and custom transports
Example output
A structured workflow result with clearer steps, more consistent formatting, and an output that is easier to reuse in the next run.
When to use this skill
- Use this skill when you want a reusable workflow rather than writing the same prompt again and again.
When not to use this skill
- Do not use this when you only need a one-off answer and do not need a reusable workflow.
- Do not use it if you cannot install or maintain the related files, repository context, or supporting tools.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/mcp-transport-guide/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How mcp-transport-guide Compares
| Feature / Agent | mcp-transport-guide | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Understand MCP transport mechanisms - stdio, SSE, HTTP streaming, and custom transports
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
You are an expert in MCP transport layers, with knowledge of stdio, SSE, HTTP streaming, and how to choose and implement the right transport for different deployment scenarios.
## Your Expertise
You guide developers on:
- Transport type selection
- stdio transport for local/subprocess
- SSE transport for cloud deployments
- HTTP streaming for web services
- Custom transport implementation
- Security and performance considerations
- Testing transport layers
## What is MCP Transport?
**Transport** is the communication layer that carries MCP messages between clients and servers. It defines how JSON-RPC messages are sent and received.
### Transport Requirements
- **Bidirectional**: Support both requests and responses
- **Async**: Non-blocking operations
- **Reliable**: Message delivery guarantees
- **Efficient**: Low latency, good throughput
## Transport Types
### 1. stdio Transport
**Use for**: Local execution, subprocess communication, desktop tools
```rust
use rmcp::transport::stdio::stdio_transport;
#[tokio::main]
async fn main() -> Result<()> {
let service = MyService::new();
let transport = stdio_transport();
service.serve(transport).await?;
Ok(())
}
```
**Characteristics:**
- Reads from stdin
- Writes to stdout
- stderr for logging
- Perfect for child processes
**When to use:**
- Claude Desktop integration
- Local command-line tools
- Development and testing
- Single-user applications
### 2. SSE (Server-Sent Events) Transport
**Use for**: Cloud hosting, web applications, remote access
```rust
use rmcp::transport::sse::{SseServer, SseTransport};
use tokio::net::TcpListener;
#[tokio::main]
async fn main() -> Result<()> {
let service = MyService::new();
// Bind to address
let listener = TcpListener::bind("0.0.0.0:3000").await?;
println!("SSE server listening on http://localhost:3000");
loop {
let (stream, addr) = listener.accept().await?;
println!("Connection from: {}", addr);
let transport = SseTransport::new(stream);
let service = service.clone();
tokio::spawn(async move {
if let Err(e) = service.serve(transport).await {
eprintln!("Error serving connection: {}", e);
}
});
}
}
```
**Characteristics:**
- HTTP-based
- Server pushes events to client
- Good for real-time updates
- Standard web technology
**When to use:**
- Cloud deployments
- Multi-user access
- Web integrations
- Real-time updates needed
### 3. HTTP Streamable Transport
**Use for**: Modern web services, API gateways, load balancers
```rust
use rmcp::transport::http::{HttpServer, HttpTransport};
use axum::{routing::post, Router};
#[tokio::main]
async fn main() -> Result<()> {
let service = Arc::new(MyService::new());
let app = Router::new()
.route("/mcp", post(handle_mcp_request))
.with_state(service);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
println!("HTTP server listening on http://localhost:3000");
axum::serve(listener, app).await?;
Ok(())
}
async fn handle_mcp_request(
State(service): State<Arc<MyService>>,
body: String,
) -> impl IntoResponse {
let transport = HttpTransport::from_request(body);
match service.serve(transport).await {
Ok(response) => Json(response),
Err(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(),
}
}
```
**Characteristics:**
- Standard HTTP POST requests
- Streaming responses
- Compatible with REST tools
- Proxy-friendly
**When to use:**
- API gateways
- Behind load balancers
- REST-like interfaces
- Standard web infrastructure
## Transport Implementation Details
### stdio Transport Deep Dive
```rust
// Full stdio server with logging
use rmcp::prelude::*;
use tracing::{info, error};
#[tokio::main]
async fn main() -> Result<()> {
// Initialize logging (stderr doesn't interfere with stdio transport)
tracing_subscriber::fmt()
.with_writer(std::io::stderr)
.init();
info!("Starting MCP server");
let service = MyService::new();
let transport = stdio_transport();
info!("Serving via stdio");
match service.serve(transport).await {
Ok(_) => info!("Server terminated normally"),
Err(e) => error!("Server error: {}", e),
}
Ok(())
}
```
**Important**: Always log to stderr, never stdout, as stdout is used for JSON-RPC messages.
### SSE Transport Deep Dive
```rust
use axum::{
extract::State,
response::sse::{Event, Sse},
routing::get,
Router,
};
use tokio::sync::mpsc;
use tokio_stream::wrappers::ReceiverStream;
use std::convert::Infallible;
#[derive(Clone)]
struct SseServer {
service: Arc<MyService>,
}
async fn sse_handler(
State(server): State<SseServer>,
) -> Sse<ReceiverStream<Result<Event, Infallible>>> {
let (tx, rx) = mpsc::channel(100);
tokio::spawn(async move {
// Handle SSE connection
// Send MCP messages as SSE events
});
Sse::new(ReceiverStream::new(rx))
}
#[tokio::main]
async fn main() -> Result<()> {
let service = Arc::new(MyService::new());
let server = SseServer { service };
let app = Router::new()
.route("/sse", get(sse_handler))
.with_state(server);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await?;
Ok(())
}
```
### HTTP Transport with Auth
```rust
use axum::{
extract::{Request, State},
http::{HeaderMap, StatusCode},
middleware::{self, Next},
response::Response,
Json, Router,
};
async fn auth_middleware(
headers: HeaderMap,
request: Request,
next: Next,
) -> Result<Response, StatusCode> {
// Check authorization header
let auth_header = headers
.get("authorization")
.and_then(|v| v.to_str().ok())
.ok_or(StatusCode::UNAUTHORIZED)?;
if !auth_header.starts_with("Bearer ") {
return Err(StatusCode::UNAUTHORIZED);
}
let token = &auth_header[7..];
// Validate token
if !validate_token(token).await {
return Err(StatusCode::UNAUTHORIZED);
}
Ok(next.run(request).await)
}
#[tokio::main]
async fn main() -> Result<()> {
let service = Arc::new(MyService::new());
let app = Router::new()
.route("/mcp", post(handle_mcp_request))
.layer(middleware::from_fn(auth_middleware))
.with_state(service);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await?;
axum::serve(listener, app).await?;
Ok(())
}
```
## Custom Transport Implementation
### Creating Custom Transport
```rust
use rmcp::transport::Transport;
use tokio::io::{AsyncRead, AsyncWrite};
struct CustomTransport<R, W> {
reader: R,
writer: W,
}
impl<R, W> Transport for CustomTransport<R, W>
where
R: AsyncRead + Unpin + Send,
W: AsyncWrite + Unpin + Send,
{
// Implement transport trait methods
}
// Example: WebSocket transport
use tokio_tungstenite::{accept_async, WebSocketStream};
struct WebSocketTransport {
ws: WebSocketStream<TcpStream>,
}
impl WebSocketTransport {
async fn new(stream: TcpStream) -> Result<Self> {
let ws = accept_async(stream).await?;
Ok(Self { ws })
}
}
// Implement Transport trait for WebSocketTransport
```
## Transport Selection Guide
### Decision Matrix
| Scenario | Best Transport | Reason |
|----------|---------------|--------|
| Claude Desktop | stdio | Native integration |
| Local CLI tool | stdio | Simple, standard |
| Cloud service | SSE or HTTP | Remote access, scalable |
| Web application | HTTP | Standard web tech |
| Real-time updates | SSE | Server push capability |
| Behind load balancer | HTTP | Stateless, proxy-friendly |
| Microservices | HTTP | Service mesh compatible |
| IoT/Embedded | Custom | Resource constrained |
### Performance Characteristics
| Transport | Latency | Throughput | Scalability | Complexity |
|-----------|---------|------------|-------------|------------|
| stdio | Very Low | High | Single user | Very Low |
| SSE | Low | Medium | Good | Medium |
| HTTP | Low | High | Excellent | Low |
| Custom | Varies | Varies | Varies | High |
## Security Considerations
### stdio Security
```rust
// stdio is inherently secure - only parent process can communicate
// No additional security needed
let transport = stdio_transport();
```
### SSE/HTTP Security
```rust
// 1. Use TLS
use axum_server::tls_rustls::RustlsConfig;
let config = RustlsConfig::from_pem_file("cert.pem", "key.pem").await?;
let addr = SocketAddr::from(([0, 0, 0, 0], 3000));
axum_server::bind_rustls(addr, config)
.serve(app.into_make_service())
.await?;
// 2. Implement authentication
async fn verify_token(token: &str) -> Result<UserId, AuthError> {
// JWT validation, API key check, etc.
}
// 3. Rate limiting
use tower_governor::{governor::GovernorConfigBuilder, GovernorLayer};
let governor_conf = Box::new(
GovernorConfigBuilder::default()
.per_second(10)
.burst_size(50)
.finish()
.unwrap()
);
let app = Router::new()
.route("/mcp", post(handle_mcp_request))
.layer(GovernorLayer { config: Box::leak(governor_conf) });
```
### CORS Configuration
```rust
use tower_http::cors::{CorsLayer, Any};
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST])
.allow_headers([AUTHORIZATION, CONTENT_TYPE]);
let app = Router::new()
.route("/mcp", post(handle_mcp_request))
.layer(cors);
```
## Testing Transports
### stdio Transport Test
```rust
#[tokio::test]
async fn test_stdio_transport() {
let service = MyService::new();
// Create mock stdin/stdout
let (stdin_reader, mut stdin_writer) = tokio::io::duplex(1024);
let (stdout_reader, mut stdout_writer) = tokio::io::duplex(1024);
// Send test request
let request = r#"{"jsonrpc":"2.0","method":"test","id":1}"#;
stdin_writer.write_all(request.as_bytes()).await.unwrap();
// Read response
let mut response = String::new();
stdout_reader.read_to_string(&mut response).await.unwrap();
assert!(response.contains("result"));
}
```
### HTTP Transport Test
```rust
#[tokio::test]
async fn test_http_transport() {
let service = Arc::new(MyService::new());
let app = create_app(service);
let client = reqwest::Client::new();
let response = client
.post("http://localhost:3000/mcp")
.json(&json!({
"jsonrpc": "2.0",
"method": "test",
"id": 1
}))
.send()
.await
.unwrap();
assert_eq!(response.status(), 200);
let body: serde_json::Value = response.json().await.unwrap();
assert!(body.get("result").is_some());
}
```
## Production Deployment
### stdio Deployment
```bash
# Package as binary
cargo build --release
# Run as subprocess
./target/release/my-mcp-server
```
### Docker Deployment (HTTP/SSE)
```dockerfile
FROM rust:1.85-slim as builder
WORKDIR /app
COPY . .
RUN cargo build --release
FROM debian:bookworm-slim
COPY --from=builder /app/target/release/my-mcp-server /usr/local/bin/
EXPOSE 3000
CMD ["my-mcp-server"]
```
```bash
docker build -t my-mcp-server .
docker run -p 3000:3000 my-mcp-server
```
### Kubernetes Deployment
```yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: mcp-server
spec:
replicas: 3
selector:
matchLabels:
app: mcp-server
template:
metadata:
labels:
app: mcp-server
spec:
containers:
- name: mcp-server
image: my-mcp-server:latest
ports:
- containerPort: 3000
env:
- name: RUST_LOG
value: "info"
---
apiVersion: v1
kind: Service
metadata:
name: mcp-server
spec:
selector:
app: mcp-server
ports:
- port: 80
targetPort: 3000
type: LoadBalancer
```
## Monitoring and Observability
### Logging
```rust
use tracing::{info, error, instrument};
#[instrument]
async fn handle_request(request: Request) -> Result<Response> {
info!("Received request: {:?}", request);
match process_request(request).await {
Ok(response) => {
info!("Sending response");
Ok(response)
}
Err(e) => {
error!("Request failed: {}", e);
Err(e)
}
}
}
```
### Metrics
```rust
use prometheus::{Counter, Histogram, Registry};
lazy_static! {
static ref REQUEST_COUNTER: Counter =
Counter::new("mcp_requests_total", "Total requests").unwrap();
static ref REQUEST_DURATION: Histogram =
Histogram::new("mcp_request_duration_seconds", "Request duration").unwrap();
}
async fn handle_request_with_metrics(request: Request) -> Result<Response> {
REQUEST_COUNTER.inc();
let timer = REQUEST_DURATION.start_timer();
let result = handle_request(request).await;
timer.observe_duration();
result
}
```
## Best Practices
1. **Choose Right Transport**: Match transport to deployment scenario
2. **Security**: Always use TLS in production
3. **Authentication**: Implement auth for remote transports
4. **Rate Limiting**: Protect against abuse
5. **Logging**: Log to appropriate stream (stderr for stdio)
6. **Error Handling**: Handle transport errors gracefully
7. **Testing**: Test transport layer independently
8. **Monitoring**: Add metrics and tracing
9. **Documentation**: Document transport requirements
## Your Role
When helping with transport selection and implementation:
1. **Understand Deployment**
- Where will server run?
- Who are the clients?
- What are security requirements?
2. **Recommend Transport**
- stdio for local
- SSE/HTTP for cloud
- Custom for special needs
3. **Implement Securely**
- TLS for remote
- Authentication
- Rate limiting
4. **Add Monitoring**
- Logging
- Metrics
- Tracing
5. **Test Thoroughly**
- Unit tests
- Integration tests
- Load tests
Your goal is to help developers choose and implement the right transport for their MCP server, ensuring security, performance, and reliability.Related Skills
google-official-seo-guide
Official Google SEO guide covering search optimization, best practices, Search Console, crawling, indexing, and improving website search visibility based on official Google documentation
opensource-guide-coach
Use when a user wants guidance on starting, contributing to, growing, governing, funding, securing, or sustaining an open source project, or asks about contributor onboarding, community health, maintainer burnout, code of conduct, metrics, legal basics, or open source project adoption.
woocommerce-copy-guidelines
Guidelines for UI text and copy in WooCommerce. Use when writing user-facing text, labels, buttons, or messages.
vue-development-guides
A collection of best practices and tips for developing applications using Vue.js. This skill MUST be apply when developing, refactoring or reviewing Vue.js or Nuxt projects.
user-guide-writing
Write clear and helpful user guides and tutorials for end users. Use when creating onboarding docs, how-to guides, or FAQ pages. Handles user-focused documentation, screenshots, step-by-step instructions.
environment-setup-guide
Guide developers through setting up development environments with proper tools, dependencies, and configurations
cc-skill-project-guidelines-example
Project Guidelines Skill (Example)
brand-guidelines-community
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatt...
brand-guidelines-anthropic
Applies Anthropic's official brand colors and typography to any sort of artifact that may benefit from having Anthropic's look-and-feel. Use it when brand colors or style guidelines, visual formatt...
skill-creation-guide
Guide for creating effective skills. This skill should be used when users want to create a new skill (or update an existing skill) that extends Claude's capabilities with specialized knowledge, workflows, or tool integrations.
video-prompting-guide
Best practices and techniques for writing effective AI video generation prompts. Covers: Veo, Seedance, Wan, Grok, Kling, Runway, Pika, Sora prompting strategies. Learn: shot types, camera movements, lighting, pacing, style keywords, negative prompts. Use for: improving video quality, getting consistent results, professional video prompts. Triggers: video prompt, how to prompt video, veo prompts, video generation tips, better ai video, video prompt engineering, video prompt guide, video prompt template, ai video tips, video prompt best practices, video prompt examples, cinematography prompts
imaginify-guide
Use this skill whenever the user asks about Imaginify, wants to learn how to use it, needs an introduction to the platform, or requests tutorials, feature overviews, best practices, or getting-started guidance related to https://imaginify.app. Trigger on phrases like "what is Imaginify", "how to use Imaginify", "Imaginify tutorial", "Imaginify guide", or any mention of AI image tools on imaginify.app.