Polymarket Position Movements
pm_movementsTrack recent position changes by whale wallets on Polymarket. View buys, sells, and size adjustments across prediction markets.
Instructions
Get recent position changes by whale wallets on Polymarket. Shows buys, sells, and position size changes across prediction markets. Cost: $0.01 per query. Source: Polymarket on-chain data.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| market_id | No | Filter by market ID | |
| wallet | No | Filter by wallet address | |
| hours | No | Lookback period in hours (default 24) | |
| limit | No | Maximum results (default 25) |
Implementation Reference
- src/tools/pm.ts:150-212 (handler)The handler function for the pm_movements tool. Calls apiGet to /api/v1/pm/movements with optional filters (market_id, wallet, hours, limit) and returns the response as text.
server.registerTool( "pm_movements", { title: "Polymarket Position Movements", description: "Get recent position changes by whale wallets on Polymarket. Shows buys, sells, " + "and position size changes across prediction markets. " + "Cost: $0.01 per query. Source: Polymarket on-chain data.", inputSchema: { market_id: z .string() .optional() .describe("Filter by market ID"), wallet: z .string() .optional() .describe("Filter by wallet address"), hours: z .number() .int() .min(1) .max(168) .optional() .describe("Lookback period in hours (default 24)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, }, async ({ market_id, wallet, hours, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/movements", { market_id, wallet, hours: hours ?? 24, limit: limit ?? 25, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} position movement(s).`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); - src/tools/pm.ts:158-181 (schema)Input schema for pm_movements tool — defines optional filters: market_id (string), wallet (string), hours (1-168 integer), limit (1-100 integer).
inputSchema: { market_id: z .string() .optional() .describe("Filter by market ID"), wallet: z .string() .optional() .describe("Filter by wallet address"), hours: z .number() .int() .min(1) .max(168) .optional() .describe("Lookback period in hours (default 24)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, - src/tools/pm.ts:148-212 (registration)The tool is registered on the MCP server via server.registerTool("pm_movements", ...) within the registerPmTools function.
// ── Position movements ──────────────────────────────────────────────── server.registerTool( "pm_movements", { title: "Polymarket Position Movements", description: "Get recent position changes by whale wallets on Polymarket. Shows buys, sells, " + "and position size changes across prediction markets. " + "Cost: $0.01 per query. Source: Polymarket on-chain data.", inputSchema: { market_id: z .string() .optional() .describe("Filter by market ID"), wallet: z .string() .optional() .describe("Filter by wallet address"), hours: z .number() .int() .min(1) .max(168) .optional() .describe("Lookback period in hours (default 24)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, }, async ({ market_id, wallet, hours, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/movements", { market_id, wallet, hours: hours ?? 24, limit: limit ?? 25, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} position movement(s).`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); - src/tools/pm.ts:29-298 (registration)The registerPmTools function that registers all Polymarket tools (including pm_movements) is exported and called from src/index.ts.
export function registerPmTools(server: McpServer): void { // ── PM whale wallets ────────────────────────────────────────────────── server.registerTool( "pm_whales", { title: "Polymarket Whale Wallets", description: "Get top Polymarket wallets ranked by PnL, volume, or position size. " + "Shows wallet address, total PnL, win rate, and active markets. " + "Cost: $0.005 per query. Source: Polymarket on-chain data.", inputSchema: { sort: z .enum(["pnl", "volume", "positions"]) .optional() .describe("Sort order (default: pnl)"), market_id: z .string() .optional() .describe("Filter by specific market ID"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, }, async ({ sort, market_id, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/whales", { sort: sort ?? "pnl", market_id, limit: limit ?? 25, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} Polymarket whale(s).`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); // ── Smart money signals ─────────────────────────────────────────────── server.registerTool( "pm_signals", { title: "Polymarket Smart Money Signals", description: "Get smart money flow signals showing where top traders are positioning. " + "Aggregates whale wallet activity into directional signals per market. " + "Cost: $0.02 per query. Source: Polymarket on-chain data.", inputSchema: { market_id: z .string() .optional() .describe("Filter by market ID"), min_confidence: z .number() .min(0) .max(1) .optional() .describe("Minimum signal confidence (0-1, default 0.5)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, }, async ({ market_id, min_confidence, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/signals", { market_id, min_confidence: min_confidence ?? 0.5, limit: limit ?? 25, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} smart money signal(s).`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); // ── Position movements ──────────────────────────────────────────────── server.registerTool( "pm_movements", { title: "Polymarket Position Movements", description: "Get recent position changes by whale wallets on Polymarket. Shows buys, sells, " + "and position size changes across prediction markets. " + "Cost: $0.01 per query. Source: Polymarket on-chain data.", inputSchema: { market_id: z .string() .optional() .describe("Filter by market ID"), wallet: z .string() .optional() .describe("Filter by wallet address"), hours: z .number() .int() .min(1) .max(168) .optional() .describe("Lookback period in hours (default 24)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 25)"), }, }, async ({ market_id, wallet, hours, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/movements", { market_id, wallet, hours: hours ?? 24, limit: limit ?? 25, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} position movement(s).`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); // ── Change feed ─────────────────────────────────────────────────────── server.registerTool( "pm_changes", { title: "Polymarket Changes", description: "Get recent changes to Polymarket data since a given timestamp. " + "Cost: $0.01 per query. Source: Polymarket on-chain data.", inputSchema: { since: z .string() .describe("ISO 8601 timestamp to get changes since (e.g. 2026-03-01T00:00:00Z)"), limit: z .number() .int() .min(1) .max(100) .optional() .describe("Maximum results (default 50)"), }, }, async ({ since, limit }) => { const res = await apiGet<PmQueryResponse>("/api/v1/pm/changes", { since, limit: limit ?? 50, }); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } const { count, data } = res.data; const warn = stalenessWarning(res); const summary = `${warn}Found ${count} Polymarket change(s) since ${since}.`; const json = JSON.stringify(data, null, 2); return { content: [{ type: "text" as const, text: `${summary}\n\n${json}` }], }; }, ); // ── Dataset stats ───────────────────────────────────────────────────── server.registerTool( "pm_stats", { title: "Polymarket Dataset Statistics", description: "Get statistics about the Polymarket dataset: total markets, wallets tracked, " + "volume, and last updated timestamp. Free endpoint.", inputSchema: {}, }, async () => { const res = await apiGet<PmStatsResponse>("/api/v1/pm/stats"); if (!res.ok) { return { content: [ { type: "text" as const, text: `API error (${res.status}): ${JSON.stringify(res.data)}`, }, ], isError: true, }; } return { content: [ { type: "text" as const, text: JSON.stringify(res.data, null, 2) }, ], }; }, ); } - src/index.ts:54-58 (registration)Top-level registration: registerPmTools(server) is called in createMcpServer() to mount pm_movements on the server.
registerPmTools(server); registerPmArbTools(server); registerPmResolutionTools(server); registerEconTools(server); registerPmMicroTools(server);