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 proxywhirl tool with action-based operations

  • Resources: 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

List all proxies in the pool

-

api_key

rotate

Get next proxy using rotation strategy

-

api_key

status

Get detailed status for a specific proxy

proxy_id

api_key

recommend

Get best proxy based on criteria

-

criteria, api_key

health

Get pool health overview

-

api_key

reset_cb

Reset circuit breaker for a proxy

proxy_id

api_key

add

Add a new proxy to the pool

proxy_url

api_key

remove

Remove a proxy from the pool

proxy_id

api_key

fetch

Fetch proxies from public sources

-

criteria.max_proxies, api_key

validate

Validate proxy connectivity

-

proxy_id, criteria.timeout, api_key

set_strategy

Change rotation strategy

strategy

api_key

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 pool

  • healthy: 70%+ proxies are healthy

  • degraded: 30-70% proxies are healthy

  • critical: 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:

  1. Assess Requirements: Determine target geography and performance needs

  2. Check Pool Health: Verify pool status before selection

  3. Get Recommendation: Use criteria-based recommendation

  4. Verify Selected Proxy: Check circuit breaker and metrics

  5. Use or Rotate: Execute request or switch proxies if issues arise

troubleshooting_workflow

A diagnostic workflow for debugging proxy issues:

  1. Diagnose Pool Health: Check overall pool status

  2. Check Specific Proxy: Examine individual proxy metrics

  3. Circuit Breaker Issues: Reset breakers if needed

  4. Find Alternative: Get fresh recommendations

  5. 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 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

  1. Startup: Initializes the AsyncProxyWhirl, loads proxies from database if available

  2. Running: Rotator is available for all tool calls

  3. 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

Async Client Guide

AsyncProxyWhirl patterns used by the MCP server internally for proxy rotation.

Async Client Guide
Advanced Strategies

All rotation strategies available through the set_strategy MCP action.

Advanced Rotation Strategies
Retry & Failover

Circuit breaker states and retry policies exposed via MCP status and reset_cb actions.

Retry & Failover Guide
CLI Reference

CLI commands for proxy management, an alternative interface to MCP.

CLI Reference
REST API Reference

The REST API provides similar functionality to MCP via HTTP endpoints.

ProxyWhirl REST API Usage Guide
Python API Reference

Complete API docs for AsyncProxyWhirl and all models used by the MCP server.

Python API