Skip to main content
Workflows Library MCP Directory Realtime AI News Sponsor Tier Subscribe
Front Page / AI Tools / Deep Dive

Build a Polymarket MCP Server for Prediction-Market Agents with Paper-Trading Validation

SKALE's Agent Pit (Aug 12, 2026) established paper trading as the training ground for prediction-market agents. This MCP server — polymarket-mcp — gives agents the same discipline as a tool surface: read markets, order books, and positions in paper mode by default, then graduate to live orders only behind an explicit mode flag with position caps. Built with FastMCP in TypeScript with inputSchema JSON, mcpServers config, and an API-key security guide.

Deepak Bagada

Deepak Bagada

CEO, SaaSNext

Aug 17, 2026 Published
|
Aug 17, 2026 Updated
|
11 Minutes Reading Time
Core Takeaways for Founders & Builders
  • polymarket-mcp exposes prediction markets to AI agents with paper-first trading as the default — the SKALE Agent Pit discipline as a tool surface.
  • Six tools cover the full loop: list_markets, get_market, get_orderbook, get_position, place_paper_order, and place_live_order.
  • Live orders require an explicit mode:live flag, an approved:true flag, and position caps — graduation is a policy decision, not a model impulse.
  • Idempotency keys prevent duplicate orders; paper and live books stay separate so benchmark P&L is not polluted.
  • Security: Polymarket API keys for live orders only, caps enforced server-side, and every order logged to an audit trail.

By Deepak Bagada, CEO at SaaSNext & Principal AI Architect.

SKALE's Agent Pit launch on August 12, 2026 made a quiet but important statement: prediction-market agents should train in a paper-trading sandbox before they touch real money. This dispatch turns that discipline into a tool surface. polymarket-mcp is a TypeScript FastMCP server that exposes Polymarket prediction markets to AI agents with paper-first trading as the default: agents read markets, order books, and positions freely, place paper orders against a local simulation book, and only reach live orders through an explicit mode flag with server-side position caps. The latest AI news hub has tracked the prediction-market agent wave; this is the governed MCP surface those agents need.

Why prediction markets need a paper-first gate

Prediction markets are the natural arena for autonomous agents — liquid, binary-outcome, fast-resolving — but live money punishes unvalidated strategies instantly. Agent Pit showed the answer: benchmark offline, trade paper, graduate with caps. polymarket-mcp enforces that pipeline structurally. The default mode is paper; live is an explicit, capped, audited exception. An agent cannot accidentally trade real money because the tool surface makes it impossible without a deliberate policy flag. That is the difference between a trading agent and a gambling agent.

Architecture

flowchart TD
    A[AI agent] -->|MCP JSON-RPC| B[polymarket-mcp server]
    B --> C[list_markets]
    B --> D[get_market]
    B --> E[get_orderbook]
    B --> F[get_position]
    B --> G[place_paper_order]
    B --> H[place_live_order]
    G --> I[Local paper book]
    H --> J{mode=live + approved + cap}
    J -- no --> K[Rejected]
    J -- yes --> L[Polymarket API]
    F --> M[Paper + live positions]

Project setup

mkdir polymarket-mcp && cd polymarket-mcp
npm init -y
npm install @modelcontextprotocol/sdk fastmcp zod dotenv
# .env
POLYMARKET_API_KEY=your_live_api_key   # only injected when mode:live
POLYMARKET_SECRET=your_api_secret
MAX_POSITION_USD=500
DEFAULT_MODE=paper
AUDIT_LOG_PATH=./audit/orders.log

Server code (index.ts)

import { FastMCP } from "fastmcp";
import { z } from "zod";
import { appendFileSync } from "fs";
import "dotenv/config";

const server = new FastMCP({ name: "polymarket-mcp", version: "1.0.0" });
const paperBook: Record<string, { size: number; price: number }> = {};

