|
| 1 | +# MCP HTTP-Streaming Support |
| 2 | + |
| 3 | +This document describes the HTTP-Streaming transport implementation for MCP (Model Context Protocol) in PraisonAI. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +HTTP-Streaming provides bidirectional streaming communication over HTTP using chunked transfer encoding. This transport method offers advantages over SSE (Server-Sent Events) including: |
| 8 | + |
| 9 | +- **Bidirectional streaming** - Both client and server can stream data |
| 10 | +- **Binary support** - Can transmit binary data, not just text |
| 11 | +- **Lower overhead** - More efficient than SSE's text-based protocol |
| 12 | +- **Better performance** - Ideal for high-throughput scenarios |
| 13 | + |
| 14 | +## Usage |
| 15 | + |
| 16 | +### Auto-Detection (Default) |
| 17 | + |
| 18 | +The MCP client automatically detects the appropriate transport based on URL patterns: |
| 19 | + |
| 20 | +```python |
| 21 | +# SSE transport (URLs ending with /sse) |
| 22 | +agent = Agent( |
| 23 | + tools=MCP("http://localhost:8080/sse") # Uses SSE |
| 24 | +) |
| 25 | + |
| 26 | +# HTTP-Streaming transport (other HTTP URLs) |
| 27 | +agent = Agent( |
| 28 | + tools=MCP("http://localhost:8080/api") # Uses HTTP-Streaming |
| 29 | +) |
| 30 | +``` |
| 31 | + |
| 32 | +### Explicit Transport Selection |
| 33 | + |
| 34 | +You can explicitly specify the transport type: |
| 35 | + |
| 36 | +```python |
| 37 | +# Force SSE transport |
| 38 | +agent = Agent( |
| 39 | + tools=MCP("http://localhost:8080/api", transport="sse") |
| 40 | +) |
| 41 | + |
| 42 | +# Force HTTP-Streaming transport |
| 43 | +agent = Agent( |
| 44 | + tools=MCP("http://localhost:8080/sse", transport="http-streaming") |
| 45 | +) |
| 46 | +``` |
| 47 | + |
| 48 | +### TypeScript Usage |
| 49 | + |
| 50 | +The TypeScript implementation follows the same pattern: |
| 51 | + |
| 52 | +```typescript |
| 53 | +import { MCP } from '@praisonai/agents/tools'; |
| 54 | + |
| 55 | +// Auto-detection |
| 56 | +const mcpAuto = new MCP("http://localhost:8080/api"); |
| 57 | +await mcpAuto.initialize(); |
| 58 | + |
| 59 | +// Explicit transport |
| 60 | +const mcpExplicit = new MCP("http://localhost:8080/api", { |
| 61 | + transport: "http-streaming", |
| 62 | + debug: true, |
| 63 | + headers: { |
| 64 | + "Authorization": "Bearer token" |
| 65 | + } |
| 66 | +}); |
| 67 | +await mcpExplicit.initialize(); |
| 68 | +``` |
| 69 | + |
| 70 | +## Transport Detection Rules |
| 71 | + |
| 72 | +The following URL patterns automatically use SSE transport: |
| 73 | +- `/sse` (exact ending) |
| 74 | +- `/sse/` (with trailing slash) |
| 75 | +- `/events` (exact ending) |
| 76 | +- `/stream` (exact ending) |
| 77 | +- `/server-sent-events` |
| 78 | +- URLs containing `transport=sse` query parameter |
| 79 | + |
| 80 | +All other HTTP/HTTPS URLs default to HTTP-Streaming transport. |
| 81 | + |
| 82 | +## Implementation Details |
| 83 | + |
| 84 | +### Message Format |
| 85 | + |
| 86 | +HTTP-Streaming uses NDJSON (Newline Delimited JSON) format: |
| 87 | +- Each message is a complete JSON object |
| 88 | +- Messages are separated by newline characters (`\n`) |
| 89 | +- Supports efficient streaming parsing |
| 90 | + |
| 91 | +### Python Architecture |
| 92 | + |
| 93 | +``` |
| 94 | +MCP (main class) |
| 95 | +├── _detect_transport() - Auto-detection logic |
| 96 | +├── HTTPStreamingMCPClient - HTTP-Streaming implementation |
| 97 | +│ ├── HTTPStreamingTransport - Low-level transport |
| 98 | +│ ├── HTTPReadStream - Read adapter |
| 99 | +│ └── HTTPWriteStream - Write adapter |
| 100 | +└── SSEMCPClient - SSE implementation (existing) |
| 101 | +``` |
| 102 | + |
| 103 | +### TypeScript Architecture |
| 104 | + |
| 105 | +``` |
| 106 | +MCP (unified class) |
| 107 | +├── detectTransport() - Auto-detection logic |
| 108 | +├── MCPHttpStreaming - HTTP-Streaming implementation |
| 109 | +│ └── HTTPStreamingTransport - Transport layer |
| 110 | +│ ├── HTTPStreamingTransport - Modern browsers |
| 111 | +│ └── HTTPStreamingTransportFallback - Legacy browsers |
| 112 | +└── MCPSse - SSE implementation (existing) |
| 113 | +``` |
| 114 | + |
| 115 | +## Server Implementation |
| 116 | + |
| 117 | +### Python Server Example |
| 118 | + |
| 119 | +```python |
| 120 | +from fastapi import FastAPI, Request |
| 121 | +from fastapi.responses import StreamingResponse |
| 122 | +import json |
| 123 | +import asyncio |
| 124 | + |
| 125 | +app = FastAPI() |
| 126 | + |
| 127 | +@app.post("/mcp/v1/stream") |
| 128 | +async def mcp_stream(request: Request): |
| 129 | + async def generate(): |
| 130 | + async for chunk in request.stream(): |
| 131 | + # Process incoming messages |
| 132 | + message = json.loads(chunk) |
| 133 | + |
| 134 | + # Generate response |
| 135 | + response = process_mcp_message(message) |
| 136 | + yield json.dumps(response).encode() + b'\n' |
| 137 | + |
| 138 | + return StreamingResponse( |
| 139 | + generate(), |
| 140 | + media_type="application/x-ndjson" |
| 141 | + ) |
| 142 | +``` |
| 143 | + |
| 144 | +### Node.js Server Example |
| 145 | + |
| 146 | +```javascript |
| 147 | +const express = require('express'); |
| 148 | +const app = express(); |
| 149 | + |
| 150 | +app.post('/mcp/v1/stream', (req, res) => { |
| 151 | + res.writeHead(200, { |
| 152 | + 'Content-Type': 'application/x-ndjson', |
| 153 | + 'Transfer-Encoding': 'chunked' |
| 154 | + }); |
| 155 | + |
| 156 | + req.on('data', (chunk) => { |
| 157 | + const message = JSON.parse(chunk); |
| 158 | + const response = processMCPMessage(message); |
| 159 | + res.write(JSON.stringify(response) + '\n'); |
| 160 | + }); |
| 161 | + |
| 162 | + req.on('end', () => { |
| 163 | + res.end(); |
| 164 | + }); |
| 165 | +}); |
| 166 | +``` |
| 167 | + |
| 168 | +## Configuration Options |
| 169 | + |
| 170 | +### Python Options |
| 171 | + |
| 172 | +```python |
| 173 | +MCP( |
| 174 | + url, |
| 175 | + transport="http-streaming", # Explicit transport |
| 176 | + timeout=60, # Request timeout in seconds |
| 177 | + debug=True, # Enable debug logging |
| 178 | + headers={ # Custom headers |
| 179 | + "Authorization": "Bearer token" |
| 180 | + } |
| 181 | +) |
| 182 | +``` |
| 183 | + |
| 184 | +### TypeScript Options |
| 185 | + |
| 186 | +```typescript |
| 187 | +new MCP(url, { |
| 188 | + transport: "http-streaming", // Explicit transport |
| 189 | + timeout: 60000, // Timeout in milliseconds |
| 190 | + debug: true, // Enable debug logging |
| 191 | + headers: { // Custom headers |
| 192 | + "Authorization": "Bearer token" |
| 193 | + }, |
| 194 | + fallbackMode: false // Force fallback for testing |
| 195 | +}) |
| 196 | +``` |
| 197 | + |
| 198 | +## Backward Compatibility |
| 199 | + |
| 200 | +The implementation maintains 100% backward compatibility: |
| 201 | + |
| 202 | +1. **Existing SSE URLs** continue to use SSE transport |
| 203 | +2. **Stdio commands** work unchanged |
| 204 | +3. **NPX commands** work unchanged |
| 205 | +4. **All existing code** continues to function without modification |
| 206 | + |
| 207 | +## Migration Guide |
| 208 | + |
| 209 | +No migration is required! Existing code continues to work. To use HTTP-Streaming: |
| 210 | + |
| 211 | +1. **Option 1**: Use URLs that don't match SSE patterns (recommended) |
| 212 | +2. **Option 2**: Add `transport="http-streaming"` parameter |
| 213 | + |
| 214 | +## Troubleshooting |
| 215 | + |
| 216 | +### Debug Mode |
| 217 | + |
| 218 | +Enable debug logging to see transport selection: |
| 219 | + |
| 220 | +```python |
| 221 | +MCP(url, debug=True) |
| 222 | +``` |
| 223 | + |
| 224 | +### Common Issues |
| 225 | + |
| 226 | +1. **Connection Refused**: Ensure the server supports HTTP-Streaming at the endpoint |
| 227 | +2. **Transport Errors**: Check if the server implements the correct protocol |
| 228 | +3. **Browser Compatibility**: TypeScript fallback mode handles older browsers |
| 229 | + |
| 230 | +## Performance Considerations |
| 231 | + |
| 232 | +HTTP-Streaming is recommended for: |
| 233 | +- High-frequency message exchange |
| 234 | +- Large message payloads |
| 235 | +- Binary data transmission |
| 236 | +- Bidirectional communication needs |
| 237 | + |
| 238 | +SSE remains suitable for: |
| 239 | +- Simple server-to-client streaming |
| 240 | +- Text-only data |
| 241 | +- Browser compatibility requirements |
| 242 | +- Existing SSE infrastructure |
| 243 | + |
| 244 | +## Future Enhancements |
| 245 | + |
| 246 | +Potential future improvements: |
| 247 | +- WebSocket transport option |
| 248 | +- gRPC streaming support |
| 249 | +- Connection pooling |
| 250 | +- Automatic reconnection for HTTP-Streaming |
| 251 | +- Compression support |
0 commit comments