Sign inSign up

superbizon007/proxy-mcp

By superbizon007

Updated 4 months ago

Image
0

309

superbizon007/proxy-mcp repository overview

proxy_mcp

FastMCP service managing a pool of SOCKS5 proxies for dynamic agent spawning. When a spawner creates a new agent container, it calls get_proxy() to lease a proxy, injects SOCKS_PROXY as an env var, and calls release_proxy() when the task finishes.

Agents route all traffic through the proxy transparently via tun2socks — no application-level proxy config needed.

Quick Start

# Install
cd apps/proxy_mcp
uv sync

# Start with Docker (Postgres + app)
docker compose up -d

# Or run locally (requires Postgres)
export PROXY_MCP_DATABASE_URL=postgresql+psycopg://proxy_mcp:proxy_mcp@localhost:5432/proxy_mcp
alembic upgrade head
proxy-mcp serve --transport streamable-http

MCP Tools

ToolDescription
get_proxyLease a proxy. Inline rotating products bypass the DB; static IPs use SELECT FOR UPDATE SKIP LOCKED. Cheapest-first by priority.
release_proxyRelease a lease after successful task completion. No-op for inline rotating leases.
report_failureRecord a failure. Static IPs auto-disable after 3 consecutive fails (configurable). Inline rotating leases log + return without state change.
list_proxiesRead-only pool overview. Returns DB rows unioned with synthesized rows for configured rotating products.
upsert_proxyInsert or update a proxy. Upserts on (host, port, protocol). Used by cli sync for static IPs.

CLI

proxy-mcp serve [--transport stdio|streamable-http] [--host HOST] [--port PORT]
proxy-mcp sync [--provider brightdata|oxylabs|decodo|dataimpulse]
                                                         # fetch static IPs from provider APIs
                                                         # rotating products are skipped (zero-row mode)
proxy-mcp list [--enabled-only] [--country US]
proxy-mcp reset-leases                                   # force-release all static leases
proxy-mcp enable PROXY_ID
proxy-mcp disable PROXY_ID

Proxy Types & Priority

Lower priority = cheaper = selected first when no proxy_type filter is passed.

TypePriorityTypical Cost (Oxylabs)
free10$0
datacenter20$1.2 / IP
isp25$1.6 / IP
dedicated_datacenter28$2.25 / IP
dedicated_isp32$3.2 / IP
residential40$6 / GB
mobile50$7.5 / GB

Two lease modes

Zero-row (rotating gateways) — no sync, no DB rows

Rotating products (BrightData zones, Oxylabs residential/mobile, Decodo rotating, DataImpulse) are leased inline from settings at request time. Each lease constructs a fresh URL with a session ID injected into the username, pointing at the provider's gateway. Nothing is written to the database.

  • No cli sync required.
  • New rotating products go live the moment env config changes.
  • The synthetic lease IDs use the prefix inline:<provider>:<product>:<country>:<session> so release_proxy and report_failure can short-circuit without DB writes.
  • See app/inline_lease.py for the candidate iterator + URL builder.
DB-backed (static IPs) — cli sync required

Static IP products (BrightData static zones, Oxylabs ISP / Datacenter / dedicated-*, Decodo static) carry per-IP state. cli sync fetches the current list from each provider's API and upserts rows into the proxies table. get_proxy then locks one with SELECT FOR UPDATE SKIP LOCKED and marks it in_use=True.

Run proxy-mcp sync once after seeding credentials, then on a cron (daily is plenty — provider IP lists rarely churn).

Provider setup

BrightData
BRIGHTDATA_API_TOKEN=<bearer>
BRIGHTDATA_CUSTOMER_ID=<your customer id>
BRIGHTDATA_ZONES='[
  {"name":"res_zone","password":"<pw>","type":"rotating","proxy_type":"residential"},
  {"name":"dc_static","password":"<pw>","type":"static","proxy_type":"datacenter"}
]'
  • Gateway: brd.superproxy.io:22225 for rotating
  • Session pattern: -session-{sid} appended to the username
  • Static IPs fetched via GET /api/zone/ips?zone={name} (Bearer auth)