function audit(entry: unknown) {
  appendFileSync(process.env.AUDIT_LOG_PATH || "./audit/orders.log", JSON.stringify(entry) + "
");
}

// --- Tool 1: list markets ---
server.addTool({
  name: "list_markets",
  description: "List active Polymarket markets, optionally filtered by tag or status.",
  inputSchema: z.object({
    tag: z.string().optional(),
    limit: z.number().int().max(100).default(20),
  }),
  async execute({ tag, limit }) {
    const url = `https://gamma-api.polymarket.com/markets?limit=${limit}${tag ? `&tag=${tag}` : ""}`;
    const res = await fetch(url);
    const markets = await res.json();
    return markets.map((m: any) => ({
      id: m.id,
      question: m.question,
      endDate: m.end_date,
      volume: m.volume,
    }));
  },
});

// --- Tool 2: get a market ---
server.addTool({
  name: "get_market",
  description: "Get full detail for a single market including current prices.",
  inputSchema: z.object({ marketId: z.string() }),
  async execute({ marketId }) {
    const res = await fetch(`https://gamma-api.polymarket.com/markets/${marketId}`);
    return await res.json();
  },
});

// --- Tool 3: get order book ---
server.addTool({
  name: "get_orderbook",
  description: "Get the current order book for a market's outcome token.",
  inputSchema: z.object({ marketId: z.string(), outcome: z.string() }),
  async execute({ marketId, outcome }) {
    const res = await fetch(`https://clob.polymarket.com/book?token_id=${marketId}-${outcome}`);
    return await res.json();
  },
});

// --- Tool 4: get position ---
server.addTool({
  name: "get_position",
  description: "Return current paper and live positions for an address.",
  inputSchema: z.object({ address: z.string() }),
  async execute({ address }) {
    return { paper: paperBook[address] ?? { size: 0 }, live: "query Polymarket API" };
  },
});

// --- Tool 5: place a paper order (default mode) ---
server.addTool({
  name: "place_paper_order",
  description: "Place a paper order against the local simulation book. No real money.",
  inputSchema: z.object({
    marketId: z.string(),
    outcome: z.string(),
    side: z.enum(["buy", "sell"]),
    size: z.number().positive(),
    price: z.number().positive(),
  }),
  async execute({ marketId, outcome, side, size, price }) {
    paperBook[`${marketId}-${outcome}`] = { size, price };
    audit({ type: "paper", marketId, outcome, side, size, price, at: new Date().toISOString() });
    return { status: "filled_paper", size, price, note: "paper order, no real funds" };
  },
});

// --- Tool 6: place a live order (explicit gate) ---
server.addTool({
  name: "place_live_order",
  description: "Place a live Polymarket order. REQUIRES mode:live and approved:true; enforced position cap.",
  inputSchema: z.object({
    mode: z.enum(["paper", "live"]),
    approved: z.boolean(),
    marketId: z.string(),
    outcome: z.string(),
    side: z.enum(["buy", "sell"]),
    size: z.number().positive(),
    price: z.number().positive(),
    idempotencyKey: z.string(),
  }),
  async execute({ mode, approved, marketId, outcome, side, size, price, idempotencyKey }) {
    if (mode !== "live" || !approved) {
      return { status: "rejected", reason: "mode must be live and approved must be true" };
    }
    const cap = parseFloat(process.env.MAX_POSITION_USD || "500");
    if (size * price > cap) return { status: "rejected", reason: `notional ${size * price} exceeds cap ${cap}` };
    // Real implementation: sign + submit to Polymarket CLOB with idempotencyKey
    audit({ type: "live", marketId, outcome, side, size, price, idempotencyKey, at: new Date().toISOString() });
    return { status: "submitted", orderId: idempotencyKey, note: "live order submitted with cap enforced" };
  },
});

server.start({ transportType: "stdio" });

inputSchema JSON definitions

{
  "place_paper_order": {
    "type": "object",
    "properties": {
      "marketId": { "type": "string" },
      "outcome": { "type": "string" },
      "side": { "type": "string", "enum": ["buy", "sell"] },
      "size": { "type": "number", "exclusiveMinimum": 0 },
      "price": { "type": "number", "exclusiveMinimum": 0 }
    },
    "required": ["marketId", "outcome", "side", "size", "price"]
  },
  "place_live_order": {
    "type": "object",
    "properties": {
      "mode": { "type": "string", "enum": ["paper", "live"] },
      "approved": { "type": "boolean" },
      "marketId": { "type": "string" },
      "outcome": { "type": "string" },
      "side": { "type": "string", "enum": ["buy", "sell"] },
      "size": { "type": "number", "exclusiveMinimum": 0 },
      "price": { "type": "number", "exclusiveMinimum": 0 },
      "idempotencyKey": { "type": "string" }
    },
    "required": ["mode", "approved", "marketId", "outcome", "side", "size", "price", "idempotencyKey"]
  }
}

mcpServers config

{
  "mcpServers": {
    "polymarket": {
      "command": "node",
      "args": ["/path/to/polymarket-mcp/dist/index.js"],
      "env": {
        "POLYMARKET_API_KEY": "${POLYMARKET_API_KEY}",
        "POLYMARKET_SECRET": "${POLYMARKET_SECRET}",
        "MAX_POSITION_USD": "500",
        "DEFAULT_MODE": "paper"
      }
    }
  }
}

Retry & idempotency rules

  • Reads (list_markets, get_market, get_orderbook) retry twice with backoff on 5xx or rate limits.
  • place_live_order is idempotent by idempotencyKey: resubmitting the same key returns the same orderId and never double-fills.
  • Never retry a live order without the same idempotency key — a confused agent retrying with a fresh key can double the position.
  • Paper orders are stateless and safe to retry; the simulation book is idempotent by construction.

Security guide

The security model is graduation by policy, not by impulse. Reads are public and unauthenticated. Paper orders need no credentials and hit a local simulation book. Live orders require the Polymarket API key — which is only injected when mode:live is used — plus an approved:true flag and a server-side notional cap from MAX_POSITION_USD. Every order, paper or live, is written to the audit log with a timestamp. The pattern mirrors the SKALE Agent Pit discipline: benchmark offline, trade paper, graduate with caps. The same graduation discipline appears across the AI workflows library and the MCP directory for every money-touching agent tool.

The bottom line

polymarket-mcp gives prediction-market agents a governed tool surface: full market data reads, paper trading by default, and live orders behind explicit flags with caps and audit. It is the SKALE Agent Pit discipline made structural — agents cannot graduate to real money without a deliberate policy decision. The tooling patterns are in the MCP directory; track the prediction-market agent wave on latest AI news.

Frequently Asked Questions

What is polymarket-mcp?

A TypeScript FastMCP server exposing Polymarket prediction markets to AI agents — market data reads, order books, positions, paper orders by default, and live orders behind an explicit mode flag with caps.

Why paper-first trading?

SKALE's Agent Pit (Aug 12, 2026) established paper trading as the training ground for prediction-market agents: validate strategies against realistic order flow before risking real money. The MCP server enforces the same discipline.

How do agents graduate to live trading?

place_live_order requires mode:live and approved:true flags plus a server-side position cap. Graduation is an explicit policy decision — never a model's spontaneous choice.

How are paper and live P&L kept separate?

Paper orders go to a local simulation book; live orders go to the Polymarket API. The books never mix, so benchmark results stay clean and live P&L is auditable.

What security does it need?

Reads are public; live orders need a Polymarket API key that is only injected when mode:live is used, with caps and an audit log on every order.

Closing thoughts

Prediction-market agents are coming whether or not we build the rails — polymarket-mcp is the rail that keeps them honest. Paper-first by default, live only by explicit policy, caps and audit on everything. That is the discipline that separates trading agents from gambling agents. The tooling is in the MCP directory; the agent-trading coverage is on latest AI news.

Executive Briefing

Enjoyed this breakdown? Get our morning dispatch in your inbox.

Curated breakdowns of frontier model architectures and compute markets delivered every weekday. Zero fluff.

Frequently Asked Questions
A TypeScript FastMCP server exposing Polymarket prediction markets to AI agents — market data reads, order books, positions, paper orders by default, and live orders behind an explicit mode flag with caps.
SKALE's Agent Pit (Aug 12, 2026) established paper trading as the training ground for prediction-market agents: validate strategies against realistic order flow before risking real money. The MCP server enforces the same discipline.
place_live_order requires mode:live and approved:true flags plus a server-side position cap. Graduation is an explicit policy decision — never a model's spontaneous choice.
Paper orders go to a local simulation book; live orders go to the Polymarket API. The books never mix, so benchmark results stay clean and live P&L is auditable.
Reads are public; live orders need a Polymarket API key that is only injected when mode:live is used, with caps and an audit log on every order.
Deepak Bagada
Author Profile

Deepak Bagada

CEO, SaaSNext

Deepak Bagada is the CEO of SaaSNext and founder of Daily AI World. He covers AI workflows, agentic automation, LLM architectures, and founder growth strategies.

Related Intelligence Analysis

Briefing AI Tools

Vercel AI SDK Tool Calling React: 5 Steps (2026)

Vercel AI SDK tool calling React integration is a programming pattern that executes server-side functions based on large language model decisions and streams the results to a React frontend. By combining streamText with...

Deepak Bagada Deepak Bagada
12m read
Breaking AI Tools

Fact-Density vs. Word Count: The New SEO for 2026

Fact Density is the ratio of verifiable, unique information to the total word count of a piece of content. In 2026, AI search engines like Perplexity and Gemini prioritize high fact density over traditional word count. A...

Deepak Bagada Deepak Bagada
4m read
Audio Briefing
Accessibility Preferences
High Contrast Mode
Accessible Reading Font

Keyboard Shortcuts

Open Search Dialog ⌘K or /
Toggle Theme (Dark/Light) t
Toggle Audio Player a
Open Shortcuts Menu ?
Close Active Dialog Esc