> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eventgraph.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Quickstart

> Set up the EventGraph MCP server in 5 minutes

## Prerequisites

* Node.js 18+ installed (`node --version`)
* An EventGraph API key ([get one free](/authentication))

***

## Step 1 — Create the MCP server

Create a new folder and save this file as `server.js`:

```bash theme={null}
mkdir eventgraph-mcp && cd eventgraph-mcp
npm init -y
npm install @modelcontextprotocol/sdk zod
```

Create `server.js`:

```javascript theme={null}
#!/usr/bin/env node
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";

const API_BASE = "https://app.eventgraph.ai";
const API_KEY = process.env.EVENTGRAPH_API_KEY;

if (!API_KEY) {
  process.stderr.write("Error: EVENTGRAPH_API_KEY environment variable is required\n");
  process.exit(1);
}

async function apiCall(path, params = {}) {
  const url = new URL(`${API_BASE}${path}`);
  for (const [k, v] of Object.entries(params)) {
    if (v !== undefined && v !== null && v !== "") {
      url.searchParams.set(k, String(v));
    }
  }
  const res = await fetch(url.toString(), {
    headers: { "X-API-Key": API_KEY },
  });
  if (!res.ok) {
    const err = await res.json().catch(() => ({}));
    throw new Error(`API error ${res.status}: ${err?.detail?.message || res.statusText}`);
  }
  const json = await res.json();
  return json.data ?? json;
}

const server = new McpServer({
  name: "eventgraph",
  version: "1.0.0",
});

// ── Free tier tools ──────────────────────────────────────────────────────────

server.tool(
  "search_markets",
  "Search prediction markets across Polymarket, Kalshi, Limitless, and OpinionTrade. Returns live market data including prices, volumes, and platform details.",
  {
    query: z.string().optional().describe("Keyword search query"),
    platform: z.enum(["polymarket", "kalshi", "limitless", "opiniontrade"]).optional().describe("Filter by platform"),
    status: z.enum(["active", "resolved", "all"]).optional().default("active").describe("Market status filter"),
    category: z.string().optional().describe("Category filter e.g. 'politics', 'sports', 'crypto'"),
    page_size: z.number().int().min(1).max(100).optional().default(20).describe("Number of results"),
  },
  async (params) => {
    const data = await apiCall("/api/v1/markets", params);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

server.tool(
  "get_market",
  "Get full details for a specific prediction market including current prices, volume, liquidity, and metadata.",
  {
    market_id: z.string().describe("The market ID (from search_markets results)"),
  },
  async ({ market_id }) => {
    const data = await apiCall(`/api/v1/markets/${market_id}`);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

server.tool(
  "search_events",
  "Search prediction market events. Events are groups of related markets (e.g. 'US 2026 Midterms' is an event containing many individual markets).",
  {
    query: z.string().optional().describe("Keyword search query"),
    category: z.string().optional().describe("Category filter"),
    page_size: z.number().int().min(1).max(100).optional().default(20),
  },
  async (params) => {
    const data = await apiCall("/api/v1/events", params);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

server.tool(
  "get_api_status",
  "Check EventGraph API health and data freshness. Shows when data was last updated for each platform.",
  {},
  async () => {
    const data = await apiCall("/api/v1/status");
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

// ── Pro tier tools ───────────────────────────────────────────────────────────

server.tool(
  "find_arbitrage",
  "Find cross-platform arbitrage opportunities — markets where the same event is priced differently on different platforms. Pro tier required.",
  {
    min_spread: z.number().optional().describe("Minimum spread percentage to return (e.g. 2 for 2%)"),
    page_size: z.number().int().min(1).max(100).optional().default(20),
  },
  async (params) => {
    const data = await apiCall("/api/v1/arbitrage", params);
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

server.tool(
  "compare_markets",
  "Compare how the same event is priced across multiple prediction market platforms side by side. Pro tier required.",
  {
    event_id: z.string().describe("The event ID to compare across platforms (from search_events results)"),
  },
  async ({ event_id }) => {
    const data = await apiCall("/api/v1/compare", { event_id });
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

server.tool(
  "get_market_history",
  "Get historical price time series data for a prediction market. Pro tier required.",
  {
    market_id: z.string().describe("The market ID"),
    interval: z.enum(["1h", "4h", "1d", "1w"]).optional().default("1d").describe("Time interval between data points"),
  },
  async ({ market_id, interval }) => {
    const data = await apiCall(`/api/v1/markets/${market_id}/history`, { interval });
    return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
  }
);

// ── Start server ─────────────────────────────────────────────────────────────

const transport = new StdioServerTransport();
await server.connect(transport);
```

Add `"type": "module"` to your `package.json`:

```json theme={null}
{
  "type": "module",
  ...
}
```

***

## Step 2 — Test it locally

```bash theme={null}
EVENTGRAPH_API_KEY=eg_live_your_key node server.js
```

The server starts and waits for MCP client connections. Now connect a client:

<CardGroup cols={3}>
  <Card title="Claude Desktop" icon="message" href="/mcp/claude">
    Add to Claude Desktop config
  </Card>

  <Card title="Cursor / Windsurf" icon="code" href="/mcp/cursor">
    Add to your IDE's MCP config
  </Card>

  <Card title="ChatGPT" icon="robot" href="/mcp/chatgpt">
    Create a Custom GPT with Actions
  </Card>
</CardGroup>

***

## Verify it's working

Once connected to Claude or Cursor, try asking:

> *"What are the top active prediction markets right now?"*

> *"Find me any arbitrage opportunities across Polymarket and Kalshi."*

> *"What markets exist around the 2026 US midterm elections?"*

The AI will call your MCP server and return live data.

<Note>
  **API key tier matters.** The `find_arbitrage`, `compare_markets`, and `get_market_history` tools require a Pro key. Free tier keys will return a `403` on those tools. [Upgrade to Pro →](/api-reference/checkout)
</Note>
