maxyychen/mcp-fetch
If you are the rightful owner of mcp-fetch and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to dayong@mcphub.com.
The MCP HTTP Fetch Server is a robust and secure server designed to fetch data from HTTP/HTTPS APIs using the Model Context Protocol (MCP) with streamable HTTP transport.
MCP HTTP Fetch Server
A Model Context Protocol (MCP) server with Streamable HTTP transport for fetching data from HTTP/HTTPS APIs with comprehensive security controls.
Features
- ✅ MCP Streamable HTTP - Full MCP specification compliance (2024-11-05)
- ✅ JSON-RPC 2.0 - Complete JSON-RPC protocol implementation
- ✅ Stateful Sessions - Session management with automatic cleanup
- ✅ SSE Support - Server-Sent Events for bidirectional communication
- ✅ SSRF Protection - Blocks private IPs, localhost, and link-local addresses
- ✅ Rate Limiting - Per-session rate limiting to prevent abuse
- ✅ Security First - URL validation, header sanitization, size limits
- ✅ Docker Ready - Multi-stage build, production-optimized
- ✅ Type Safe - Full Python type hints and Pydantic models
Quick Start
Option 1: Local Development
# Create virtual environment
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
# Run server
uvicorn src.server:app --reload --port 8080
Option 2: Docker Compose (Recommended)
# Start services
docker compose up -d
# View logs
docker compose logs -f
# Stop services
docker compose down
Option 3: Docker
# Build image
docker build -t mcp-http-fetch:latest .
# Run container
docker run -d -p 8080:8080 \
-v $(pwd)/config:/app/config:ro \
-v $(pwd)/logs:/app/logs \
--name mcp-fetch \
mcp-http-fetch:latest
Testing the Server
1. Health Check
curl http://localhost:8080/health
2. Initialize MCP Session
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2024-11-05",
"capabilities": {},
"clientInfo": {"name": "curl-client", "version": "1.0"}
}
}'
Response:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"protocolVersion": "2024-11-05",
"capabilities": {
"tools": {"listChanged": false},
"logging": {}
},
"serverInfo": {
"name": "mcp-http-fetch-server",
"version": "1.0.0"
}
}
}
Important: Save the Mcp-Session-Id from response headers!
3. List Available Tools
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID_HERE" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/list",
"params": {}
}'
4. Fetch HTTP API (GET Request)
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID_HERE" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "http_fetch",
"arguments": {
"url": "https://api.github.com/users/octocat",
"method": "GET",
"headers": {
"Accept": "application/json"
}
}
}
}'
5. Fetch HTTP API (POST Request with Body)
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID_HERE" \
-d '{
"jsonrpc": "2.0",
"id": 4,
"method": "tools/call",
"params": {
"name": "http_fetch",
"arguments": {
"url": "https://httpbin.org/post",
"method": "POST",
"headers": {
"Content-Type": "application/json"
},
"body": {
"name": "test",
"value": 123
}
}
}
}'
6. Open SSE Stream
# Open SSE stream for server notifications
curl -N http://localhost:8080/mcp \
-H "Mcp-Session-Id: YOUR_SESSION_ID_HERE"
HTTP Fetch Tool
Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | - | Target URL (HTTP/HTTPS only) |
method | string | No | GET | HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS) |
headers | object | No | {} | HTTP headers as key-value pairs |
body | string/object | No | null | Request body (string or JSON object) |
timeout | number | No | 30 | Request timeout in seconds |
follow_redirects | boolean | No | true | Whether to follow HTTP redirects |
Response Format
{
"status_code": 200,
"headers": {
"content-type": "application/json",
"content-length": "1234"
},
"body": "response content",
"content_type": "application/json",
"is_binary": false,
"size_bytes": 1234,
"elapsed_ms": 123.45,
"url": "https://final.url.after.redirects/"
}
Security Features
SSRF Protection
The server blocks requests to:
- Private IP ranges (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16)
- Localhost (127.0.0.0/8)
- Link-local addresses (169.254.0.0/16) - AWS metadata endpoint
- Reserved and multicast IPs
URL Validation
- Only HTTP and HTTPS schemes allowed
- DNS resolution before request
- Domain allowlist/blocklist support
- Redirect validation
Rate Limiting
- Per-session rate limiting (default: 60 requests/minute)
- Configurable limits via environment variables
- Token bucket algorithm
Header Sanitization
- Dangerous headers blocked (Host, Connection, etc.)
- Only safe headers allowed
- Header value validation
Response Handling
- Maximum response size (default: 10MB)
- Binary content detection
- Sensitive header filtering (Authorization, Cookie)
Configuration
Environment Variables
Create a .env file (see .env.example):
# Server
HOST=0.0.0.0
PORT=8080
LOG_LEVEL=INFO
# HTTP Fetch
HTTP_TIMEOUT=30
HTTP_MAX_REDIRECTS=5
HTTP_MAX_RESPONSE_SIZE=10485760
HTTP_USER_AGENT=MCP-HTTP-Fetch/1.0
HTTP_FOLLOW_REDIRECTS=true
# Security
SECURITY_BLOCK_PRIVATE_IPS=true
ALLOWED_DOMAINS=api.github.com,httpbin.org
BLOCKED_DOMAINS=malicious.com
RATE_LIMIT_PER_MINUTE=60
# Session
SESSION_TIMEOUT_MINUTES=30
YAML Configuration
Edit config/config.yaml:
server:
host: "0.0.0.0"
port: 8080
log_level: "INFO"
http_fetch:
timeout: 30
max_redirects: 5
max_response_size: 10485760
security:
block_private_ips: true
allowed_domains: []
blocked_domains: []
rate_limit_per_minute: 60
Project Structure
mcp-fetch/
├── src/
│ ├── server.py # FastAPI application
│ ├── mcp_handler.py # Tool registration and execution
│ ├── mcp_transport.py # MCP Streamable HTTP transport
│ ├── mcp_session.py # Session management
│ ├── jsonrpc/
│ │ ├── models.py # JSON-RPC models
│ │ └── handler.py # JSON-RPC handler
│ ├── tools/
│ │ └── http_fetch.py # HTTP fetch tool
│ └── utils/
│ ├── errors.py # Custom exceptions
│ ├── validation.py # Input validation
│ └── security.py # SSRF protection
├── config/
│ └── config.yaml # Configuration
├── tests/ # Test suite (future)
├── logs/ # Application logs
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.md
API Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /mcp | MCP requests with session management |
| GET | /mcp | Open SSE stream for server notifications |
| GET | /health | Health check |
| GET | / | Service information |
MCP Protocol Flow
1. Client → POST /mcp (initialize)
Server → Returns session ID in Mcp-Session-Id header
2. Client → GET /mcp (with session ID)
Server → Opens SSE stream
3. Client → POST /mcp (tools/list, with session ID)
Server → Returns available tools
4. Client → POST /mcp (tools/call http_fetch, with session ID)
Server → Executes HTTP request, returns result
5. Client → POST /mcp (ping, with session ID)
Server → Keepalive response
Development
Install Development Dependencies
pip install -r requirements.txt
Run Tests
pytest tests/ -v
Code Formatting
black src/
ruff check src/
mypy src/
Example Use Cases
1. Fetch JSON API
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "http_fetch",
"arguments": {
"url": "https://api.github.com/repos/python/cpython",
"method": "GET"
}
}
}'
2. POST JSON Data
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "http_fetch",
"arguments": {
"url": "https://httpbin.org/post",
"method": "POST",
"body": {"key": "value"}
}
}
}'
3. Custom Headers
curl -X POST http://localhost:8080/mcp \
-H "Content-Type: application/json" \
-H "Mcp-Session-Id: YOUR_SESSION_ID" \
-d '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "http_fetch",
"arguments": {
"url": "https://api.github.com/user",
"method": "GET",
"headers": {
"Authorization": "Bearer YOUR_TOKEN",
"Accept": "application/vnd.github.v3+json"
}
}
}
}'
Error Handling
The server returns standard JSON-RPC error responses:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32004,
"message": "Cannot fetch from private IP: example.local resolves to 192.168.1.1",
"data": null
}
}
Error Codes
| Code | Description |
|---|---|
| -32700 | Parse error |
| -32600 | Invalid request |
| -32601 | Method not found |
| -32602 | Invalid params |
| -32603 | Internal error |
| -32001 | Tool not found |
| -32002 | Tool execution error |
| -32003 | HTTP fetch error |
| -32004 | Security error |
| -32005 | Rate limit error |
Troubleshooting
SSRF Protection Blocking Valid Requests
If you need to fetch from internal services (e.g., in development):
# Disable SSRF protection (NOT recommended for production)
export SECURITY_BLOCK_PRIVATE_IPS=false
Rate Limit Issues
Increase rate limit:
export RATE_LIMIT_PER_MINUTE=120
Connection Issues
Check logs:
# Docker
docker compose logs -f
# Local
tail -f logs/server.log
License
MIT License
Contributing
- Fork the repository
- Create a feature branch
- Commit your changes
- Push to the branch
- Create a Pull Request
References
Support
For issues and questions, please open an issue on GitHub.