Loading...
Loading...
Enable Claude to trade, analyze, and manage Polymarket prediction markets with 45 AI-powered tools, real-time monitoring, and enterprise-grade safety features
npx skill4agent add aradotso/mcp-skills polymarket-mcp-serverSkill by ara.so — MCP Skills collection.
# Clone and install
git clone https://github.com/caiovicentino/polymarket-mcp-server.git
cd polymarket-mcp-server
./quickstart.sh
# Or automated one-liner
curl -sSL https://raw.githubusercontent.com/caiovicentino/polymarket-mcp-server/main/quickstart.sh | bash# Use automated installer
./install.sh
# Or manual installation
python -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install -e ..envcp .env.example .envDEMO_MODE=true# Required
POLYGON_PRIVATE_KEY=${POLYGON_PRIVATE_KEY}
POLYGON_ADDRESS=${POLYGON_ADDRESS}
# Optional Safety Limits
MAX_ORDER_SIZE_USD=1000
MAX_TOTAL_EXPOSURE_USD=5000
MAX_POSITION_SIZE_PER_MARKET=2000
MIN_LIQUIDITY_REQUIRED=10000
MAX_SPREAD_TOLERANCE=0.05
REQUIRE_CONFIRMATION_ABOVE_USD=500
ENABLE_AUTONOMOUS_TRADING=trueclaude_desktop_config.json~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.json{
"mcpServers": {
"polymarket": {
"command": "/absolute/path/to/venv/bin/python",
"args": ["-m", "polymarket_mcp.server"],
"cwd": "/absolute/path/to/polymarket-mcp-server",
"env": {
"POLYGON_PRIVATE_KEY": "${POLYGON_PRIVATE_KEY}",
"POLYGON_ADDRESS": "${POLYGON_ADDRESS}"
}
}
}
}# Tool: search_markets
{
"query": "Trump election",
"limit": 10,
"offset": 0
}# Tool: get_trending_markets
{
"period": "24h", # "24h", "7d", or "30d"
"limit": 20
}# Tool: get_markets_closing_soon
{
"hours": 24,
"limit": 10
}# Tool: get_markets_by_category
{
"category": "Politics", # Politics, Sports, Crypto, Pop Culture
"limit": 20
}# Tool: get_market_details
{
"market_id": "0x1234..."
}# Tool: analyze_market_opportunity
{
"market_id": "0x1234...",
"analysis_depth": "deep" # "quick" or "deep"
}
# Returns: BUY/SELL/HOLD recommendation with reasoning# Tool: get_orderbook_depth
{
"token_id": "0x5678..."
}# Tool: compare_markets
{
"market_ids": ["0x1234...", "0x5678...", "0x9abc..."]
}# Tool: calculate_spread
{
"token_id": "0x5678..."
}# Tool: place_limit_order
{
"token_id": "0x5678...",
"side": "BUY", # or "SELL"
"price": 0.65,
"size": 100,
"time_in_force": "GTC" # GTC, GTD, FOK, FAK
}# Tool: place_market_order
{
"token_id": "0x5678...",
"side": "BUY",
"amount": 50
}# Tool: smart_trade
{
"instruction": "Buy $200 worth of Yes on Trump 2024 election if price below 0.60",
"strategy": "passive" # aggressive, passive, or mid
}
# Automatically parses instruction and executes optimal trade# Tool: get_ai_suggested_prices
{
"token_id": "0x5678...",
"side": "BUY",
"strategy": "mid" # aggressive, passive, or mid
}# Tool: cancel_order
{
"order_id": "0xabcd..."
}# Tool: get_open_orders
{
"market_id": "0x1234..." # Optional filter
}# Tool: get_portfolio_summary
{}
# Returns: total value, positions, P&L, risk metrics# Tool: get_active_positions
{
"market_id": "0x1234..." # Optional filter
}# Tool: calculate_pnl
{
"position_id": "0x5678...",
"include_unrealized": true
}# Tool: analyze_portfolio_risk
{}
# Returns: concentration risk, liquidity risk, diversification score# Tool: optimize_portfolio
{
"risk_profile": "balanced", # conservative, balanced, or aggressive
"target_allocation": {
"Politics": 0.4,
"Sports": 0.3,
"Crypto": 0.3
}
}
# Returns: rebalancing suggestions with rationale# Tool: get_trade_history
{
"start_date": "2024-01-01",
"end_date": "2024-12-31",
"market_id": "0x1234..." # Optional
}# Tool: subscribe_to_market
{
"market_id": "0x1234...",
"channels": ["price", "orderbook", "trades"]
}# Tool: subscribe_to_user_orders
{}
# Monitors all your order status changes# Tool: get_websocket_status
{}
# Returns: connection state, subscriptions, message counts# Tool: unsubscribe_from_market
{
"market_id": "0x1234..."
}from polymarket_mcp.client import PolymarketClient
from decimal import Decimal
import os
# Initialize client
client = PolymarketClient(
private_key=os.getenv("POLYGON_PRIVATE_KEY"),
polygon_address=os.getenv("POLYGON_ADDRESS")
)
# Search markets
markets = client.search_markets(query="election", limit=5)
for market in markets:
print(f"{market['question']} - Volume: ${market['volume24h']}")
# Get market analysis
market_id = markets[0]['id']
analysis = client.analyze_market_opportunity(
market_id=market_id,
analysis_depth="deep"
)
print(f"Recommendation: {analysis['recommendation']}")
print(f"Reasoning: {analysis['reasoning']}")
# Place order with safety checks
token_id = markets[0]['tokens'][0]['id']
order = client.place_limit_order(
token_id=token_id,
side="BUY",
price=Decimal("0.55"),
size=100,
time_in_force="GTC"
)
print(f"Order placed: {order['id']}")
# Monitor portfolio
portfolio = client.get_portfolio_summary()
print(f"Total Value: ${portfolio['total_value_usd']}")
print(f"Unrealized P&L: ${portfolio['unrealized_pnl']}")
# Get real-time updates via WebSocket
client.subscribe_to_market(
market_id=market_id,
channels=["price", "orderbook"]
)from polymarket_mcp.client import PolymarketClient
from decimal import Decimal
class SimpleArbitrageBot:
def __init__(self, client: PolymarketClient):
self.client = client
self.min_spread = Decimal("0.05") # 5% minimum spread
def find_arbitrage_opportunities(self):
"""Find markets with high spreads"""
trending = self.client.get_trending_markets(period="24h", limit=50)
opportunities = []
for market in trending:
for token in market['tokens']:
spread = self.client.calculate_spread(token['id'])
if spread['spread_percentage'] > float(self.min_spread):
opportunities.append({
'market': market['question'],
'token_id': token['id'],
'spread': spread['spread_percentage'],
'best_bid': spread['best_bid'],
'best_ask': spread['best_ask']
})
return sorted(opportunities, key=lambda x: x['spread'], reverse=True)
def execute_trade(self, opportunity):
"""Execute trade on identified opportunity"""
# Get AI-suggested optimal price
suggested = self.client.get_ai_suggested_prices(
token_id=opportunity['token_id'],
side="BUY",
strategy="mid"
)
# Place order
order = self.client.place_limit_order(
token_id=opportunity['token_id'],
side="BUY",
price=Decimal(str(suggested['suggested_price'])),
size=100,
time_in_force="GTC"
)
return order
# Usage
client = PolymarketClient(
private_key=os.getenv("POLYGON_PRIVATE_KEY"),
polygon_address=os.getenv("POLYGON_ADDRESS")
)
bot = SimpleArbitrageBot(client)
opportunities = bot.find_arbitrage_opportunities()
for opp in opportunities[:3]:
print(f"Opportunity: {opp['market']}")
print(f"Spread: {opp['spread']:.2%}")
order = bot.execute_trade(opp)
print(f"Order placed: {order['id']}\n")from polymarket_mcp.client import PolymarketClient
class RiskManager:
def __init__(self, client: PolymarketClient):
self.client = client
self.max_exposure_usd = 5000
self.max_position_size = 2000
self.max_category_allocation = 0.4 # 40%
def check_trade_allowed(self, trade_value_usd: float, market_category: str) -> dict:
"""Validate if trade passes risk checks"""
portfolio = self.client.get_portfolio_summary()
risk_analysis = self.client.analyze_portfolio_risk()
# Check total exposure
new_exposure = portfolio['total_value_usd'] + trade_value_usd
if new_exposure > self.max_exposure_usd:
return {
"allowed": False,
"reason": f"Would exceed max exposure: ${new_exposure} > ${self.max_exposure_usd}"
}
# Check position size
if trade_value_usd > self.max_position_size:
return {
"allowed": False,
"reason": f"Trade size ${trade_value_usd} exceeds max position ${self.max_position_size}"
}
# Check category concentration
category_exposure = risk_analysis.get('category_concentration', {}).get(market_category, 0)
new_category_allocation = (category_exposure + trade_value_usd) / new_exposure
if new_category_allocation > self.max_category_allocation:
return {
"allowed": False,
"reason": f"Would exceed {market_category} allocation: {new_category_allocation:.1%}"
}
return {"allowed": True, "reason": "All risk checks passed"}
def suggest_position_size(self, market_id: str) -> float:
"""Suggest optimal position size based on risk"""
portfolio = self.client.get_portfolio_summary()
market = self.client.get_market_details(market_id)
# Kelly Criterion simplified
win_rate = 0.55 # Estimate from market analysis
odds = market['tokens'][0]['price']
kelly_fraction = (win_rate - (1 - win_rate) / odds) / odds
suggested_size = portfolio['total_value_usd'] * kelly_fraction * 0.5 # Half Kelly
return min(suggested_size, self.max_position_size)
# Usage
client = PolymarketClient(
private_key=os.getenv("POLYGON_PRIVATE_KEY"),
polygon_address=os.getenv("POLYGON_ADDRESS")
)
risk_mgr = RiskManager(client)
# Check if trade is allowed
trade_check = risk_mgr.check_trade_allowed(
trade_value_usd=500,
market_category="Politics"
)
if trade_check['allowed']:
suggested_size = risk_mgr.suggest_position_size(market_id="0x1234...")
print(f"Suggested position size: ${suggested_size:.2f}")
else:
print(f"Trade blocked: {trade_check['reason']}")# 1. Find trending markets
trending = client.get_trending_markets(period="24h", limit=20)
# 2. Analyze each market
for market in trending[:5]:
analysis = client.analyze_market_opportunity(
market_id=market['id'],
analysis_depth="deep"
)
if analysis['recommendation'] == 'BUY':
# 3. Get orderbook depth
orderbook = client.get_orderbook_depth(market['tokens'][0]['id'])
# 4. Check liquidity
if orderbook['total_liquidity'] > 10000:
print(f"Good opportunity: {market['question']}")
print(f"Reason: {analysis['reasoning']}")# 1. Get portfolio risk analysis
risk = client.analyze_portfolio_risk()
# 2. If risk is high, get optimization suggestions
if risk['overall_risk_score'] > 70:
optimization = client.optimize_portfolio(
risk_profile="balanced",
target_allocation={
"Politics": 0.35,
"Sports": 0.30,
"Crypto": 0.35
}
)
# 3. Execute suggested trades
for suggestion in optimization['suggestions']:
if suggestion['action'] == 'REDUCE':
client.place_market_order(
token_id=suggestion['token_id'],
side="SELL",
amount=suggestion['amount']
)import asyncio
async def monitor_positions():
# Subscribe to user orders
client.subscribe_to_user_orders()
# Monitor portfolio value
while True:
portfolio = client.get_portfolio_summary()
# Alert on significant P&L change
if abs(portfolio['unrealized_pnl']) > 500:
print(f"⚠️ Large P&L movement: ${portfolio['unrealized_pnl']}")
# Analyze if should close positions
risk = client.analyze_portfolio_risk()
if risk['liquidity_risk'] > 80:
print("🚨 High liquidity risk - consider closing positions")
await asyncio.sleep(60) # Check every minute
# Run monitoring
asyncio.run(monitor_positions())polymarket-web
# Or: ./start_web_dashboard.sh
# Access at: http://localhost:8080# Order Limits
MAX_ORDER_SIZE_USD=1000
MAX_POSITION_SIZE_PER_MARKET=2000
MAX_TOTAL_EXPOSURE_USD=5000
# Liquidity Checks
MIN_LIQUIDITY_REQUIRED=10000
MAX_SPREAD_TOLERANCE=0.05
# Confirmations
REQUIRE_CONFIRMATION_ABOVE_USD=500
ENABLE_AUTONOMOUS_TRADING=true# API Rate Limits (per minute)
RATE_LIMIT_READ_PER_MIN=100
RATE_LIMIT_WRITE_PER_MIN=20
RATE_LIMIT_BURST_SIZE=5WEBSOCKET_RECONNECT_DELAY=5
WEBSOCKET_MAX_RETRIES=10
WEBSOCKET_PING_INTERVAL=30# Test API connectivity
python -m polymarket_mcp.test_connection
# Check WebSocket status
python -c "from polymarket_mcp.client import PolymarketClient; \
c = PolymarketClient(); \
print(c.get_websocket_status())"# Verify wallet configuration
from polymarket_mcp.client import PolymarketClient
import os
client = PolymarketClient(
private_key=os.getenv("POLYGON_PRIVATE_KEY"),
polygon_address=os.getenv("POLYGON_ADDRESS")
)
# Test authentication
try:
portfolio = client.get_portfolio_summary()
print("✓ Authentication successful")
except Exception as e:
print(f"✗ Auth failed: {e}")from polymarket_mcp.client import PolymarketClient
from time import sleep
client = PolymarketClient()
# Built-in rate limiting
for i in range(100):
try:
markets = client.search_markets(query=f"test {i}", limit=1)
# Rate limiter automatically throttles requests
except Exception as e:
if "rate limit" in str(e).lower():
print("Rate limit hit, waiting...")
sleep(60)# Check order validation before placing
from polymarket_mcp.client import PolymarketClient
from decimal import Decimal
client = PolymarketClient()
# Validate market liquidity
orderbook = client.get_orderbook_depth(token_id="0x5678...")
if orderbook['total_liquidity'] < 10000:
print("⚠️ Low liquidity - consider smaller order size")
# Calculate expected slippage
spread = client.calculate_spread(token_id="0x5678...")
if spread['spread_percentage'] > 0.05:
print(f"⚠️ High spread: {spread['spread_percentage']:.2%}")# Switch to full mode
# 1. Get Polygon wallet private key
# 2. Update .env:
DEMO_MODE=false
POLYGON_PRIVATE_KEY=your_actual_key
POLYGON_ADDRESS=0xYourAddress
# 3. Restart MCP server# Run all tests
pytest
# Test specific tool
pytest tests/test_trading.py::test_place_limit_order
# Test with real API (caution)
pytest tests/test_integration.py --run-liveTOOLS_REFERENCE.md