MCP Server Types: Deep Dive
Complete reference for all MCP server types supported in Claude Code plugins.
stdio (Standard Input/Output)
Overview
Execute local MCP servers as child processes with communication via stdin/stdout. Best choice for local tools, custom servers, and NPM packages.
Configuration
Basic:
{
"my-server": {
"command": "npx",
"args": ["-y", "my-mcp-server"]
}
}With environment:
{
"my-server": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/custom-server",
"args": ["--config", "${CLAUDE_PLUGIN_ROOT}/config.json"],
"env": {
"API_KEY": "${MY_API_KEY}",
"LOG_LEVEL": "debug",
"DATABASE_URL": "${DB_URL}"
}
}
}Process Lifecycle
- Startup: Claude Code spawns process with
commandandargs - Communication: JSON-RPC messages via stdin/stdout
- Lifecycle: Process runs for entire Claude Code session
- Shutdown: Process terminated when Claude Code exits
Use Cases
NPM Packages:
{
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/path"]
}
}Custom Scripts:
{
"custom": {
"command": "${CLAUDE_PLUGIN_ROOT}/servers/my-server.js",
"args": ["--verbose"]
}
}Python Servers:
{
"python-server": {
"command": "python",
"args": ["-m", "my_mcp_server"],
"env": {
"PYTHONUNBUFFERED": "1"
}
}
}Best Practices
- Use absolute paths or ${CLAUDEPLUGINROOT}
- Set PYTHONUNBUFFERED for Python servers
- Pass configuration via args or env, not stdin
- Handle server crashes gracefully
- Log to stderr, not stdout (stdout is for MCP protocol)
Troubleshooting
Server won't start:
- Check command exists and is executable
- Verify file paths are correct
- Check permissions
- Review
claude --debuglogs
Communication fails:
- Ensure server uses stdin/stdout correctly
- Check for stray print/console.log statements
- Verify JSON-RPC format
SSE (Server-Sent Events)
Overview
Connect to hosted MCP servers via HTTP with server-sent events for streaming. Best for cloud services and OAuth authentication.
Configuration
Basic:
{
"hosted-service": {
"type": "sse",
"url": "https://mcp.example.com/sse"
}
}With headers:
{
"service": {
"type": "sse",
"url": "https://mcp.example.com/sse",
"headers": {
"X-API-Version": "v1",
"X-Client-ID": "${CLIENT_ID}"
}
}
}Connection Lifecycle
- Initialization: HTTP connection established to URL
- Handshake: MCP protocol negotiation
- Streaming: Server sends events via SSE
- Requests: Client sends HTTP POST for tool calls
- Reconnection: Automatic reconnection on disconnect
Authentication
OAuth (Automatic):
{
"asana": {
"type": "sse",
"url": "https://mcp.asana.com/sse"
}
}Claude Code handles OAuth flow:
- User prompted to authenticate on first use
- Opens browser for OAuth flow
- Tokens stored securely
- Automatic token refresh
Custom Headers:
{
"service": {
"type": "sse",
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}Use Cases
Official Services:
- Asana:
https://mcp.asana.com/sse - GitHub:
https://mcp.github.com/sse - Other hosted MCP servers
Custom Hosted Servers: Deploy your own MCP server and expose via HTTPS + SSE.
Best Practices
- Always use HTTPS, never HTTP
- Let OAuth handle authentication when available
- Use environment variables for tokens
- Handle connection failures gracefully
- Document OAuth scopes required
Troubleshooting
Connection refused:
- Check URL is correct and accessible
- Verify HTTPS certificate is valid
- Check network connectivity
- Review firewall settings
OAuth fails:
- Clear cached tokens
- Check OAuth scopes
- Verify redirect URLs
- Re-authenticate
HTTP (REST API)
Overview
Connect to RESTful MCP servers via standard HTTP requests. Best for token-based auth and stateless interactions.
Configuration
Basic:
{
"api": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}With authentication:
{
"api": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_TOKEN}",
"Content-Type": "application/json",
"X-API-Version": "2024-01-01"
}
}
}Request/Response Flow
- Tool Discovery: GET to discover available tools
- Tool Invocation: POST with tool name and parameters
- Response: JSON response with results or errors
- Stateless: Each request independent
Authentication
Token-Based:
{
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}API Key:
{
"headers": {
"X-API-Key": "${API_KEY}"
}
}Custom Auth:
{
"headers": {
"X-Auth-Token": "${AUTH_TOKEN}",
"X-User-ID": "${USER_ID}"
}
}Use Cases
- REST API backends
- Internal services
- Microservices
- Serverless functions
Best Practices
- Use HTTPS for all connections
- Store tokens in environment variables
- Implement retry logic for transient failures
- Handle rate limiting
- Set appropriate timeouts
Troubleshooting
HTTP errors:
- 401: Check authentication headers
- 403: Verify permissions
- 429: Implement rate limiting
- 500: Check server logs
Timeout issues:
- Increase timeout if needed
- Check server performance
- Optimize tool implementations
WebSocket (Real-time)
Overview
Connect to MCP servers via WebSocket for real-time bidirectional communication. Best for streaming and low-latency applications.
Configuration
Basic:
{
"realtime": {
"type": "ws",
"url": "wss://mcp.example.com/ws"
}
}With authentication:
{
"realtime": {
"type": "ws",
"url": "wss://mcp.example.com/ws",
"headers": {
"Authorization": "Bearer ${TOKEN}",
"X-Client-ID": "${CLIENT_ID}"
}
}
}Connection Lifecycle
- Handshake: WebSocket upgrade request
- Connection: Persistent bidirectional channel
- Messages: JSON-RPC over WebSocket
- Heartbeat: Keep-alive messages
- Reconnection: Automatic on disconnect
Use Cases
- Real-time data streaming
- Live updates and notifications
- Collaborative editing
- Low-latency tool calls
- Push notifications from server
Best Practices
- Use WSS (secure WebSocket), never WS
- Implement heartbeat/ping-pong
- Handle reconnection logic
- Buffer messages during disconnection
- Set connection timeouts
Troubleshooting
Connection drops:
- Implement reconnection logic
- Check network stability
- Verify server supports WebSocket
- Review firewall settings
Message delivery:
- Implement message acknowledgment
- Handle out-of-order messages
- Buffer during disconnection
Comparison Matrix
| Feature | stdio | SSE | HTTP | WebSocket |
|---|---|---|---|---|
| Transport | Process | HTTP/SSE | HTTP | WebSocket |
| Direction | Bidirectional | Server→Client | Request/Response | Bidirectional |
| State | Stateful | Stateful | Stateless | Stateful |
| Auth | Env vars | OAuth/Headers | Headers | Headers |
| Use Case | Local tools | Cloud services | REST APIs | Real-time |
| Latency | Lowest | Medium | Medium | Low |
| Setup | Easy | Medium | Easy | Medium |
| Reconnect | Process respawn | Automatic | N/A | Automatic |
Choosing the Right Type
Use stdio when:
- Running local tools or custom servers
- Need lowest latency
- Working with file systems or local databases
- Distributing server with plugin
Use SSE when:
- Connecting to hosted services
- Need OAuth authentication
- Using official MCP servers (Asana, GitHub)
- Want automatic reconnection
Use HTTP when:
- Integrating with REST APIs
- Need stateless interactions
- Using token-based auth
- Simple request/response pattern
Use WebSocket when:
- Need real-time updates
- Building collaborative features
- Low-latency critical
- Bi-directional streaming required
Migration Between Types
From stdio to SSE
Before (stdio):
{
"local-server": {
"command": "node",
"args": ["server.js"]
}
}After (SSE - deploy server):
{
"hosted-server": {
"type": "sse",
"url": "https://mcp.example.com/sse"
}
}From HTTP to WebSocket
Before (HTTP):
{
"api": {
"type": "http",
"url": "https://api.example.com/mcp"
}
}After (WebSocket):
{
"realtime": {
"type": "ws",
"url": "wss://api.example.com/ws"
}
}Benefits: Real-time updates, lower latency, bi-directional communication.
Advanced Configuration
Multiple Servers
Combine different types:
{
"local-db": {
"command": "npx",
"args": ["-y", "mcp-server-sqlite", "./data.db"]
},
"cloud-api": {
"type": "sse",
"url": "https://mcp.example.com/sse"
},
"internal-service": {
"type": "http",
"url": "https://api.example.com/mcp",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}Conditional Configuration
Use environment variables to switch servers:
{
"api": {
"type": "http",
"url": "${API_URL}",
"headers": {
"Authorization": "Bearer ${API_TOKEN}"
}
}
}Set different values for dev/prod:
- Dev:
API_URL=http://localhost:8080/mcp - Prod:
API_URL=https://api.production.com/mcp
Security Considerations
Stdio Security
- Validate command paths
- Don't execute user-provided commands
- Limit environment variable access
- Restrict file system access
Network Security
- Always use HTTPS/WSS
- Validate SSL certificates
- Don't skip certificate verification
- Use secure token storage
Token Management
- Never hardcode tokens
- Use environment variables
- Rotate tokens regularly
- Implement token refresh
- Document scopes required
Conclusion
Choose the MCP server type based on your use case:
- stdio for local, custom, or NPM-packaged servers
- SSE for hosted services with OAuth
- HTTP for REST APIs with token auth
- WebSocket for real-time bidirectional communication
Test thoroughly and handle errors gracefully for robust MCP integration.