MCP Server Guide¶
ProxyWhirl provides a Model Context Protocol (MCP) server that enables AI assistants to manage proxies programmatically. This guide covers installation, configuration, the unified tool interface, resources, prompts, and integration patterns.
Overview¶
The MCP server exposes ProxyWhirl’s proxy management capabilities through a standardized protocol that AI assistants can use. It provides:
Unified Tool: A single
proxywhirltool with action-based operationsResources: Real-time proxy pool health and configuration data
Prompts: Guided workflows for proxy selection and troubleshooting
Note
The MCP server requires Python 3.10 or higher due to FastMCP dependencies.
Quick Start¶
Installation¶
# Install ProxyWhirl with MCP support
pip install "proxywhirl[mcp]"
# Or with uv
uv pip install "proxywhirl[mcp]"
Running the Server¶
# Run the MCP server with stdio transport (default)
proxywhirl-mcp
# With uvx (no install required)
uvx "proxywhirl[mcp]" proxywhirl-mcp
# Specify transport type
proxywhirl-mcp --transport http
proxywhirl-mcp --transport sse
proxywhirl-mcp --transport streamable-http
# Or use the Python module directly
python -m proxywhirl.mcp.server
Auto-Loading Proxies¶
The MCP server automatically loads proxies from proxywhirl.db if it exists in the current directory (or the path set by PROXYWHIRL_MCP_DB). Use the CLI Reference to populate the database first:
# Fetch proxies and save to database
proxywhirl fetch
# Then run MCP server (proxies load automatically)
proxywhirl-mcp
Note
Auto-fetch fallback: If the database does not exist or is empty after loading, the MCP server will automatically fetch proxies from public sources (up to 100 proxies) to ensure the pool is not empty on startup. This cold-start behavior means the server is usable even without pre-populating the database.
CLI Options¶
proxywhirl-mcp [OPTIONS]
Options:
--transport {stdio,http,sse,streamable-http} Transport type (default: stdio)
--api-key API_KEY API key for authentication
--db DB Path to proxy database file (default: proxywhirl.db)
--log-level {debug,info,warning,error} Log level (default: info)
Environment Variables:
PROXYWHIRL_MCP_API_KEY API key for authentication
PROXYWHIRL_MCP_DB Path to proxy database file
PROXYWHIRL_MCP_LOG_LEVEL Log level
The proxywhirl Tool¶
The MCP server exposes a single unified tool called proxywhirl that handles all proxy management operations through an action parameter.
Available Actions¶
Action |
Description |
Required Parameters |
Optional Parameters |
|---|---|---|---|
|
List all proxies in the pool |
- |
|
|
Get next proxy using rotation strategy |
- |
|
|
Get detailed status for a specific proxy |
|
|
|
Get best proxy based on criteria |
- |
|
|
Get pool health overview |
- |
|
|
Reset circuit breaker for a proxy |
|
|
|
Add a new proxy to the pool |
|
|
|
Remove a proxy from the pool |
|
|
|
Fetch proxies from public sources |
- |
|
|
Validate proxy connectivity |
- |
|
|
Change rotation strategy |
|
|
Action Examples¶
List All Proxies¶
{
"action": "list"
}
Response:
{
"proxies": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://proxy1.example.com:8080",
"status": "healthy",
"success_rate": 0.95,
"avg_latency_ms": 120.5,
"region": "US",
"total_requests": 150,
"total_successes": 142,
"total_failures": 8
}
],
"total": 1,
"healthy": 1,
"degraded": 0,
"unhealthy": 0,
"dead": 0,
"unknown": 0
}
Rotate to Next Proxy¶
{
"action": "rotate"
}
Response:
{
"proxy": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://proxy1.example.com:8080",
"status": "healthy",
"success_rate": 0.95,
"avg_latency_ms": 120.5,
"region": "US"
}
}
Get Proxy Status¶
{
"action": "status",
"proxy_id": "550e8400-e29b-41d4-a716-446655440000"
}
Response:
{
"proxy_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://proxy1.example.com:8080",
"status": "healthy",
"metrics": {
"success_rate": 0.95,
"avg_latency_ms": 120.5,
"total_requests": 150,
"successful_requests": 142,
"failed_requests": 8,
"ema_response_time_ms": 115.3
},
"health": {
"last_check": "2024-01-15T10:30:00Z",
"last_success": "2024-01-15T10:29:55Z",
"last_failure": "2024-01-15T09:15:00Z",
"circuit_breaker": "closed",
"consecutive_failures": 0,
"consecutive_successes": 25
},
"region": "US",
"protocol": "http"
}
Get Proxy Recommendation¶
{
"action": "recommend",
"criteria": {
"region": "US",
"performance": "high"
}
}
Response:
{
"recommendation": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://proxy1.example.com:8080",
"score": 0.92,
"reason": "Best high performance proxy in US region with high reliability",
"metrics": {
"success_rate": 0.95,
"avg_latency_ms": 85.2,
"region": "US",
"performance_tier": "high",
"total_requests": 500
},
"alternatives": [
{
"id": "660e8400-e29b-41d4-a716-446655440001",
"url": "http://proxy2.example.com:8080",
"score": 0.88,
"reason": "Alternative with 92.0% success rate"
}
]
}
}
The criteria parameter supports:
region: Country code filter (e.g., “US”, “DE”, “JP”)performance: Performance tier ("high","medium","low")
Check Pool Health¶
{
"action": "health"
}
Response:
{
"pool_status": "healthy",
"total_proxies": 10,
"healthy_proxies": 8,
"degraded_proxies": 1,
"failed_proxies": 1,
"average_success_rate": 0.89,
"average_latency_ms": 145.3,
"last_update": "2024-01-15T10:30:00Z",
"total_requests": 5000,
"total_successes": 4450,
"total_failures": 550,
"rate_limit": {
"enabled": false,
"message": "Rate limiting not configured"
}
}
Note
Pool status values match those in the ProxyWhirl REST API Usage Guide /api/v1/health endpoint:
empty: No proxies in poolhealthy: 70%+ proxies are healthydegraded: 30-70% proxies are healthycritical: Less than 30% proxies are healthy
Reset Circuit Breaker¶
{
"action": "reset_cb",
"proxy_id": "550e8400-e29b-41d4-a716-446655440000"
}
Response:
{
"success": true,
"proxy_id": "550e8400-e29b-41d4-a716-446655440000",
"previous_state": "open",
"new_state": "closed",
"message": "Circuit breaker reset successfully for proxy 550e8400-e29b-41d4-a716-446655440000"
}
Add Proxy¶
{
"action": "add",
"proxy_url": "http://newproxy.example.com:8080"
}
Response:
{
"success": true,
"proxy": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"url": "http://newproxy.example.com:8080",
"protocol": "http",
"status": "unknown"
},
"pool_size": 11
}
Remove Proxy¶
{
"action": "remove",
"proxy_id": "550e8400-e29b-41d4-a716-446655440000"
}
Response:
{
"success": true,
"proxy_id": "550e8400-e29b-41d4-a716-446655440000",
"message": "Proxy 550e8400-e29b-41d4-a716-446655440000 removed successfully",
"pool_size": 9
}
Fetch Proxies¶
{
"action": "fetch",
"criteria": {"max_proxies": 50}
}
Response:
{
"success": true,
"fetched": 50,
"pool_size": 60,
"message": "Fetched 50 proxies from public sources"
}
Validate Proxies¶
{
"action": "validate",
"proxy_id": "550e8400-e29b-41d4-a716-446655440000"
}
Response:
{
"validated": 1,
"valid": 1,
"invalid": 0,
"results": [
{
"proxy_id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://proxy1.example.com:8080",
"valid": true,
"latency_ms": 120.5,
"status_code": 200
}
],
"message": "Validated 1 proxies: 1 valid, 0 invalid"
}
Omit proxy_id to validate all proxies in the pool.
Note
When validating all proxies, the results array in the response is truncated to the first 10 entries to limit response size. The validated, valid, and invalid counts still reflect all proxies tested.
Set Strategy¶
{
"action": "set_strategy",
"strategy": "performance-based"
}
Response:
{
"success": true,
"previous_strategy": "RoundRobinStrategy",
"new_strategy": "PerformanceBasedStrategy",
"message": "Strategy changed from RoundRobinStrategy to PerformanceBasedStrategy"
}
Valid strategies: round-robin, random, weighted, least-used, performance-based, session, geo-targeted. For detailed strategy configuration and tuning, see Advanced Rotation Strategies.
Resources¶
The MCP server exposes two resources that AI assistants can read for real-time data.
resource://proxywhirl/health¶
Returns real-time pool health data as JSON. This resource provides the same data as the health action but is accessible as a resource that can be subscribed to.
{
"pool_status": "healthy",
"total_proxies": 10,
"healthy_proxies": 8,
"degraded_proxies": 1,
"failed_proxies": 1,
"average_success_rate": 0.89,
"average_latency_ms": 145.3,
"last_update": "2024-01-15T10:30:00Z",
"total_requests": 5000,
"total_successes": 4450,
"total_failures": 550,
"rate_limit": {
"enabled": false,
"message": "Rate limiting not configured"
}
}
resource://proxywhirl/config¶
Returns current configuration settings as JSON.
{
"rotation_strategy": "RoundRobinStrategy",
"timeout": 30.0,
"verify_ssl": true,
"follow_redirects": true,
"pool_connections": 10,
"pool_max_keepalive": 20,
"circuit_breaker": {
"failure_threshold": 5,
"timeout_duration": 60,
"window_duration": 120
},
"retry_policy": {
"max_attempts": 3,
"backoff_strategy": "exponential",
"base_delay": 1.0,
"max_backoff_delay": 60.0,
"multiplier": 2.0
},
"logging": {
"level": "INFO",
"format": "json",
"redact_credentials": true
}
}
Prompts¶
The MCP server provides two guided workflow prompts for AI assistants.
proxy_selection_workflow¶
A step-by-step workflow for selecting the optimal proxy for a request:
Assess Requirements: Determine target geography and performance needs
Check Pool Health: Verify pool status before selection
Get Recommendation: Use criteria-based recommendation
Verify Selected Proxy: Check circuit breaker and metrics
Use or Rotate: Execute request or switch proxies if issues arise
troubleshooting_workflow¶
A diagnostic workflow for debugging proxy issues:
Diagnose Pool Health: Check overall pool status
Check Specific Proxy: Examine individual proxy metrics
Circuit Breaker Issues: Reset breakers if needed
Find Alternative: Get fresh recommendations
Rotate Away: Switch to different proxy
Authentication¶
Authentication is optional. When not configured, all requests are allowed. The MCP server uses FastMCP v2 middleware for authentication.
Enabling Authentication¶
from proxywhirl.mcp.server import set_auth
from proxywhirl.mcp.auth import MCPAuth
# Enable authentication with API key
auth = MCPAuth(api_key="your-secret-api-key")
set_auth(auth)
Authenticated Tool Calls¶
When authentication is enabled, include api_key in tool calls:
{
"action": "list",
"api_key": "your-secret-api-key"
}
Auth Middleware¶
The server uses FastMCP v2’s middleware system to validate API keys on every tool call:
# Middleware is automatically registered with the MCP server
# It validates api_key from tool arguments or context
Disabling Authentication¶
from proxywhirl.mcp.server import set_auth
# Disable authentication
set_auth(None)
Warning
Store API keys securely using environment variables or a secrets manager. Never hardcode keys in source code. See Deployment Security & Reverse Proxy Configuration for production security best practices and Configuration Reference for all environment variables.
Progress Reporting¶
Long-running operations (fetch, validate) report progress via FastMCP v2’s context:
# Progress is automatically reported for:
# - fetch: Reports progress as proxies are fetched from sources
# - validate: Reports progress as each proxy is validated
# AI assistants can display this progress to users
Transport Options¶
The MCP server supports multiple transport protocols:
from proxywhirl.mcp import ProxyWhirlMCPServer
server = ProxyWhirlMCPServer()
# stdio transport (default) - for CLI integration
server.run(transport="stdio")
# HTTP transport - for REST-like access
server.run(transport="http")
# SSE transport - for server-sent events
server.run(transport="sse")
# Streamable HTTP - for streaming responses
server.run(transport="streamable-http")
Integration with Claude Desktop¶
Add ProxyWhirl to your Claude Desktop configuration:
macOS¶
Edit ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"proxywhirl": {
"command": "proxywhirl-mcp"
}
}
}
Windows¶
Edit %APPDATA%\Claude\claude_desktop_config.json:
{
"mcpServers": {
"proxywhirl": {
"command": "proxywhirl-mcp"
}
}
}
With uvx (Recommended)¶
Use uvx to run without a global install:
{
"mcpServers": {
"proxywhirl": {
"command": "uvx",
"args": ["proxywhirl[mcp]", "proxywhirl-mcp"]
}
}
}
With Transport Options¶
To use a specific transport:
{
"mcpServers": {
"proxywhirl": {
"command": "proxywhirl-mcp",
"args": ["--transport", "http"]
}
}
}
Programmatic Usage¶
Use the MCP server functions directly in Python code:
import asyncio
from proxywhirl.mcp.server import (
proxywhirl,
get_rotator,
set_rotator,
cleanup_rotator,
)
from proxywhirl import AsyncProxyWhirl
async def main():
# List all proxies
result = await proxywhirl(action="list")
print(f"Total proxies: {result.get('total', 0)}")
# Check pool health
result = await proxywhirl(action="health")
print(f"Pool status: {result.get('pool_status', 'unknown')}")
# Get recommendation with criteria
result = await proxywhirl(
action="recommend",
criteria={"region": "US", "performance": "high"}
)
if "recommendation" in result:
print(f"Recommended: {result['recommendation']['url']}")
# Rotate to next proxy
result = await proxywhirl(action="rotate")
if "proxy" in result:
print(f"Selected: {result['proxy']['url']}")
# Clean up
await cleanup_rotator()
asyncio.run(main())
Custom Rotator Configuration¶
import asyncio
from proxywhirl.mcp.server import set_rotator, proxywhirl, cleanup_rotator
from proxywhirl import AsyncProxyWhirl, ProxyConfiguration
async def main():
# Create custom rotator
config = ProxyConfiguration(
timeout=60,
pool_connections=50,
)
rotator = AsyncProxyWhirl(
strategy="round-robin",
config=config
)
# Set as global MCP rotator
await set_rotator(rotator)
# Add proxies
await rotator.add_proxy("http://proxy1.example.com:8080")
await rotator.add_proxy("http://proxy2.example.com:8080")
# Now MCP tool calls use this rotator
result = await proxywhirl(action="list")
print(f"Proxies: {result['total']}")
# Cleanup
await cleanup_rotator()
asyncio.run(main())
Lifecycle Management¶
The MCP server uses FastMCP v2’s lifespan management for proper resource initialization and cleanup:
from proxywhirl.mcp.server import mcp_lifespan
async def run_server():
async with mcp_lifespan():
# Server is running
# Rotator is initialized from database
# Resources are available
pass
# Cleanup is automatic on exit
How Lifespan Works¶
Startup: Initializes the
AsyncProxyWhirl, loads proxies from database if availableRunning: Rotator is available for all tool calls
Shutdown: Cleans up rotator resources automatically
# The lifespan is automatically passed to FastMCP:
mcp = FastMCP("ProxyWhirl", lifespan=_mcp_lifespan)
Server Class Usage¶
from proxywhirl.mcp import ProxyWhirlMCPServer
from proxywhirl import AsyncProxyWhirl
async def main():
# With custom rotator
rotator = AsyncProxyWhirl(strategy="weighted")
server = ProxyWhirlMCPServer(proxy_manager=rotator)
await server.initialize() # Required for async setup
server.run() # Starts the server
# Without custom rotator (uses defaults)
server = ProxyWhirlMCPServer()
server.run() # Auto-initializes rotator on first use
Error Handling¶
The MCP server returns errors in a consistent format:
{
"error": "Error message description",
"code": 400
}
Common Error Codes¶
Code |
Meaning |
Example |
|---|---|---|
400 |
Bad Request |
Missing required parameter |
401 |
Unauthorized |
Invalid API key |
404 |
Not Found |
Proxy ID not found |
500 |
Internal Error |
Server-side failure |
Example Error Responses¶
// Missing proxy_id
{
"error": "proxy_id required for status action",
"code": 400
}
// Authentication failed
{
"error": "Authentication failed: Invalid API key",
"code": 401
}
// Proxy not found
{
"error": "Proxy not found: invalid-uuid",
"code": 404
}
Best Practices¶
1. Always Check Pool Health First¶
Before making proxy selections, verify the pool is healthy:
{"action": "health"}
If pool_status is "critical" or "empty", fetch new proxies before proceeding.
2. Use Recommendations for Critical Requests¶
For important requests, use the recommend action instead of rotate:
{
"action": "recommend",
"criteria": {"performance": "high"}
}
3. Monitor Circuit Breaker States¶
Check proxy status before use to avoid open circuit breakers. For circuit breaker internals (state transitions, rolling windows, persistence), see Retry & Failover Guide.
{
"action": "status",
"proxy_id": "your-proxy-id"
}
If circuit_breaker is "open", either wait or reset it.
4. Handle Errors Gracefully¶
Always check for error responses:
result = await proxywhirl(action="status", proxy_id="invalid")
if "error" in result:
print(f"Error {result['code']}: {result['error']}")
else:
print(f"Status: {result['status']}")
5. Clean Up Resources¶
Always clean up when done:
from proxywhirl.mcp.server import cleanup_rotator
await cleanup_rotator()
Troubleshooting¶
Server Won’t Start¶
Python version too low:
RuntimeError: MCP server requires Python 3.10 or higher
Solution: Upgrade to Python 3.10+.
FastMCP not installed:
FastMCP is not installed. MCP server cannot run.
Solution: pip install fastmcp or pip install "proxywhirl[mcp]"
No Proxies Available¶
Database not found:
MCP: No database at proxywhirl.db, starting with empty pool
Solution: Run proxywhirl fetch --output proxywhirl.db first.
Authentication Failures¶
Invalid API key:
{"error": "Authentication failed: Invalid API key", "code": 401}
Solution: Verify the API key matches what was configured with set_auth().
See Also¶
AsyncProxyWhirl patterns used by the MCP server internally for proxy rotation.
All rotation strategies available through the set_strategy MCP action.
Circuit breaker states and retry policies exposed via MCP status and reset_cb actions.
CLI commands for proxy management, an alternative interface to MCP.
The REST API provides similar functionality to MCP via HTTP endpoints.
Complete API docs for AsyncProxyWhirl and all models used by the MCP server.