Oxylabs
OXYLABS_USERNAME=<sub-account>
OXYLABS_PASSWORD=<sub-account password>
OXYLABS_PRODUCTS='[
  {"name":"residential","type":"rotating","proxy_type":"residential"},
  {"name":"mobile","type":"rotating","proxy_type":"mobile"},
  {"name":"isp_shared","type":"static","proxy_type":"isp",
   "list_url":"https://stats.oxylabs.io/api/proxy-list/isp"},
  {"name":"isp_dedicated","type":"static","proxy_type":"dedicated_isp",
   "list_url":"https://stats.oxylabs.io/api/proxy-list/dedicated-isp"},
  {"name":"dc_dedicated","type":"static","proxy_type":"dedicated_datacenter",
   "list_url":"https://stats.oxylabs.io/api/proxy-list/dedicated-datacenter"}
]'
  • Gateway: pr.oxylabs.io:7777 for rotating
  • Session pattern: -sessid-{sid} appended to the username
  • Static IPs fetched via the per-product list_url from your dashboard (HTTP Basic auth)
Decodo (formerly Smartproxy)
DECODO_API_TOKEN=<token>
DECODO_USERNAME=<sub-account>
DECODO_PASSWORD=<sub-account password>
DECODO_PRODUCTS='[
  {"name":"rot_residential","type":"rotating","proxy_type":"residential"}
]'
  • Gateway: gate.smartproxy.com:5000 (SOCKS5) / :7000 (HTTP) for rotating
  • Session pattern: -sessionid-{sid} appended to the username
  • Static IP list endpoint: not yet verified against current Decodo docs — see app/providers/decodo.py:13-15
DataImpulse
DATAIMPULSE_LOGIN=<login>
DATAIMPULSE_PASSWORD=<password>
DATAIMPULSE_PRODUCTS='[
  {"name":"rot_residential","country":"GB","proxy_type":"residential"}
]'
  • Gateway: gw.dataimpulse.com:824 (SOCKS5)
  • Country targeting: __cr.<lower> segment in the username
  • Session pattern: ;sessid.{sid} appended (semicolon + dot delimiters preserved literally in URL encoding)
  • Gateway-only — no static IPs to sync

Environment Variables

Service
# Required
PROXY_MCP_DATABASE_URL=postgresql+psycopg://user:pass@localhost:5432/proxy_mcp

# Optional
PROXY_MCP_HOST=0.0.0.0
PROXY_MCP_PORT=8002
PROXY_MCP_AUTO_DISABLE_FAILS=3        # consecutive fails before static IP auto-disable
PROXY_MCP_LEASE_TIMEOUT=60            # minutes before stale lease cleanup (static IPs only)
LOG_LEVEL=INFO
API_KEY=                              # bearer auth for streamable-http mode (Core sets this on its calls)
Per-provider

Set credentials + the corresponding *_PRODUCTS (or *_ZONES for BrightData) JSON array. The full reference is in .env.example. Each entry must include type (rotating or static) and proxy_type (one of the seven values listed above). Country is optional.

Minimum viable setup (Oxylabs residential only)

PROXY_MCP_DATABASE_URL=postgresql+psycopg://proxy_mcp:proxy_mcp@db:5432/proxy_mcp
API_KEY=<bearer Core sends>

OXYLABS_USERNAME=<account>
OXYLABS_PASSWORD=<password>
OXYLABS_PRODUCTS='[{"name":"residential","type":"rotating","proxy_type":"residential"}]'

Start the service. Set PROXY_MCP_URL=http://proxy-mcp:8002/mcp and PROXY_AGENTS=linux.chrome.agent on Core. No cli sync needed — every Chrome agent spawn now leases an inline residential proxy.

What needs cli sync

SetupSync needed?
Pure rotating (Oxylabs residential, DataImpulse, BrightData rotating zones, Decodo rotating)No
Static IPs (Oxylabs ISP / DC / dedicated-*, BrightData static zones, Decodo static)Yes — daily cron is plenty
Mixed (rotating + static from the same provider)Yes for the static portion; rotating items in the same *_PRODUCTS JSON are skipped automatically with a 'N rotating skipped' note

Agent integration

Core's spawner injects the lease as an env var on the agent pod:

# Browser / desktop / scraper / terminal / downloader agents (tun2socks routing)
SOCKS_PROXY=socks5://user:[email protected]:1080

# Android agent (ADB http_proxy)
ANDROID_PROXY=1.2.3.4:1080

Both values come back in the ProxyLease response. Core picks the right env name based on agent_type_key.

See specs/PLAN_PROXY_INTEGRATION.md (Core-side wiring) and specs/PLAN_PROXY_ZERO_ROW.md (this service's lease model) for the design behind both halves.

Tests

uv sync --dev
uv run pytest tests/ -v

Tag summary

Content type

Image

Digest

sha256:f0e87bbab

Size

83.6 MB

Last updated

4 months ago

docker pull superbizon007/proxy-mcp